/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
625.2.1 by Jelmer Vernooij
Move commands to a separate module and register them lazily.
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
644 by Jelmer Vernooij
Fix import.
15
import os
16
625.2.1 by Jelmer Vernooij
Move commands to a separate module and register them lazily.
17
from bzrlib import (
18
    branch,
19
    builtins,
20
    merge_directive,
21
    workingtree,
22
    )
23
from bzrlib.commands import (
24
    Command,
25
    display_command,
26
    )
27
from bzrlib.errors import (
28
    BzrCommandError,
29
    NotVersionedError,
30
    NoSuchFile,
31
    )
32
from bzrlib.option import Option
33
34
from bzrlib.plugins.gtk import (
35
    open_display,
36
    import_pygtk,
37
    set_ui_factory,
38
    )
39
40
class GTKCommand(Command):
41
    """Abstract class providing GTK specific run commands."""
42
43
    def run(self):
44
        open_display()
45
        dialog = self.get_gtk_dialog(os.path.abspath('.'))
46
        dialog.run()
47
48
49
class cmd_gbranch(GTKCommand):
50
    """GTK+ branching.
51
    
52
    """
53
54
    def get_gtk_dialog(self, path):
55
        from bzrlib.plugins.gtk.branch import BranchDialog
56
        return BranchDialog(path)
57
58
59
class cmd_gcheckout(GTKCommand):
60
    """ GTK+ checkout.
61
    
62
    """
63
    
64
    def get_gtk_dialog(self, path):
65
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
66
        return CheckoutDialog(path)
67
68
69
70
class cmd_gpush(GTKCommand):
71
    """ GTK+ push.
72
    
73
    """
74
    takes_args = [ "location?" ]
75
76
    def run(self, location="."):
77
        (br, path) = branch.Branch.open_containing(location)
78
        open_display()
79
        from bzrlib.plugins.gtk.push import PushDialog
80
        dialog = PushDialog(br.repository, br.last_revision(), br)
81
        dialog.run()
82
83
84
class cmd_gloom(GTKCommand):
85
    """ GTK+ loom.
86
    
87
    """
88
    takes_args = [ "location?" ]
89
90
    def run(self, location="."):
91
        try:
92
            (tree, path) = workingtree.WorkingTree.open_containing(location)
93
            br = tree.branch
94
        except NoWorkingTree, e:
95
            (br, path) = branch.Branch.open_containing(location)
96
            tree = None
97
        open_display()
98
        from bzrlib.plugins.gtk.loom import LoomDialog
99
        dialog = LoomDialog(br, tree)
100
        dialog.run()
101
102
103
class cmd_gdiff(GTKCommand):
104
    """Show differences in working tree in a GTK+ Window.
105
    
106
    Otherwise, all changes for the tree are listed.
107
    """
108
    takes_args = ['filename?']
109
    takes_options = ['revision']
110
111
    @display_command
112
    def run(self, revision=None, filename=None):
113
        set_ui_factory()
114
        wt = workingtree.WorkingTree.open_containing(".")[0]
115
        wt.lock_read()
116
        try:
117
            branch = wt.branch
118
            if revision is not None:
119
                if len(revision) == 1:
120
                    tree1 = wt
121
                    revision_id = revision[0].as_revision_id(tree1.branch)
122
                    tree2 = branch.repository.revision_tree(revision_id)
123
                elif len(revision) == 2:
124
                    revision_id_0 = revision[0].as_revision_id(branch)
125
                    tree2 = branch.repository.revision_tree(revision_id_0)
126
                    revision_id_1 = revision[1].as_revision_id(branch)
127
                    tree1 = branch.repository.revision_tree(revision_id_1)
128
            else:
129
                tree1 = wt
130
                tree2 = tree1.basis_tree()
131
132
            from diff import DiffWindow
133
            import gtk
134
            window = DiffWindow()
135
            window.connect("destroy", gtk.main_quit)
