/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: Vincent Ladeuil
  • Date: 2009-12-10 16:13:32 UTC
  • Revision ID: v.ladeuil+lp@free.fr-20091210161332-d9vlfd6jy6zolxa1
Thanks to lamont, we know spell Prettifying with the right number of 't'.

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
 
22
 
 
23
from bzrlib.config import BranchConfig, GlobalConfig
21
24
from bzrlib.revision import Revision, NULL_REVISION
22
 
from bzrlib.config import BranchConfig
23
 
from bzrlib.config import GlobalConfig
 
25
from bzrlib.trace import mutter
24
26
 
25
27
class BranchWindow(Window):
26
28
    """Branch window.
51
53
        else:
52
54
            self.compact_view = False
53
55
 
54
 
        self.set_title(branch.nick + " - revision history")
 
56
        self.set_title(branch._get_nick(local=True) + " - revision history")
55
57
 
56
 
        # Use three-quarters of the screen by default
57
 
        screen = self.get_screen()
58
 
        monitor = screen.get_monitor_geometry(0)
59
 
        width = int(monitor.width * 0.75)
60
 
        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)
61
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')
62
71
 
63
72
        # FIXME AndyFitz!
64
73
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
93
102
 
94
103
        self.construct()
95
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
 
96
114
    def set_revision(self, revid):
97
115
        self.treeview.set_revision_id(revid)
98
116
 
102
120
        self.add(vbox)
103
121
 
104
122
        self.paned = gtk.VPaned()
105
 
        self.paned.pack1(self.construct_top(), resize=True, shrink=False)
106
 
        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)
107
125
        self.paned.show()
108
126
 
109
 
        vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
110
 
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
111
 
        
 
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
 
112
132
        vbox.pack_start(self.paned, expand=True, fill=True)
113
133
        vbox.set_focus_child(self.paned)
114
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())
115
141
        vbox.show()
116
 
 
 
142
    
117
143
    def construct_menubar(self):
118
144
        menubar = gtk.MenuBar()
119
145
 
135
161
        edit_menuitem = gtk.MenuItem("_Edit")
136
162
        edit_menuitem.set_submenu(edit_menu)
137
163
 
138
 
        edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
139
 
 
140
164
        edit_menu_branchopts = gtk.MenuItem("Branch Settings")
141
165
        edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
142
166
 
143
167
        edit_menu_globopts = gtk.MenuItem("Global Settings")
144
168
        edit_menu_globopts.connect('activate', lambda x: PreferencesWindow().show())
145
169
 
146
 
        edit_menu.add(edit_menu_find)
147
170
        edit_menu.add(edit_menu_branchopts)
148
171
        edit_menu.add(edit_menu_globopts)
149
172
 
159
182
 
160
183
        view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
161
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()
162
188
        view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
163
189
 
164
190
        view_menu_compact = gtk.CheckMenuItem("Show Compact Graph")
165
191
        view_menu_compact.set_active(self.compact_view)
166
192
        view_menu_compact.connect('activate', self._brokenlines_toggled_cb)
167
 
 
 
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
                
168
212
        view_menu.add(view_menu_toolbar)
169
213
        view_menu.add(view_menu_compact)
170
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())
171
219
 
172
220
        self.mnu_show_revno_column = gtk.CheckMenuItem("Show Revision _Number Column")
173
221
        self.mnu_show_date_column = gtk.CheckMenuItem("Show _Date Column")
195
243
        tag_image.set_from_file(icon_path("tag-16.png"))
196
244
        self.go_menu_tags = gtk.ImageMenuItem("_Tags")
197
245
        self.go_menu_tags.set_image(tag_image)
198
 
        self._update_tags()
 
246
        self.treeview.connect('refreshed', lambda w: self._update_tags())
199
247
 
200
248
        go_menu.add(go_menu_next)
201
249
        go_menu.add(go_menu_prev)
202
250
        go_menu.add(gtk.SeparatorMenuItem())
203
251
        go_menu.add(self.go_menu_tags)
204
252
 
205
 
        revision_menu = gtk.Menu()
 
253
        self.revision_menu = RevisionMenu(self.branch.repository, [], self.branch, parent=self)
206
254
        revision_menuitem = gtk.MenuItem("_Revision")
207
 
        revision_menuitem.set_submenu(revision_menu)
208
 
 
209
 
        revision_menu_diff = gtk.MenuItem("View Changes")
210
 
        revision_menu_diff.connect('activate', 
211
 
                self._menu_diff_cb)
212
 
        
213
 
        revision_menu_compare = gtk.MenuItem("Compare with...")
214
 
        revision_menu_compare.connect('activate',
215
 
                self._compare_with_cb)
216
 
 
217
 
        revision_menu_tag = gtk.MenuItem("Tag Revision")
218
 
        revision_menu_tag.connect('activate', self._tag_revision_cb)
219
 
 
220
 
        revision_menu.add(revision_menu_tag)
221
 
        revision_menu.add(revision_menu_diff)
222
 
        revision_menu.add(revision_menu_compare)
 
255
        revision_menuitem.set_submenu(self.revision_menu)
223
256
 
224
257
        branch_menu = gtk.Menu()
225
258
        branch_menuitem = gtk.MenuItem("_Branch")
228
261
        branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
229
262
        branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
230
263
 
 
264
        try:
 
265
            from bzrlib.plugins import search
 
266
        except ImportError:
 
267
            mutter("Didn't find search plugin")
 
268
        else:
 
269
            branch_menu.add(gtk.SeparatorMenuItem())
 
270
 
 
271
            branch_index_menuitem = gtk.MenuItem("_Index")
 
272
            branch_index_menuitem.connect('activate', self._branch_index_cb)
 
273
            branch_menu.add(branch_index_menuitem)
 
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
 
231
279
        help_menu = gtk.Menu()
232
280
        help_menuitem = gtk.MenuItem("_Help")
233
281
        help_menuitem.set_submenu(help_menu)
254
302
 
255
303
        self.treeview = TreeView(self.branch, self.start_revs, self.maxnum, self.compact_view)
256
304
 
257
 
        self.treeview.connect('revision-selected',
258
 
                self._treeselection_changed_cb)
259
 
        self.treeview.connect('revision-activated',
260
 
                self._tree_revision_activated)
261
 
 
262
 
        self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
263
 
 
264
305
        for col in ["revno", "date"]:
265
306
            option = self.config.get_user_option(col + '-column-visible')
266
307
            if option is not None:
273
314
        align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
274
315
        align.set_padding(5, 0, 0, 0)
275
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')
276
326
        align.show()
277
327
 
278
328
        return align
300
350
 
301
351
    def construct_bottom(self):
302
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
 
303
360
        from bzrlib.plugins.gtk.revisionview import RevisionView
304
361
        self.revisionview = RevisionView(branch=self.branch)
305
 
        (width, height) = self.get_size()
306
 
        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')
307
369
        self.revisionview.show()
308
370
        self.revisionview.set_show_callback(self._show_clicked_cb)
309
371
        self.revisionview.connect('notify::revision', self._go_clicked_cb)
310
372
        self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
311
 
        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
312
384
 
313
385
    def _tag_selected_cb(self, menuitem, revid):
314
386
        self.treeview.set_revision_id(revid)
319
391
        parents  = self.treeview.get_parents()
320
392
        children = self.treeview.get_children()
321
393
 
 
394
        self.revision_menu.set_revision_ids([revision.revision_id])
 
395
 
322
396
        if revision and revision != NULL_REVISION:
323
397
            prev_menu = gtk.Menu()
324
398
            if len(parents) > 0:
363
437
 
364
438
            self.revisionview.set_revision(revision)
365
439
            self.revisionview.set_children(children)
366
 
    
 
440
            self.update_diff_panel(revision, parents)
 
441
 
367
442
    def _tree_revision_activated(self, widget, path, col):
368
443
        # TODO: more than one parent
369
444
        """Callback for when a treeview row gets activated."""
371
446
        parents  = self.treeview.get_parents()
372
447
 
373
448
        if len(parents) == 0:
374
 
            parent_id = None
 
449
            parent_id = NULL_REVISION
375
450
        else:
376
451
            parent_id = parents[0]
377
452
 
378
453
        self.show_diff(revision.revision_id, parent_id)
379
454
        self.treeview.grab_focus()
380
455
        
381
 
    def _menu_diff_cb(self,w):
382
 
        (path, focus) = self.treeview.treeview.get_cursor()
383
 
        revid = self.treeview.model[path][treemodel.REVID]
384
 
        
385
 
        parentids = self.branch.repository.revision_parents(revid)
386
 
 
387
 
        if len(parentids) == 0:
388
 
            parentid = NULL_REVISION
389
 
        else:
390
 
            parentid = parentids[0]
391
 
        
392
 
        self.show_diff(revid,parentid)    
393
 
 
394
456
    def _back_clicked_cb(self, *args):
395
457
        """Callback for when the back button is clicked."""
396
458
        self.treeview.back()
409
471
        self.show_diff(revid, parentid)
410
472
        self.treeview.grab_focus()
411
473
 
412
 
    def _compare_with_cb(self,w):
413
 
        """Callback for revision 'compare with' menu. Will show a small
