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