/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to viz/branchwin.py

  • Committer: Jelmer Vernooij
  • Date: 2010-03-03 14:10:25 UTC
  • mto: This revision was merged to the branch mainline in revision 686.
  • Revision ID: jelmer@samba.org-20100303141025-rz53ongyh8miv3q5
Don't crash when there is already a lan-notify instance running.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
import gobject
14
14
import pango
15
15
 
16
 
from bzrlib.plugins.gtk.window import Window
17
16
from bzrlib.plugins.gtk import icon_path
 
17
from bzrlib.plugins.gtk.branchview import TreeView, treemodel
18
18
from bzrlib.plugins.gtk.tags import AddTagDialog
19
19
from bzrlib.plugins.gtk.preferences import PreferencesWindow
20
 
from bzrlib.plugins.gtk.branchview import TreeView, treemodel
 
20
from bzrlib.plugins.gtk.revisionmenu import RevisionMenu
 
21
from bzrlib.plugins.gtk.window import Window
21
22
 
22
23
from bzrlib.config import BranchConfig, GlobalConfig
23
24
from bzrlib.revision import Revision, NULL_REVISION
52
53
        else:
53
54
            self.compact_view = False
54
55
 
55
 
        self.set_title(branch.nick + " - revision history")
 
56
        self.set_title(branch._get_nick(local=True) + " - revision history")
56
57
 
57
 
        # Use three-quarters of the screen by default
58
 
        screen = self.get_screen()
59
 
        monitor = screen.get_monitor_geometry(0)
60
 
        width = int(monitor.width * 0.75)
61
 
        height = int(monitor.height * 0.75)
 
58
        # user-configured window size
 
59
        size = self._load_size('viz-window-size')
 
60
        if size:
 
61
            width, height = size
 
62
        else:
 
63
            # Use three-quarters of the screen by default
 
64
            screen = self.get_screen()
 
65
            monitor = screen.get_monitor_geometry(0)
 
66
            width = int(monitor.width * 0.75)
 
67
            height = int(monitor.height * 0.75)
62
68
        self.set_default_size(width, height)
 
69
        self.set_size_request(width/3, height/3)
 
70
        self._save_size_on_destroy(self, 'viz-window-size')
63
71
 
64
72
        # FIXME AndyFitz!
65
73
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
94
102
 
95
103
        self.construct()
96
104
 
 
105
    def _save_size_on_destroy(self, widget, config_name):
 
106
        """Creates a hook that saves the size of widget to config option 
 
107
           config_name when the window is destroyed/closed."""
 
108
        def save_size(src):
 
109
            width, height = widget.allocation.width, widget.allocation.height
 
110
            value = '%sx%s' % (width, height)
 
111
            self.config.set_user_option(config_name, value)
 
112
        self.connect("destroy", save_size)
 
113
 
97
114
    def set_revision(self, revid):
98
115
        self.treeview.set_revision_id(revid)
99
116
 
103
120
        self.add(vbox)
104
121
 
105
122
        self.paned = gtk.VPaned()
106
 
        self.paned.pack1(self.construct_top(), resize=True, shrink=False)
107
 
        self.paned.pack2(self.construct_bottom(), resize=False, shrink=True)
 
123
        self.paned.pack1(self.construct_top(), resize=False, shrink=True)
 
124
        self.paned.pack2(self.construct_bottom(), resize=True, shrink=False)
108
125
        self.paned.show()
109
126
 
110
 
        vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
111
 
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
112
 
        
 
127
        nav = self.construct_navigation()
 
128
        menubar = self.construct_menubar()
 
129
        vbox.pack_start(menubar, expand=False, fill=True)
 
130
        vbox.pack_start(nav, expand=False, fill=True)
 
131
 
113
132
        vbox.pack_start(self.paned, expand=True, fill=True)
114
133
        vbox.set_focus_child(self.paned)
115
134
 
 
135
        self.treeview.connect('revision-selected',
 
136
                self._treeselection_changed_cb)
 