414
 
            dialog with branch revisions to compare with selected revision in TreeView"""
415
 
        
416
 
        from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
417
 
        
418
 
        rb = RevisionBrowser(self.branch,self)
419
 
        ret = rb.run()
420
 
        
421
 
        if ret == gtk.RESPONSE_OK:          
422
 
            (path, focus) = self.treeview.treeview.get_cursor()
423
 
            revid = self.treeview.model[path][treemodel.REVID]
424
 
            self.show_diff(revid, rb.selected_revid)
425
 
            
426
 
        rb.destroy()
427
 
            
428
474
    def _set_revision_cb(self, w, revision_id):
429
475
        self.treeview.set_revision_id(revision_id)
430
476
 
440
486
        self.treeview.set_property('compact', self.compact_view)
441
487
        self.treeview.refresh()
442
488
 
443
 
    def _tag_revision_cb(self, w):
 
489
    def _branch_index_cb(self, w):
 
490
        from bzrlib.plugins.search import index as _mod_index
 
491
        _mod_index.index_url(self.branch.base)
 
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
 
444
498
        try:
445
 
            self.treeview.set_sensitive(False)
446
 
            dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
447
 
            response = dialog.run()
448
 
            if response != gtk.RESPONSE_NONE:
449
 
                dialog.hide()
450
 
            
451
 
                if response == gtk.RESPONSE_OK:
452
 
                    self.treeview.add_tag(dialog.tagname, dialog._revid)
453
 
                
454
 
                dialog.destroy()
455
 
 
456
 
        finally:
457
 
            self.treeview.set_sensitive(True)
 
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()
458
518
 
459
519
    def _about_dialog_cb(self, w):
460
520
        from bzrlib.plugins.gtk.about import AboutDialog
467
527
 
468
528
    def _toolbar_visibility_changed(self, col):
469
529
        if col.get_active():
470
 
            self.toolbar.show() 
 
530
            self.toolbar.show()
471
531
        else:
472
532
            self.toolbar.hide()
473
 
 
 
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
    
474
568
    def _show_about_cb(self, w):
475
569
        dialog = AboutDialog()
476
570
        dialog.connect('response', lambda d,r: d.destroy())
484
578
 
485
579
        if self.branch.supports_tags():
486
580
            tags = self.branch.tags.get_tag_dict().items()
487
 
            tags.sort()
488
 
            tags.reverse()
 
581
            tags.sort(reverse=True)
489
582
            for tag, revid in tags:
490
583
                tag_image = gtk.Image()
491
584
                tag_image.set_from_file(icon_path('tag-16.png'))
492
585
                tag_item = gtk.ImageMenuItem(tag.replace('_', '__'))
493
586
                tag_item.set_image(tag_image)
494
587
                tag_item.connect('activate', self._tag_selected_cb, revid)
 
588
                tag_item.set_sensitive(self.treeview.has_revision_id(revid))
495
589
                menu.add(tag_item)
496
590
            self.go_menu_tags.set_submenu(menu)
497
591
 
501
595
 
502
596
        self.go_menu_tags.show_all()
503
597
 
504
 
    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):
505
611
        """Open a new window to show a diff between the given revisions."""
506
612
        from bzrlib.plugins.gtk.diff import DiffWindow
507
613
        window = DiffWindow(parent=self)
508
614
 
509
 
        if parentid is None:
510
 
            parentid = NULL_REVISION
511
 
 
512
615
        rev_tree    = self.branch.repository.revision_tree(revid)
513
616
        parent_tree = self.branch.repository.revision_tree(parentid)
514
617
 
515
 
        description = revid + " - " + self.branch.nick
 
618
        description = revid + " - " + self.branch._get_nick(local=True)
516
619
        window.set_diff(description, rev_tree, parent_tree)
517
620
        window.show()
518
621
 
519
 
 
 
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()