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