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
23
24
from bzrlib.revision import Revision, NULL_REVISION
55
58
self.set_title(branch.nick + " - revision history")
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)
60
# user-configured window size
61
size = self._load_size('viz-window-size')
65
# Use three-quarters of the screen by default
66
screen = self.get_screen()
67
monitor = screen.get_monitor_geometry(0)
68
width = int(monitor.width * 0.75)
69
height = int(monitor.height * 0.75)
62
70
self.set_default_size(width, height)
71
self.set_size_request(width/3, height/3)
72
self.connect("size-allocate", self._on_size_allocate, 'viz-window-size')
65
75
icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
105
115
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)
116
self.paned.pack1(self.construct_top(), resize=False, shrink=True)
117
self.paned.pack2(self.construct_bottom(), resize=True, shrink=False)
108
118
self.paned.show()
110
vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
111
vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
120
nav = self.construct_navigation()
121
menubar = self.construct_menubar()
122
vbox.pack_start(menubar, expand=False, fill=True)
123
vbox.pack_start(nav, expand=False, fill=True)
113
125
vbox.pack_start(self.paned, expand=True, fill=True)
114
126
vbox.set_focus_child(self.paned)
118
130
def construct_menubar(self):
119
131
menubar = gtk.MenuBar()
136
148
edit_menuitem = gtk.MenuItem("_Edit")
137
149
edit_menuitem.set_submenu(edit_menu)
139
edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
141
151
edit_menu_branchopts = gtk.MenuItem("Branch Settings")
142
152
edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
144
154
edit_menu_globopts = gtk.MenuItem("Global Settings")
145
155
edit_menu_globopts.connect('activate', lambda x: PreferencesWindow().show())
147
edit_menu.add(edit_menu_find)
148
157
edit_menu.add(edit_menu_branchopts)
149
158
edit_menu.add(edit_menu_globopts)
161
170
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
162
171
view_menu_toolbar.set_active(True)
172
if self.config.get_user_option('viz-toolbar-visible') == 'False':
173
view_menu_toolbar.set_active(False)
163
175
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
165
177
view_menu_compact = gtk.CheckMenuItem("Show Compact Graph")
166
178
view_menu_compact.set_active(self.compact_view)
167
179
view_menu_compact.connect('activate', self._brokenlines_toggled_cb)
181
view_menu_diffs = gtk.CheckMenuItem("Show Diffs")
182
view_menu_diffs.set_active(False)
183
if self.config.get_user_option('viz-show-diffs') == 'True':
184
view_menu_diffs.set_active(True)
185
view_menu_diffs.connect('toggled', self._diff_visibility_changed)
187
view_menu_wide_diffs = gtk.CheckMenuItem("Wide Diffs")
188
view_menu_wide_diffs.set_active(False)
189
if self.config.get_user_option('viz-wide-diffs') == 'True':
190
view_menu_wide_diffs.set_active(True)
191
view_menu_wide_diffs.connect('toggled', self._diff_placement_changed)
193
view_menu_wrap_diffs = gtk.CheckMenuItem("Wrap _Long Lines in Diffs")
194
view_menu_wrap_diffs.set_active(False)
195
if self.config.get_user_option('viz-wrap-diffs') == 'True':
196
view_menu_wrap_diffs.set_active(True)
197
view_menu_wrap_diffs.connect('toggled', self._diff_wrap_changed)
169
199
view_menu.add(view_menu_toolbar)
170
200
view_menu.add(view_menu_compact)
171
201
view_menu.add(gtk.SeparatorMenuItem())
202
view_menu.add(view_menu_diffs)
203
view_menu.add(view_menu_wide_diffs)
204
view_menu.add(view_menu_wrap_diffs)
205
view_menu.add(gtk.SeparatorMenuItem())
173
207
self.mnu_show_revno_column = gtk.CheckMenuItem("Show Revision _Number Column")
174
208
self.mnu_show_date_column = gtk.CheckMenuItem("Show _Date Column")
196
230
tag_image.set_from_file(icon_path("tag-16.png"))
197
231
self.go_menu_tags = gtk.ImageMenuItem("_Tags")
198
232
self.go_menu_tags.set_image(tag_image)
233
self.treeview.connect('refreshed', lambda w: self._update_tags())
201
235
go_menu.add(go_menu_next)
202
236
go_menu.add(go_menu_prev)
203
237
go_menu.add(gtk.SeparatorMenuItem())
204
238
go_menu.add(self.go_menu_tags)
206
revision_menu = gtk.Menu()
240
self.revision_menu = RevisionMenu(self.branch.repository, [], self.branch, parent=self)
207
241
revision_menuitem = gtk.MenuItem("_Revision")
208
revision_menuitem.set_submenu(revision_menu)
210
revision_menu_diff = gtk.MenuItem("View Changes")
211
revision_menu_diff.connect('activate',
214
revision_menu_compare = gtk.MenuItem("Compare with...")
215
revision_menu_compare.connect('activate',
216
self._compare_with_cb)
218
revision_menu_tag = gtk.MenuItem("Tag Revision")
219
revision_menu_tag.connect('activate', self._tag_revision_cb)
221
revision_menu.add(revision_menu_tag)
222
revision_menu.add(revision_menu_diff)
223
revision_menu.add(revision_menu_compare)
242
revision_menuitem.set_submenu(self.revision_menu)
225
244
branch_menu = gtk.Menu()
226
245
branch_menuitem = gtk.MenuItem("_Branch")
234
253
except ImportError:
235
254
mutter("Didn't find search plugin")
256
branch_menu.add(gtk.SeparatorMenuItem())
237
258
branch_index_menuitem = gtk.MenuItem("_Index")
238
259
branch_index_menuitem.connect('activate', self._branch_index_cb)
239
260
branch_menu.add(branch_index_menuitem)
262
branch_search_menuitem = gtk.MenuItem("_Search")
263
branch_search_menuitem.connect('activate', self._branch_search_cb)
264
branch_menu.add(branch_search_menuitem)
241
266
help_menu = gtk.Menu()
242
267
help_menuitem = gtk.MenuItem("_Help")
243
268
help_menuitem.set_submenu(help_menu)
283
308
align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
284
309
align.set_padding(5, 0, 0, 0)
285
310
align.add(self.treeview)
311
# user-configured size
312
size = self._load_size('viz-graph-size')
315
align.set_size_request(width, height)
317
(width, height) = self.get_size()
318
align.set_size_request(width, int(height / 2.5))
319
align.connect('size-allocate', self._on_size_allocate, 'viz-graph-size')
311
345
def construct_bottom(self):
312
346
"""Construct the bottom half of the window."""
347
if self.config.get_user_option('viz-wide-diffs') == 'True':
348
self.diff_paned = gtk.VPaned()
350
self.diff_paned = gtk.HPaned()
351
(width, height) = self.get_size()
352
self.diff_paned.set_size_request(20, 20) # shrinkable
313
354
from bzrlib.plugins.gtk.revisionview import RevisionView
314
355
self.revisionview = RevisionView(branch=self.branch)
315
(width, height) = self.get_size()
316
self.revisionview.set_size_request(width, int(height / 2.5))
356
self.revisionview.set_size_request(width/3, int(height / 2.5))
357
# user-configured size
358
size = self._load_size('viz-revisionview-size')
361
self.revisionview.set_size_request(width, height)
362
self.revisionview.connect('size-allocate', self._on_size_allocate, 'viz-revisionview-size')
317
363
self.revisionview.show()
318
364
self.revisionview.set_show_callback(self._show_clicked_cb)
319
365
self.revisionview.connect('notify::revision', self._go_clicked_cb)
320
366
self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
321
return self.revisionview
367
self.diff_paned.pack1(self.revisionview)
369
from bzrlib.plugins.gtk.diff import DiffWidget
370
self.diff = DiffWidget()
371
self.diff_paned.pack2(self.diff)
373
self.diff_paned.show_all()
374
if self.config.get_user_option('viz-show-diffs') != 'True':
377
return self.diff_paned
323
379
def _tag_selected_cb(self, menuitem, revid):
324
380
self.treeview.set_revision_id(revid)
374
432
self.revisionview.set_revision(revision)
375
433
self.revisionview.set_children(children)
434
self.update_diff_panel(revision, parents)
377
436
def _tree_revision_activated(self, widget, path, col):
378
437
# TODO: more than one parent
379
438
"""Callback for when a treeview row gets activated."""
388
447
self.show_diff(revision.revision_id, parent_id)
389
448
self.treeview.grab_focus()
391
def _menu_diff_cb(self,w):
392
(path, focus) = self.treeview.treeview.get_cursor()
393
revid = self.treeview.model[path][treemodel.REVID]
395
parentids = self.branch.repository.revision_parents(revid)
397
if len(parentids) == 0:
398
parentid = NULL_REVISION
400
parentid = parentids[0]
402
self.show_diff(revid,parentid)
404
450
def _back_clicked_cb(self, *args):
405
451
"""Callback for when the back button is clicked."""
406
452
self.treeview.back()
419
465
self.show_diff(revid, parentid)
420
466
self.treeview.grab_focus()
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"""
426
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
428
rb = RevisionBrowser(self.branch,self)
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)
438
468
def _set_revision_cb(self, w, revision_id):
439
469
self.treeview.set_revision_id(revision_id)
450
480
self.treeview.set_property('compact', self.compact_view)
451
481
self.treeview.refresh()
453
def _tag_revision_cb(self, w):
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:
461
if response == gtk.RESPONSE_OK:
462
self.treeview.add_tag(dialog.tagname, dialog._revid)
467
self.treeview.set_sensitive(True)
469
483
def _branch_index_cb(self, w):
470
484
from bzrlib.plugins.search import index as _mod_index
471
485
_mod_index.index_url(self.branch.base)
487
def _branch_search_cb(self, w):
488
from bzrlib.plugins.search import index as _mod_index
489
from bzrlib.plugins.gtk.search import SearchDialog
490
from bzrlib.plugins.search import errors as search_errors
493
index = _mod_index.open_index_url(self.branch.base)
494
except search_errors.NoSearchIndex:
495
dialog = gtk.MessageDialog(self, type=gtk.MESSAGE_QUESTION,
496
buttons=gtk.BUTTONS_OK_CANCEL,
497
message_format="This branch has not been indexed yet. "
499
if dialog.run() == gtk.RESPONSE_OK:
501
index = _mod_index.index_url(self.branch.base)
506
dialog = SearchDialog(index)
508
if dialog.run() == gtk.RESPONSE_OK:
509
self.set_revision(dialog.get_revision())
473
513
def _about_dialog_cb(self, w):
474
514
from bzrlib.plugins.gtk.about import AboutDialog
482
522
def _toolbar_visibility_changed(self, col):
483
523
if col.get_active():
486
526
self.toolbar.hide()
527
self.config.set_user_option('viz-toolbar-visible', col.get_active())
529
def _make_diff_nonzero_size(self):
530
"""make sure the diff isn't zero-width or zero-height"""
531
alloc = self.diff.get_allocation()
532
if (alloc.width < 10) or (alloc.height < 10):
533
width, height = self.get_size()
534
self.revisionview.set_size_request(width/3, int(height / 2.5))
536
def _diff_visibility_changed(self, col):
537
"""Hide or show the diff panel."""
540
self._make_diff_nonzero_size()
543
self.config.set_user_option('viz-show-diffs', str(col.get_active()))
544
self.update_diff_panel()
546
def _diff_placement_changed(self, col):
547
"""Toggle the diff panel's position."""
548
self.config.set_user_option('viz-wide-diffs', str(col.get_active()))
550
old = self.paned.get_child2()
551
self.paned.remove(old)
552
self.paned.pack2(self.construct_bottom(), resize=True, shrink=False)
553
self._make_diff_nonzero_size()
555
self.treeview.emit('revision-selected')
557
def _diff_wrap_changed(self, widget):
558
"""Toggle word wrap in the diff widget."""
559
self.config.set_user_option('viz-wrap-diffs', widget.get_active())
560
self.diff._on_wraplines_toggled(widget)
488
562
def _show_about_cb(self, w):
489
563
dialog = AboutDialog()
490
564
dialog.connect('response', lambda d,r: d.destroy())
499
573
if self.branch.supports_tags():
500
574
tags = self.branch.tags.get_tag_dict().items()
575
tags.sort(reverse=True)
503
576
for tag, revid in tags:
504
577
tag_image = gtk.Image()
505
578
tag_image.set_from_file(icon_path('tag-16.png'))
506
579
tag_item = gtk.ImageMenuItem(tag.replace('_', '__'))
507
580
tag_item.set_image(tag_image)
508
581
tag_item.connect('activate', self._tag_selected_cb, revid)
582
tag_item.set_sensitive(self.treeview.has_revision_id(revid))
509
583
menu.add(tag_item)
510
584
self.go_menu_tags.set_submenu(menu)
516
590
self.go_menu_tags.show_all()
592
def _load_size(self, name):
593
"""Read and parse 'name' from self.config.
594
The value is a string, formatted as WIDTHxHEIGHT
595
Returns None, or (width, height)
597
size = self.config.get_user_option(name)
599
width, height = [int(num) for num in size.split('x')]
600
# avoid writing config every time we start
601
self._sizes[name] = (width, height)
605
def _on_size_allocate(self, widget, allocation, name):
606
"""When window has been resized, save the new size."""
608
if name in self._sizes:
609
width, height = self._sizes[name]
611
size_changed = (width != allocation.width) or \
612
(height != allocation.height)
615
width, height = allocation.width, allocation.height
616
self._sizes[name] = (width, height)
617
value = '%sx%s' % (width, height)
618
self.config.set_user_option(name, value)
518
620
def show_diff(self, revid=None, parentid=None):
519
621
"""Open a new window to show a diff between the given revisions."""
520
622
from bzrlib.plugins.gtk.diff import DiffWindow
530
632
window.set_diff(description, rev_tree, parent_tree)
635
def update_diff_panel(self, revision=None, parents=None):
636
"""Show the current revision in the diff panel."""
637
if self.config.get_user_option('viz-show-diffs') != 'True':
640
if not revision: # default to selected row
641
revision = self.treeview.get_revision()
642
if (not revision) or (revision == NULL_REVISION):
645
if not parents: # default to selected row's parents
646
parents = self.treeview.get_parents()
647
if len(parents) == 0:
650
parent_id = parents[0]
652
rev_tree = self.branch.repository.revision_tree(revision.revision_id)
653
parent_tree = self.branch.repository.revision_tree(parent_id)
655
self.diff.set_diff(rev_tree, parent_tree)
656
if self.config.get_user_option('viz-wrap-diffs') == 'True':
657
self.diff._on_wraplines_toggled(wrap=True)