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