137
        self.treeview.connect('revision-activated',
 
138
                self._tree_revision_activated)
 
139
 
 
140
        self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
116
141
        vbox.show()
117
 
 
 
142
    
118
143
    def construct_menubar(self):
119
144
        menubar = gtk.MenuBar()
120
145
 
136
161
        edit_menuitem = gtk.MenuItem("_Edit")
137
162
        edit_menuitem.set_submenu(edit_menu)
138
163
 
139
 
        edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
140
 
 
141
164
        edit_menu_branchopts = gtk.MenuItem("Branch Settings")
142
165
        edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
143
166
 
144
167
        edit_menu_globopts = gtk.MenuItem("Global Settings")
145
168
        edit_menu_globopts.connect('activate', lambda x: PreferencesWindow().show())
146
169
 
147
 
        edit_menu.add(edit_menu_find)
148
170
        edit_menu.add(edit_menu_branchopts)
149
171
        edit_menu.add(edit_menu_globopts)
150
172
 
160
182
 
161
183
        view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
162
184
        view_menu_toolbar.set_active(True)
 
185
        if self.config.get_user_option('viz-toolbar-visible') == 'False':
 
186
            view_menu_toolbar.set_active(False)
 
187
            self.toolbar.hide()
163
188
        view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
164
189
 
165
190
        view_menu_compact = gtk.CheckMenuItem("Show Compact Graph")
166
191
        view_menu_compact.set_active(self.compact_view)
167
192
        view_menu_compact.connect('activate', self._brokenlines_toggled_cb)
168
 
 
 
193
        
 
194
        view_menu_diffs = gtk.CheckMenuItem("Show Diffs")
 
195
        view_menu_diffs.set_active(False)
 
196
        if self.config.get_user_option('viz-show-diffs') == 'True':
 
197
            view_menu_diffs.set_active(True)
 
198
        view_menu_diffs.connect('toggled', self._diff_visibility_changed)
 
199
        
 
200
        view_menu_wide_diffs = gtk.CheckMenuItem("Wide Diffs")
 
201
        view_menu_wide_diffs.set_active(False)
 
202
        if self.config.get_user_option('viz-wide-diffs') == 'True':
 
203
            view_menu_wide_diffs.set_active(True)
 
204
        view_menu_wide_diffs.connect('toggled', self._diff_placement_changed)
 
205
        
 
206
        view_menu_wrap_diffs = gtk.CheckMenuItem("Wrap _Long Lines in Diffs")
 
207
        view_menu_wrap_diffs.set_active(False)
 
208
        if self.config.get_user_option('viz-wrap-diffs') == 'True':
 
209
            view_menu_wrap_diffs.set_active(True)
 
210
        view_menu_wrap_diffs.connect('toggled', self._diff_wrap_changed)
 
211
                
169
212
        view_menu.add(view_menu_toolbar)
170
213
        view_menu.add(view_menu_compact)
171
214
        view_menu.add(gtk.SeparatorMenuItem())
 
215
        view_menu.add(view_menu_diffs)
 
216
        view_menu.add(view_menu_wide_diffs)
 
217
        view_menu.add(view_menu_wrap_diffs)
 
218
        view_menu.add(gtk.SeparatorMenuItem())
172
219
 
173
220
        self.mnu_show_revno_column = gtk.CheckMenuItem("Show Revision _Number Column")
174
221
        self.mnu_show_date_column = gtk.CheckMenuItem("Show _Date Column")
196
243
        tag_image.set_from_file(icon_path("tag-16.png"))
197
244
        self.go_menu_tags = gtk.ImageMenuItem("_Tags")
198
245
        self.go_menu_tags.set_image(tag_image)
199
 
        self._update_tags()
 
246
        self.treeview.connect('refreshed', lambda w: self._update_tags())
200
247
 
201
248
        go_menu.add(go_menu_next)
202
249
        go_menu.add(go_menu_prev)