136
            window.set_diff("Working Tree", tree1, tree2)
137
            if filename is not None:
138
                tree_filename = wt.relpath(filename)
139
                try:
140
                    window.set_file(tree_filename)
141
                except NoSuchFile:
142
                    if (tree1.path2id(tree_filename) is None and 
143
                        tree2.path2id(tree_filename) is None):
144
                        raise NotVersionedError(filename)
145
                    raise BzrCommandError('No changes found for file "%s"' % 
146
                                          filename)
147
            window.show()
148
149
            gtk.main()
150
        finally:
151
            wt.unlock()
152
153
154
def start_viz_window(branch, revisions, limit=None):
155
    """Start viz on branch with revision revision.
156
    
157
    :return: The viz window object.
158
    """
159
    from bzrlib.plugins.gtk.viz import BranchWindow
160
    return BranchWindow(branch, revisions, limit)
161
162
163
class cmd_visualise(Command):
164
    """Graphically visualise this branch.
165
166
    Opens a graphical window to allow you to see the history of the branch
167
    and relationships between revisions in a visual manner,
168
169
    The default starting point is latest revision on the branch, you can
170
    specify a starting point with -r revision.
171
    """
172
    takes_options = [
173
        "revision",
174
        Option('limit', "Maximum number of revisions to display.",
175
               int, 'count')]
176
    takes_args = [ "locations*" ]
177
    aliases = [ "visualize", "vis", "viz" ]
178
179
    def run(self, locations_list, revision=None, limit=None):
180
        set_ui_factory()
181
        if locations_list is None:
182
            locations_list = ["."]
183
        revids = []
184
        for location in locations_list:
185
            (br, path) = branch.Branch.open_containing(location)
186
            if revision is None:
187
                revids.append(br.last_revision())
188
            else:
189
                revids.append(revision[0].as_revision_id(br))
190
        import gtk
191
        pp = start_viz_window(br, revids, limit)
192
        pp.connect("destroy", lambda w: gtk.main_quit())
193
        pp.show()
194
        gtk.main()
195
196
197
class cmd_gannotate(GTKCommand):
198
    """GTK+ annotate.
199
    
200
    Browse changes to FILENAME line by line in a GTK+ window.
201
    """
202
203
    takes_args = ["filename", "line?"]
204
    takes_options = [
205
        Option("all", help="Show annotations on all lines."),
206
        Option("plain", help="Don't highlight annotation lines."),
207
        Option("line", type=int, argname="lineno",
208
               help="Jump to specified line number."),
209
        "revision",
210
    ]
211
    aliases = ["gblame", "gpraise"]
212
    
213
    def run(self, filename, all=False, plain=False, line='1', revision=None):
214
        gtk = open_display()
215
216
        try:
217
            line = int(line)
218
        except ValueError:
219
            raise BzrCommandError('Line argument ("%s") is not a number.' % 
220
                                  line)
221
222
        from annotate.gannotate import GAnnotateWindow
223
        from annotate.config import GAnnotateConfig
224
        from bzrlib.bzrdir import BzrDir
225
226
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
227
        if wt is not None:
228
            tree = wt
229
        else:
230
            tree = br.basis_tree()
231
232
        file_id = tree.path2id(path)
233
234
        if file_id is None:
235
            raise NotVersionedError(filename)
236
        if revision is not None:
237
            if len(revision) != 1:
238
                raise BzrCommandError("Only 1 revion may be specified.")
239
            revision_id = revision[0].as_revision_id(br)
240
            tree = br.repository.revision_tree(revision_id)
241
        else:
242
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
243
244
        window = GAnnotateWindow(all, plain, branch=br)
245
        window.connect("destroy", lambda w: gtk.main_quit())
246
        config = GAnnotateConfig(window)
247
        window.show()
248
        br.lock_read()
249
        if wt is not None:
250
            wt.lock_read()
251
        try:
252
            window.annotate(tree, br, file_id)
