/b-gtk/fix-viz

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