203
250
        go_menu.add(gtk.SeparatorMenuItem())
204
251
        go_menu.add(self.go_menu_tags)
205
252
 
206
 
        revision_menu = gtk.Menu()
 
253
        self.revision_menu = RevisionMenu(self.branch.repository, [], self.branch, parent=self)
207
254
        revision_menuitem = gtk.MenuItem("_Revision")
208
 
        revision_menuitem.set_submenu(revision_menu)
209
 
 
210
 
        revision_menu_diff = gtk.MenuItem("View Changes")
211
 
        revision_menu_diff.connect('activate', 
212
 
                self._menu_diff_cb)
213
 
        
214
 
        revision_menu_compare = gtk.MenuItem("Compare with...")
215
 
        revision_menu_compare.connect('activate',
216
 
                self._compare_with_cb)
217
 
 
218
 
        revision_menu_tag = gtk.MenuItem("Tag Revision")
219
 
        revision_menu_tag.connect('activate', self._tag_revision_cb)
220
 
 
221
 
        revision_menu.add(revision_menu_tag)
222
 
        revision_menu.add(revision_menu_diff)
223
 
        revision_menu.add(revision_menu_compare)
 
255
        revision_menuitem.set_submenu(self.revision_menu)
224
256
 
225
257
        branch_menu = gtk.Menu()
226
258
        branch_menuitem = gtk.MenuItem("_Branch")
234
266
        except ImportError:
235
267
            mutter("Didn't find search plugin")
236
268
        else:
 
269
            branch_menu.add(gtk.SeparatorMenuItem())
 
270
 
237
271
            branch_index_menuitem = gtk.MenuItem("_Index")
238
272
            branch_index_menuitem.connect('activate', self._branch_index_cb)
239
273
            branch_menu.add(branch_index_menuitem)
240
274
 
 
275
            branch_search_menuitem = gtk.MenuItem("_Search")
 
276
            branch_search_menuitem.connect('activate', self._branch_search_cb)
 
277
            branch_menu.add(branch_search_menuitem)
 
278
 
241
279
        help_menu = gtk.Menu()
242
280
        help_menuitem = gtk.MenuItem("_Help")
243
281
        help_menuitem.set_submenu(help_menu)
264
302
 
265
303
        self.treeview = TreeView(self.branch, self.start_revs, self.maxnum, self.compact_view)
266
304
 
267
 
        self.treeview.connect('revision-selected',
268
 
                self._treeselection_changed_cb)
269
 
        self.treeview.connect('revision-activated',
270
 
                self._tree_revision_activated)
271
 
 
272
 
        self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
273
 
 
274
305
        for col in ["revno", "date"]:
275
306
            option = self.config.get_user_option(col + '-column-visible')
276
307
            if option is not None:
283
314
        align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
284
315
        align.set_padding(5, 0, 0, 0)
285
316
        align.add(self.treeview)
 
317
        # user-configured size
 
318
        size = self._load_size('viz-graph-size')
 
319
        if size:
 
320
            width, height = size
 
321
            align.set_size_request(width, height)
 
322
        else:
 
323
            (width, height) = self.get_size()
 
324
            align.set_size_request(width, int(height / 2.5))
 
325
        self._save_size_on_destroy(align, 'viz-graph-size')
286
326
        align.show()
287
327
 
288
328
        return align
310
350
 
311
351
    def construct_bottom(self):
312
352
        """Construct the bottom half of the window."""
 
353
        if self.config.get_user_option('viz-wide-diffs') == 'True':
 
354
            self.diff_paned = gtk.VPaned()
 
355
        else:
 
356
            self.diff_paned = gtk.HPaned()
 
357
        (width, height) = self.get_size()
 
358
        self.diff_paned.set_size_request(20, 20) # shrinkable
 
359
 
313
360
        from bzrlib.plugins.gtk.revisionview import RevisionView
314
361
        self.revisionview = RevisionView(branch=self.branch)