253
            window.jump_to_line(line)
254
            gtk.main()
255
        finally:
256
            br.unlock()
257
            if wt is not None:
258
                wt.unlock()
259
260
261
262
class cmd_gcommit(GTKCommand):
263
    """GTK+ commit dialog
264
265
    Graphical user interface for committing revisions"""
266
267
    aliases = [ "gci" ]
268
    takes_args = []
269
    takes_options = []
270
271
    def run(self, filename=None):
272
        import os
273
        open_display()
274
        from commit import CommitDialog
275
        from bzrlib.errors import (BzrCommandError,
276
                                   NotBranchError,
277
                                   NoWorkingTree)
278
279
        wt = None
280
        br = None
281
        try:
282
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
283
            br = wt.branch
284
        except NoWorkingTree, e:
285
            from dialog import error_dialog
286
            error_dialog(_i18n('Directory does not have a working tree'),
287
                         _i18n('Operation aborted.'))
288
            return 1 # should this be retval=3?
289
290
        # It is a good habit to keep things locked for the duration, but it
291
        # could cause difficulties if someone wants to do things in another
292
        # window... We could lock_read() until we actually go to commit
293
        # changes... Just a thought.
294
        wt.lock_write()
295
        try:
296
            dlg = CommitDialog(wt)
297
            return dlg.run()
298
        finally:
299
            wt.unlock()
300
301
302
class cmd_gstatus(GTKCommand):
303
    """GTK+ status dialog
304
305
    Graphical user interface for showing status 
306
    information."""
307
308
    aliases = [ "gst" ]
309
    takes_args = ['PATH?']
310
    takes_options = ['revision']
311
312
    def run(self, path='.', revision=None):
313
        import os
314
        gtk = open_display()
315
        from bzrlib.plugins.gtk.status import StatusWindow
316
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
317
318
        if revision is not None:
319
            try:
320
                revision_id = revision[0].as_revision_id(wt.branch)
321
            except:
322
                from bzrlib.errors import BzrError
323
                raise BzrError('Revision %r doesn\'t exist'
324
                               % revision[0].user_spec )
325
        else:
326
            revision_id = None
327
328
        status = StatusWindow(wt, wt_path, revision_id)
329
        status.connect("destroy", gtk.main_quit)
330
        status.show()
331
        gtk.main()
332
333
334
class cmd_gsend(GTKCommand):
335
    """GTK+ send merge directive.
336
337
    """
338
    def run(self):
339
        (br, path) = branch.Branch.open_containing(".")
340
        gtk = open_display()
341
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
342
        from StringIO import StringIO
343
        dialog = SendMergeDirectiveDialog(br)
344
        if dialog.run() == gtk.RESPONSE_OK:
345
            outf = StringIO()
346
            outf.writelines(dialog.get_merge_directive().to_lines())
347
            mail_client = br.get_config().get_mail_client()
348
            mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]", 
349
                outf.getvalue())
350
351
            
352
353
354
class cmd_gconflicts(GTKCommand):
355
    """GTK+ conflicts.
356
    
357
    Select files from the list of conflicts and run an external utility to
358
    resolve them.
359
    """
360
    def run(self):
361
        (wt, path) = workingtree.WorkingTree.open_containing('.')
362
        open_display()
363
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
364
        dialog = ConflictsDialog(wt)
365
        dialog.run()
366
367
368
class cmd_gpreferences(GTKCommand):
369
    """ GTK+ preferences dialog.
370
371
    """
372
    def run(self):
373
        open_display()
374
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
375
        dialog = PreferencesWindow()
376
        dialog.run()
377
378
379
class cmd_ginfo(Command):
380
    """ GTK+ info dialog
381
    
382
    """
383
    def run(self):
384
        from bzrlib import workingtree
385
        from bzrlib.plugins.gtk.olive.info import InfoDialog
386
        wt = workingtree.WorkingTree.open_containing('.')[0]
