/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
49 by Jelmer Vernooij
Merge in Dan Loda's gannotate plugin and put it in annotate/
1
# This program is free software; you can redistribute it and/or modify
2
# it under the terms of the GNU General Public License as published by
3
# the Free Software Foundation; either version 2 of the License, or
4
# (at your option) any later version.
5
6
# This program is distributed in the hope that it will be useful,
7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9
# GNU General Public License for more details.
10
11
# You should have received a copy of the GNU General Public License
12
# along with this program; if not, write to the Free Software
13
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14
15
"""GTK+ frontends to Bazaar commands """
73 by Jelmer Vernooij
Release 0.9, list myself as maintainer.
16
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
17
import bzrlib
18
162 by Aaron Bentley
Update version to 0.16.0
19
__version__ = '0.16.0'
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
20
version_info = tuple(int(n) for n in __version__.split('.'))
21
22
23
def check_bzrlib_version(desired):
24
    """Check that bzrlib is compatible.
25
26
    If version is < bzr-gtk version, assume incompatible.
27
    If version == bzr-gtk version, assume completely compatible
28
    If version == bzr-gtk version + 1, assume compatible, with deprecations
29
    Otherwise, assume incompatible.
30
    """
31
    desired_plus = (desired[0], desired[1]+1)
32
    bzrlib_version = bzrlib.version_info[:2]
33
    if bzrlib_version == desired:
34
        return
35
    try:
36
        from bzrlib.trace import warning
37
    except ImportError:
38
        # get the message out any way we can
39
        from warnings import warn as warning
40
    if bzrlib_version < desired:
41
        warning('Installed bzr version %s is too old to be used with bzr-gtk'
42
                ' %s.' % (bzrlib.__version__, __version__))
43
        # Not using BzrNewError, because it may not exist.
44
        raise Exception, ('Version mismatch', version_info)
45
    else:
46
        warning('bzr-gtk is not up to date with installed bzr version %s.'
47
                ' \nThere should be a newer version available, e.g. %i.%i.' 
48
                % (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
49
        if bzrlib_version != desired_plus:
50
            raise Exception, 'Version mismatch'
51
52
53
check_bzrlib_version(version_info[:2])
54
146 by Jelmer Vernooij
Move more code to top-level directory.
55
from bzrlib.trace import warning
56
if __name__ != 'bzrlib.plugins.gtk':
57
    warning("Not running as bzrlib.plugins.gtk, things may break.")
58
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
59
from bzrlib.lazy_import import lazy_import
60
lazy_import(globals(), """
61
from bzrlib import (
62
    branch,
63
    errors,
64
    workingtree,
65
    )
66
""")
67
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
68
from bzrlib.commands import Command, register_command, display_command
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
69
from bzrlib.errors import NotVersionedError, BzrCommandError, NoSuchFile
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
70
from bzrlib.commands import Command, register_command
71
from bzrlib.option import Option
72
from bzrlib.bzrdir import BzrDir
73
126.1.5 by Szilveszter Farkas (Phanatic)
bzr gbranch should work now (Fixed: #77751)
74
import os.path
75
66.2.20 by Aaron Bentley
Nicer error when PyGTK not installed
76
def import_pygtk():
77
    try:
78
        import pygtk
79
    except ImportError:
80
        raise errors.BzrCommandError("PyGTK not installed.")
81
    pygtk.require('2.0')
82
    return pygtk
83
84
133 by Jelmer Vernooij
Actually use the ui factory.
85
def set_ui_factory():
86
    pygtk = import_pygtk()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
87
    from ui import GtkUIFactory
133 by Jelmer Vernooij
Actually use the ui factory.
88
    import bzrlib.ui
89
    bzrlib.ui.ui_factory = GtkUIFactory()
90
91
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
92
class GTKCommand(Command):
93
    """Abstract class providing GTK specific run commands."""
94
95
    def open_display(self):
96
        pygtk = import_pygtk()
97
        try:
98
            import gtk
99
        except RuntimeError, e:
100
            if str(e) == "could not open display":
101
                raise NoDisplayError
102
        set_ui_factory()
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
103
        return gtk
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
104
105
    def run(self):
106
        self.open_display()
107
        dialog = self.get_gtk_dialog(os.path.abspath('.'))
108
        dialog.run()
109
110
111
class cmd_gbranch(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
112
    """GTK+ branching.
113
    
114
    """
115
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
116
    def get_gtk_dialog(self, path):
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
117
        from bzrlib.plugins.gtk.branch import BranchDialog
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
118
        return BranchDialog(path)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
119
120
121
register_command(cmd_gbranch)
122
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
123
class cmd_gcheckout(GTKCommand):
126.1.18 by Szilveszter Farkas (Phanatic)
Improved Branch dialog. Refactored Checkout dialog.
124
    """ GTK+ checkout.
125
    
126
    """
127
    
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
128
    def get_gtk_dialog(self, path):
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
129
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
130
        return CheckoutDialog(path)
126.1.18 by Szilveszter Farkas (Phanatic)
Improved Branch dialog. Refactored Checkout dialog.
131
132
register_command(cmd_gcheckout)
133
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
134
135
class cmd_gpush(GTKCommand):
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
136
    """ GTK+ push.
137
    
138
    """
139
    takes_args = [ "location?" ]
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
140
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
141
    def run(self, location="."):
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
142
        (br, path) = branch.Branch.open_containing(location)
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
143
        self.open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
144
        from push import PushDialog
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
145
        dialog = PushDialog(br)
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
146
        dialog.run()
147
148
register_command(cmd_gpush)
149
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
150
151
class cmd_gdiff(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
152
    """Show differences in working tree in a GTK+ Window.
153
    
154
    Otherwise, all changes for the tree are listed.
155
    """
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
156
    takes_args = ['filename?']
58.1.1 by Aaron Bentley
gdiff takes -r arguments
157
    takes_options = ['revision']
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
158
159
    @display_command
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
160
    def run(self, revision=None, filename=None):
133 by Jelmer Vernooij
Actually use the ui factory.
161
        set_ui_factory()
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
162
        wt = workingtree.WorkingTree.open_containing(".")[0]
161 by Aaron Bentley
Fix gannotate interaction with dirstate
163
        wt.lock_read()
164
        try:
165
            branch = wt.branch
166
            if revision is not None:
167
                if len(revision) == 1:
168
                    tree1 = wt
169
                    revision_id = revision[0].in_history(branch).rev_id
170
                    tree2 = branch.repository.revision_tree(revision_id)
171
                elif len(revision) == 2:
172
                    revision_id_0 = revision[0].in_history(branch).rev_id
173
                    tree2 = branch.repository.revision_tree(revision_id_0)
174
                    revision_id_1 = revision[1].in_history(branch).rev_id
175
                    tree1 = branch.repository.revision_tree(revision_id_1)
176
            else:
58.1.1 by Aaron Bentley
gdiff takes -r arguments
177
                tree1 = wt
161 by Aaron Bentley
Fix gannotate interaction with dirstate
178
                tree2 = tree1.basis_tree()
179
180
            from diff import DiffWindow
181
            import gtk
182
            window = DiffWindow()
183
            window.connect("destroy", gtk.main_quit)
184
            window.set_diff("Working Tree", tree1, tree2)
185
            if filename is not None:
186
                tree_filename = wt.relpath(filename)
187
                try:
188
                    window.set_file(tree_filename)
189
                except NoSuchFile:
190
                    if (tree1.inventory.path2id(tree_filename) is None and 
191
                        tree2.inventory.path2id(tree_filename) is None):
192
                        raise NotVersionedError(filename)
193
                    raise BzrCommandError('No changes found for file "%s"' % 
194
                                          filename)
195
            window.show()
196
197
            gtk.main()
198
        finally:
199
            wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
200
201
register_command(cmd_gdiff)
202
203
class cmd_visualise(Command):
204
    """Graphically visualise this branch.
205
206
    Opens a graphical window to allow you to see the history of the branch
207
    and relationships between revisions in a visual manner,
208
209
    The default starting point is latest revision on the branch, you can
210
    specify a starting point with -r revision.
211
    """
212
    takes_options = [
213
        "revision",
214
        Option('limit', "maximum number of revisions to display",
215
               int, 'count')]
216
    takes_args = [ "location?" ]
217
    aliases = [ "visualize", "vis", "viz" ]
218
219
    def run(self, location=".", revision=None, limit=None):
133 by Jelmer Vernooij
Actually use the ui factory.
220
        set_ui_factory()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
221
        (br, path) = branch.Branch.open_containing(location)
222
        br.lock_read()
223
        br.repository.lock_read()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
224
        try:
225
            if revision is None:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
226
                revid = br.last_revision()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
227
                if revid is None:
228
                    return
229
            else:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
230
                (revno, revid) = revision[0].in_history(br)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
231
152 by Jelmer Vernooij
Cleanup some more code.
232
            from viz.branchwin import BranchWindow
233
            import gtk
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
234
                
152 by Jelmer Vernooij
Cleanup some more code.
235
            pp = BranchWindow()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
236
            pp.set_branch(br, revid, limit)
152 by Jelmer Vernooij
Cleanup some more code.
237
            pp.connect("destroy", lambda w: gtk.main_quit())
238
            pp.show()
239
            gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
240
        finally:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
241
            br.repository.unlock()
242
            br.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
243
244
245
register_command(cmd_visualise)
246
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
247
248
class cmd_gannotate(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
249
    """GTK+ annotate.
250
    
251
    Browse changes to FILENAME line by line in a GTK+ window.
252
    """
253
59.2.1 by Aaron Bentley
Gannotate takes a line number
254
    takes_args = ["filename", "line?"]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
255
    takes_options = [
256
        Option("all", help="show annotations on all lines"),
257
        Option("plain", help="don't highlight annotation lines"),
258
        Option("line", type=int, argname="lineno",
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
259
               help="jump to specified line number"),
260
        "revision",
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
261
    ]
262
    aliases = ["gblame", "gpraise"]
263
    
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
264
    def run(self, filename, all=False, plain=False, line='1', revision=None):
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
265
        self.open_display()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
266
59.2.1 by Aaron Bentley
Gannotate takes a line number
267
        try:
268
            line = int(line)
269
        except ValueError:
270
            raise BzrCommandError('Line argument ("%s") is not a number.' % 
271
                                  line)
272
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
273
        from annotate.gannotate import GAnnotateWindow
274
        from annotate.config import GAnnotateConfig
275
161 by Aaron Bentley
Fix gannotate interaction with dirstate
276
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
277
        if wt is not None:
278
            tree = wt
279
        else:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
280
            tree = br.basis_tree()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
281
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
282
        file_id = tree.path2id(path)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
283
284
        if file_id is None:
285
            raise NotVersionedError(filename)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
286
        if revision is not None:
287
            if len(revision) != 1:
288
                raise BzrCommandError("Only 1 revion may be specified.")
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
289
            revision_id = revision[0].in_history(br).rev_id
290
            tree = br.repository.revision_tree(revision_id)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
291
        else:
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
292
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
293
294
        window = GAnnotateWindow(all, plain)
295
        window.connect("destroy", lambda w: gtk.main_quit())
296
        window.set_title(path + " - gannotate")
297
        config = GAnnotateConfig(window)
298
        window.show()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
299
        br.lock_read()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
300
        if wt is not None:
301
            wt.lock_read()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
302
        try:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
303
            window.annotate(tree, br, file_id)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
304
            window.jump_to_line(line)
305
            gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
306
        finally:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
307
            br.unlock()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
308
            if wt is not None:
309
                wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
310
311
register_command(cmd_gannotate)
312
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
313
314
class cmd_gcommit(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
315
    """GTK+ commit dialog
316
317
    Graphical user interface for committing revisions"""
318
    
145 by Jelmer Vernooij
Fix some strings, import.
319
    aliases = [ "gci" ]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
320
    takes_args = []
321
    takes_options = []
322
323
    def run(self, filename=None):
93.1.17 by Alexander Belchenko
gcommit reworked again.
324
        import os
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
325
        self.open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
326
        from commit import CommitDialog
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
327
        from bzrlib.commit import Commit
93.1.17 by Alexander Belchenko
gcommit reworked again.
328
        from bzrlib.errors import (BzrCommandError,
329
                                   NotBranchError,
330
                                   NoWorkingTree,
331
                                   PointlessCommit,
332
                                   ConflictsInTree,
333
                                   StrictCommitFailed)
334
335
        wt = None
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
336
        br = None
93.1.17 by Alexander Belchenko
gcommit reworked again.
337
        try:
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
338
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
339
            br = wt.branch
93.1.17 by Alexander Belchenko
gcommit reworked again.
340
        except NotBranchError, e:
341
            path = e.path
342
        except NoWorkingTree, e:
343
            path = e.base
344
            try:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
345
                (br, path) = branch.Branch.open_containing(path)
93.1.17 by Alexander Belchenko
gcommit reworked again.
346
            except NotBranchError, e:
347
                path = e.path
348
135 by Jelmer Vernooij
Throw out the old CommitDialog code and use the new code instead, also for 'gcommit'.
349
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
350
        commit = CommitDialog(wt, path, not br)
135 by Jelmer Vernooij
Throw out the old CommitDialog code and use the new code instead, also for 'gcommit'.
351
        commit.run()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
352
353
register_command(cmd_gcommit)
354
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
355
356
class cmd_gstatus(GTKCommand):
157 by Jelmer Vernooij
Add gstatus command.
357
    """GTK+ status dialog
358
359
    Graphical user interface for showing status 
360
    information."""
361
    
362
    aliases = [ "gst" ]
363
    takes_args = ['PATH?']
364
    takes_options = []
365
366
    def run(self, path='.'):
367
        import os
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
368
        self.open_display()
157 by Jelmer Vernooij
Add gstatus command.
369
        from status import StatusDialog
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
370
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
157 by Jelmer Vernooij
Add gstatus command.
371
        status = StatusDialog(wt, wt_path)
372
        status.connect("destroy", gtk.main_quit)
373
        status.run()
374
375
register_command(cmd_gstatus)
376
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
377
378
class cmd_gconflicts(GTKCommand):
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
379
    """ GTK+ push.
380
    
381
    """
382
    def run(self):
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
383
        (wt, path) = workingtree.WorkingTree.open_containing('.')
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
384
        self.open_display()
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
385
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
386
        dialog = ConflictsDialog(wt)
387
        dialog.run()
388
389
register_command(cmd_gconflicts)
157 by Jelmer Vernooij
Add gstatus command.
390
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
391
392
class cmd_gpreferences(GTKCommand):
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
393
    """ GTK+ preferences dialog.
394
395
    """
396
    def run(self):
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
397
        self.open_display()
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
398
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
399
        dialog = PreferencesWindow()
400
        dialog.run()
401
402
register_command(cmd_gpreferences)
403
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
404
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
405
class cmd_commit_notify(GTKCommand):
406
    """Run the bzr commit notifier.
407
408
    This is a background program which will pop up a notification on the users
409
    screen when a commit occurs.
410
    """
411
412
    def run(self):
413
        gtk = self.open_display()
414
        import cgi
415
        import dbus
416
        import dbus.service
417
        import pynotify
418
        from bzrlib.bzrdir import BzrDir
419
        from bzrlib import errors
420
        from bzrlib.osutils import format_date
421
        from bzrlib.transport import get_transport
422
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
423
            import dbus.glib
424
        from bzrlib.plugins.dbus import activity
425
        bus = dbus.SessionBus()
426
        # get the object so we can subscribe to callbacks from it.
427
        broadcast_service = bus.get_object(
428
            activity.Broadcast.DBUS_NAME,
429
            activity.Broadcast.DBUS_PATH)
430
        def catch_branch(revision_id, url):
431
            try:
432
                if isinstance(revision_id, unicode):
433
                    revision_id = revision_id.encode('utf8')
434
                transport = get_transport(url)
435
                try:
436
                    transport.local_abspath('.')
437
                except errors.TransportNotPossible:
438
                    # dont show remote urls for now.
439
                    return
440
                # here we should:
441
                a_dir = BzrDir.open_from_transport(transport)
442
                branch = a_dir.open_branch()
443
                revno = branch.revision_id_to_revno(revision_id)
444
                revision = branch.repository.get_revision(revision_id)
445
                summary = 'New revision %d in %s' % (revno, url)
446
                body  = 'Committer: %s\n' % revision.committer
447
                body += 'Date: %s\n' % format_date(revision.timestamp,
448
                    revision.timezone)
449
                body += '\n'
450
                body += revision.message
451
                body = cgi.escape(body)
452
                #print repr(body)
453
                nw = pynotify.Notification(summary, body)
454
                nw.set_timeout(5000)
455
                nw.show()
456
            except Exception, e:
457
                print e
458
                raise
459
        broadcast_service.connect_to_signal("Revision", catch_branch,
460
            dbus_interface=activity.Broadcast.DBUS_INTERFACE)
461
        pynotify.init("bzr commit-notify")
462
        gtk.main()
463
464
register_command(cmd_commit_notify)
465
466
152 by Jelmer Vernooij
Cleanup some more code.
467
import gettext
468
gettext.install('olive-gtk')
469
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
470
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
471
class NoDisplayError(BzrCommandError):
472
    """gtk could not find a proper display"""
473
474
    def __str__(self):
133 by Jelmer Vernooij
Actually use the ui factory.
475
        return "No DISPLAY. Unable to run GTK+ application."
476
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
477
140 by Jelmer Vernooij
add framework for tests.
478
def test_suite():
479
    from unittest import TestSuite
480
    import tests
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
481
    import sys
482
    default_encoding = sys.getdefaultencoding()
483
    try:
484
        result = TestSuite()
485
        result.addTest(tests.test_suite())
486
    finally:
170.1.2 by Aaron Bentley
Test suite only fixes encoding if it's changed. Fixes test_selftest bug.
487
        if sys.getdefaultencoding() != default_encoding:
488
            reload(sys)
489
            sys.setdefaultencoding(default_encoding)
140 by Jelmer Vernooij
add framework for tests.
490
    return result