315
 
        (width, height) = self.get_size()
316
 
        self.revisionview.set_size_request(width, int(height / 2.5))
 
362
        self.revisionview.set_size_request(width/3, int(height / 2.5))
 
363
        # user-configured size
 
364
        size = self._load_size('viz-revisionview-size')
 
365
        if size:
 
366
            width, height = size
 
367
            self.revisionview.set_size_request(width, height)
 
368
        self._save_size_on_destroy(self.revisionview, 'viz-revisionview-size')
317
369
        self.revisionview.show()
318
370
        self.revisionview.set_show_callback(self._show_clicked_cb)
319
371
        self.revisionview.connect('notify::revision', self._go_clicked_cb)
320
372
        self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
321
 
        return self.revisionview
 
373
        self.diff_paned.pack1(self.revisionview)
 
374
 
 
375
        from bzrlib.plugins.gtk.diff import DiffWidget
 
376
        self.diff = DiffWidget()
 
377
        self.diff_paned.pack2(self.diff)
 
378
 
 
379
        self.diff_paned.show_all()
 
380
        if self.config.get_user_option('viz-show-diffs') != 'True':
 
381
            self.diff.hide()
 
382
 
 
383
        return self.diff_paned
322
384
 
323
385
    def _tag_selected_cb(self, menuitem, revid):
324
386
        self.treeview.set_revision_id(revid)
329
391
        parents  = self.treeview.get_parents()
330
392
        children = self.treeview.get_children()
331
393
 
 
394
        self.revision_menu.set_revision_ids([revision.revision_id])
 
395
 
332
396
        if revision and revision != NULL_REVISION:
333
397
            prev_menu = gtk.Menu()
334
398
            if len(parents) > 0:
373
437
 
374
438
            self.revisionview.set_revision(revision)
375
439
            self.revisionview.set_children(children)
376
 
    
 
440
            self.update_diff_panel(revision, parents)
 
441
 
377
442
    def _tree_revision_activated(self, widget, path, col):
378
443
        # TODO: more than one parent
379
444
        """Callback for when a treeview row gets activated."""
381
446
        parents  = self.treeview.get_parents()
382
447
 
383
448
        if len(parents) == 0:
384
 
            parent_id = None
 
449
            parent_id = NULL_REVISION
385
450
        else:
386
451
            parent_id = parents[0]
387
452
 
388
453
        self.show_diff(revision.revision_id, parent_id)
389
454
        self.treeview.grab_focus()
390
455
        
391
 
    def _menu_diff_cb(self,w):
392
 
        (path, focus) = self.treeview.treeview.get_cursor()
393
 
        revid = self.treeview.model[path][treemodel.REVID]
394
 
        
395
 
        parentids = self.branch.repository.revision_parents(revid)
396
 
 
397
 
        if len(parentids) == 0:
398
 
            parentid = NULL_REVISION
399
 
        else:
400
 
            parentid = parentids[0]
401
 
        
402
 
        self.show_diff(revid,parentid)    
403
 
 
404
456
    def _back_clicked_cb(self, *args):
405
457
        """Callback for when the back button is clicked."""
406
458
        self.treeview.back()
419
471
        self.show_diff(revid, parentid)
420
472
        self.treeview.grab_focus()
421
473
 
422
 
    def _compare_with_cb(self,w):
423
 
        """Callback for revision 'compare with' menu. Will show a small
424
 
            dialog with branch revisions to compare with selected revision in TreeView"""
425
 
        
426
 
        from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
427
 
        
428
 
        rb = RevisionBrowser(self.branch,self)
429
 
        ret = rb.run()
430
 
        
431
 
        if ret == gtk.RESPONSE_OK:          
432
 
            (path, focus) = self.treeview.treeview.get_cursor()
433
 
            revid = self.treeview.model[path][treemodel.REVID]
434
 
            self.show_diff(revid, rb.selected_revid)
435
 
            
436
 
        rb.destroy()