387
        info = InfoDialog(wt.branch)
388
        info.display()
389
        info.window.run()
390
391
392
class cmd_gmerge(Command):
393
    """ GTK+ merge dialog
394
    
395
    """
396
    takes_args = ["merge_from_path?"]
397
    def run(self, merge_from_path=None):
398
        from bzrlib.plugins.gtk.dialog import error_dialog
399
        from bzrlib.plugins.gtk.merge import MergeDialog
400
        
401
        (wt, path) = workingtree.WorkingTree.open_containing('.')
402
        old_tree = wt.branch.repository.revision_tree(wt.branch.last_revision())
403
        delta = wt.changes_from(old_tree)
404
        if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
405
            error_dialog(_i18n('There are local changes in the branch'),
406
                         _i18n('Please commit or revert the changes before merging.'))
407
        else:
408
            parent_branch_path = wt.branch.get_parent()
409
            merge = MergeDialog(wt, path, parent_branch_path)
410
            response = merge.run()
411
            merge.destroy()
412
413
414
class cmd_gmissing(Command):
415
    """ GTK+ missing revisions dialog.
416
417
    """
418
    takes_args = ["other_branch?"]
419
    def run(self, other_branch=None):
420
        pygtk = import_pygtk()
421
        try:
422
            import gtk
423
        except RuntimeError, e:
424
            if str(e) == "could not open display":
425
                raise NoDisplayError
426
427
        from bzrlib.plugins.gtk.missing import MissingWindow
428
        from bzrlib.branch import Branch
429
430
        local_branch = Branch.open_containing(".")[0]
431
        if other_branch is None:
432
            other_branch = local_branch.get_parent()
433
            
434
            if other_branch is None:
435
                raise errors.BzrCommandError("No peer location known or specified.")
436
        remote_branch = Branch.open_containing(other_branch)[0]
437
        set_ui_factory()
438
        local_branch.lock_read()
439
        try:
440
            remote_branch.lock_read()
441
            try:
442
                dialog = MissingWindow(local_branch, remote_branch)
443
                dialog.run()
444
            finally:
445
                remote_branch.unlock()
446
        finally:
447
            local_branch.unlock()
448
449
450
class cmd_ginit(GTKCommand):
451
    def run(self):
452
        open_display()
453
        from initialize import InitDialog
454
        dialog = InitDialog(os.path.abspath(os.path.curdir))
455
        dialog.run()
456
457
458
class cmd_gtags(GTKCommand):
459
    def run(self):
460
        br = branch.Branch.open_containing('.')[0]
461
        
462
        gtk = open_display()
463
        from tags import TagsWindow
464
        window = TagsWindow(br)
465
        window.show()
466
        gtk.main()
467
468
469
class cmd_gselftest(GTKCommand):
470
    """Version of selftest that displays a notification at the end"""
471
472
    takes_args = builtins.cmd_selftest.takes_args
473
    takes_options = builtins.cmd_selftest.takes_options
474
    _see_also = ['selftest']
475
476
    def run(self, *args, **kwargs):
477
        import cgi
478
        import sys
479
        default_encoding = sys.getdefaultencoding()
480
        # prevent gtk from blowing up later
481
        gtk = import_pygtk()
482
        # prevent gtk from messing with default encoding
483
        import pynotify
484
        if sys.getdefaultencoding() != default_encoding:
485
            reload(sys)
486
            sys.setdefaultencoding(default_encoding)
487
        result = builtins.cmd_selftest().run(*args, **kwargs)
488
        if result == 0:
489
            summary = 'Success'
490
            body = 'Selftest succeeded in "%s"' % os.getcwd()
491
        if result == 1:
492
            summary = 'Failure'
493
            body = 'Selftest failed in "%s"' % os.getcwd()
494
        pynotify.init("bzr gselftest")
495
        note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
496
        note.set_timeout(pynotify.EXPIRES_NEVER)
497
        note.show()