437
 
            
438
474
    def _set_revision_cb(self, w, revision_id):
439
475
        self.treeview.set_revision_id(revision_id)
440
476
 
450
486
        self.treeview.set_property('compact', self.compact_view)
451
487
        self.treeview.refresh()
452
488
 
453
 
    def _tag_revision_cb(self, w):
454
 
        try:
455
 
            self.treeview.set_sensitive(False)
456
 
            dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
457
 
            response = dialog.run()
458
 
            if response != gtk.RESPONSE_NONE:
459
 
                dialog.hide()
460
 
            
461
 
                if response == gtk.RESPONSE_OK:
462
 
                    self.treeview.add_tag(dialog.tagname, dialog._revid)
463
 
                
464
 
                dialog.destroy()
465
 
 
466
 
        finally:
467
 
            self.treeview.set_sensitive(True)
468
 
 
469
489
    def _branch_index_cb(self, w):
470
490
        from bzrlib.plugins.search import index as _mod_index
471
491
        _mod_index.index_url(self.branch.base)
472
492
 
 
493
    def _branch_search_cb(self, w):
 
494
        from bzrlib.plugins.search import index as _mod_index
 
495
        from bzrlib.plugins.gtk.search import SearchDialog
 
496
        from bzrlib.plugins.search import errors as search_errors
 
497
 
 
498
        try:
 
499
            index = _mod_index.open_index_url(self.branch.base)
 
500
        except search_errors.NoSearchIndex:
 
501
            dialog = gtk.MessageDialog(self, type=gtk.MESSAGE_QUESTION, 
 
502
                buttons=gtk.BUTTONS_OK_CANCEL, 
 
503
                message_format="This branch has not been indexed yet. "
 
504
                               "Index now?")
 
505
            if dialog.run() == gtk.RESPONSE_OK:
 
506
                dialog.destroy()
 
507
                index = _mod_index.index_url(self.branch.base)
 
508
            else:
 
509
                dialog.destroy()
 
510
                return
 
511
 
 
512
        dialog = SearchDialog(index)
 
513
        
 
514
        if dialog.run() == gtk.RESPONSE_OK:
 
515
            self.set_revision(dialog.get_revision())
 
516
 
 
517
        dialog.destroy()
 
518
 
473
519
    def _about_dialog_cb(self, w):
474
520
        from bzrlib.plugins.gtk.about import AboutDialog
475
521
 
481
527
 
482
528
    def _toolbar_visibility_changed(self, col):
483
529
        if col.get_active():
484
 
            self.toolbar.show() 
 
530
            self.toolbar.show()
485
531
        else:
486
532
            self.toolbar.hide()
487
 
 
 
533
        self.config.set_user_option('viz-toolbar-visible', col.get_active())
 
534
 
 
535
    def _make_diff_nonzero_size(self):
 
536
        """make sure the diff isn't zero-width or zero-height"""
 
537
        alloc = self.diff.get_allocation()
 
538
        if (alloc.width < 10) or (alloc.height < 10):
 
539
            width, height = self.get_size()
 
540
            self.revisionview.set_size_request(width/3, int(height / 2.5))
 
541
 
 
542
    def _diff_visibility_changed(self, col):
 
543
        """Hide or show the diff panel."""
 
544
        if col.get_active():
 
545
            self.diff.show()
 
546
            self._make_diff_nonzero_size()
 
547
        else:
 
548
            self.diff.hide()
 
549
        self.config.set_user_option('viz-show-diffs', str(col.get_active()))
 
550
        self.update_diff_panel()
 
551
 
 
552
    def _diff_placement_changed(self, col):
 
553
        """Toggle the diff panel's position."""
 
554
        self.config.set_user_option('viz-wide-diffs', str(col.get_active()))
 
555
 
 
556
        old = self.paned.get_child2()
 
557
        self.paned.remove(old)
 
558
        self.paned.pack2(self.construct_bottom(), resize=True, shrink=False)
 
559
        self._make_diff_nonzero_size()
 
560
 
 
561
        self.treeview.emit('revision-selected')
 
562
    
 
563
    def _diff_wrap_changed(self, widget):
 
564
        """Toggle word wrap in the diff widget."""
 
565
        self.config.set_user_option('viz-wrap-diffs', widget.get_active())
 
566
        self.diff._on_wraplines_toggled(widget)
 
567
    
488
568
    def _show_about_cb(self, w):
489
569
        dialog = AboutDialog()
490
570
        dialog.connect('response', lambda d,r: d.destroy())
498
578
 
499
579
        if self.branch.supports_tags():
500
580
            tags = self.branch.tags.get_tag_dict().items()
501
 
            tags.sort()
502
 
            tags.reverse()
 
581
            tags.sort(reverse=True)
503
582
            for tag, revid in tags:
504
583
                tag_image = gtk.Image()
505
584
                tag_image.set_from_file(icon_path('tag-16.png'))
506
585
                tag_item = gtk.ImageMenuItem(tag.replace('_', '__'))
507
586
                tag_item.set_image(tag_image)
508
587
                tag_item.connect('activate', self._tag_selected_cb, revid)
 
588
                tag_item.set_sensitive(self.treeview.has_revision_id(revid))
509
589
                menu.add(tag_item)
510
590
            self.go_menu_tags.set_submenu(menu)
511
591
 
515
595
 
516
596
        self.go_menu_tags.show_all()
517
597
 
518
 
    def show_diff(self, revid=None, parentid=None):
 
598
    def _load_size(self, name):
 
599
        """Read and parse 'name' from self.config.
 
600
        The value is a string, formatted as WIDTHxHEIGHT
 
601
        Returns None, or (width, height)
 
602
        """
 
603
        size = self.config.get_user_option(name)
 
604
        if size:
 
605
            width, height = [int(num) for num in size.split('x')]
 
606
            # avoid writing config every time we start
 
607
            return width, height
 
608
        return None
 
609
 
 
610
    def show_diff(self, revid=None, parentid=NULL_REVISION):
519
611
        """Open a new window to show a diff between the given revisions."""
520
612
        from bzrlib.plugins.gtk.diff import DiffWindow
521
613
        window = DiffWindow(parent=self)
522
614
 
523
 
        if parentid is None:
524
 
            parentid = NULL_REVISION
525
 
 
526
615
        rev_tree    = self.branch.repository.revision_tree(revid)
527
616
        parent_tree = self.branch.repository.revision_tree(parentid)
528
617
 
529
 
        description = revid + " - " + self.branch.nick
 
618
        description = revid + " - " + self.branch._get_nick(local=True)
530
619
        window.set_diff(description, rev_tree, parent_tree)
531
620
        window.show()
532
621
 
533
 
 
 
622
    def update_diff_panel(self, revision=None, parents=None):
 
623
        """Show the current revision in the diff panel."""
 
624
        if self.config.get_user_option('viz-show-diffs') != 'True':
 
625
            return
 
626
 
 
627
        if not revision: # default to selected row
 
628
            revision = self.treeview.get_revision()
 
629
        if revision == NULL_REVISION:
 
630
            return
 
631
 
 
632
        if not parents: # default to selected row's parents
 
633
            parents  = self.treeview.get_parents()
 
634
        if len(parents) == 0:
 
635
            parent_id = NULL_REVISION
 
636
        else:
 
637
            parent_id = parents[0]
 
638
 
 
639
        rev_tree    = self.branch.repository.revision_tree(revision.revision_id)
 
640
        parent_tree = self.branch.repository.revision_tree(parent_id)
 
641
 
 
642
        self.diff.set_diff(rev_tree, parent_tree)
 
643
        if self.config.get_user_option('viz-wrap-diffs') == 'True':
 
644
            self.diff._on_wraplines_toggled(wrap=True)
 
645
        self.diff.show_all()