16
16
from bzrlib.plugins.gtk.window import Window
17
from bzrlib.plugins.gtk import icon_path
18
17
from bzrlib.plugins.gtk.tags import AddTagDialog
19
18
from bzrlib.plugins.gtk.preferences import PreferencesWindow
20
from bzrlib.plugins.gtk.branchview import TreeView, treemodel
21
from bzrlib.revision import Revision, NULL_REVISION
19
from bzrlib.revision import Revision
22
20
from bzrlib.config import BranchConfig
23
21
from bzrlib.config import GlobalConfig
22
from treeview import TreeView
23
from about import AboutDialog
25
25
class BranchWindow(Window):
29
29
for a particular branch.
32
def __init__(self, branch, start_revs, maxnum, parent=None):
32
def __init__(self, branch, start, maxnum, parent=None):
33
33
"""Create a new BranchWindow.
35
35
:param branch: Branch object for branch to show.
36
:param start_revs: Revision ids of top revisions.
36
:param start: Revision id of top revision.
37
37
:param maxnum: Maximum number of revisions to display,
67
67
gtk.accel_map_add_entry("<viz>/Go/Next Revision", gtk.keysyms.Up, gtk.gdk.MOD1_MASK)
68
68
gtk.accel_map_add_entry("<viz>/Go/Previous Revision", gtk.keysyms.Down, gtk.gdk.MOD1_MASK)
69
gtk.accel_map_add_entry("<viz>/View/Refresh", gtk.keysyms.F5, 0)
71
70
self.accel_group = gtk.AccelGroup()
72
71
self.add_accel_group(self.accel_group)
85
84
self.next_rev_action.connect("activate", self._fwd_clicked_cb)
86
85
self.next_rev_action.connect_accelerator()
88
self.refresh_action = gtk.Action("refresh", "_Refresh", "Refresh view", gtk.STOCK_REFRESH)
89
self.refresh_action.set_accel_path("<viz>/View/Refresh")
90
self.refresh_action.set_accel_group(self.accel_group)
91
self.refresh_action.connect("activate", self._refresh_clicked)
92
self.refresh_action.connect_accelerator()
96
89
def set_revision(self, revid):
109
102
vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
110
103
vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
104
vbox.pack_start(self.construct_loading_msg(), expand=False, fill=True)
112
106
vbox.pack_start(self.paned, expand=True, fill=True)
113
107
vbox.set_focus_child(self.paned)
127
121
file_menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accel_group)
128
122
file_menu_quit.connect('activate', lambda x: gtk.main_quit())
130
if self._parent is not None:
131
file_menu.add(file_menu_close)
124
file_menu.add(file_menu_close)
132
125
file_menu.add(file_menu_quit)
134
127
edit_menu = gtk.Menu()
140
133
edit_menu_branchopts = gtk.MenuItem("Branch Settings")
141
134
edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
143
edit_menu_globopts = gtk.MenuItem("Global Settings")
144
edit_menu_globopts.connect('activate', lambda x: PreferencesWindow().show())
136
edit_menu_prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
137
edit_menu_prefs.connect('activate', lambda x: PreferencesWindow().show())
146
139
edit_menu.add(edit_menu_find)
147
140
edit_menu.add(edit_menu_branchopts)
148
edit_menu.add(edit_menu_globopts)
141
edit_menu.add(edit_menu_prefs)
150
143
view_menu = gtk.Menu()
151
144
view_menuitem = gtk.MenuItem("_View")
152
145
view_menuitem.set_submenu(view_menu)
154
view_menu_refresh = self.refresh_action.create_menu_item()
155
view_menu_refresh.connect('activate', self._refresh_clicked)
157
view_menu.add(view_menu_refresh)
158
view_menu.add(gtk.SeparatorMenuItem())
160
147
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
161
148
view_menu_toolbar.set_active(True)
162
149
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
169
156
view_menu.add(view_menu_compact)
170
157
view_menu.add(gtk.SeparatorMenuItem())
172
self.mnu_show_revno_column = gtk.CheckMenuItem("Show Revision _Number Column")
173
self.mnu_show_date_column = gtk.CheckMenuItem("Show _Date Column")
175
# Revision numbers are pointless if there are multiple branches
176
if len(self.start_revs) > 1:
177
self.mnu_show_revno_column.set_sensitive(False)
178
self.treeview.set_property('revno-column-visible', False)
180
for (col, name) in [(self.mnu_show_revno_column, "revno"),
181
(self.mnu_show_date_column, "date")]:
159
for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
160
col = gtk.CheckMenuItem("Show " + label + " Column")
182
161
col.set_active(self.treeview.get_property(name + "-column-visible"))
183
162
col.connect('toggled', self._col_visibility_changed, name)
184
163
view_menu.add(col)
191
170
go_menu_next = self.next_rev_action.create_menu_item()
192
171
go_menu_prev = self.prev_rev_action.create_menu_item()
194
tag_image = gtk.Image()
195
tag_image.set_from_file(icon_path("tag-16.png"))
196
self.go_menu_tags = gtk.ImageMenuItem("_Tags")
197
self.go_menu_tags.set_image(tag_image)
173
tags_menu = gtk.Menu()
174
go_menu_tags = gtk.MenuItem("_Tags")
175
go_menu_tags.set_submenu(tags_menu)
177
if self.branch.supports_tags():
178
tags = self.branch.tags.get_tag_dict().items()
181
for tag, revid in tags:
182
tag_item = gtk.MenuItem(tag)
183
tag_item.connect('activate', self._tag_selected_cb, revid)
184
tags_menu.add(tag_item)
186
go_menu_tags.set_sensitive(len(tags) != 0)
188
go_menu_tags.set_sensitive(False)
200
190
go_menu.add(go_menu_next)
201
191
go_menu.add(go_menu_prev)
202
192
go_menu.add(gtk.SeparatorMenuItem())
203
go_menu.add(self.go_menu_tags)
193
go_menu.add(go_menu_tags)
205
195
revision_menu = gtk.Menu()
206
196
revision_menuitem = gtk.MenuItem("_Revision")
209
199
revision_menu_diff = gtk.MenuItem("View Changes")
210
200
revision_menu_diff.connect('activate',
213
revision_menu_compare = gtk.MenuItem("Compare with...")
214
revision_menu_compare.connect('activate',
215
self._compare_with_cb)
201
lambda w: self.treeview.show_diff())
217
203
revision_menu_tag = gtk.MenuItem("Tag Revision")
218
204
revision_menu_tag.connect('activate', self._tag_revision_cb)
220
206
revision_menu.add(revision_menu_tag)
221
207
revision_menu.add(revision_menu_diff)
222
revision_menu.add(revision_menu_compare)
224
209
branch_menu = gtk.Menu()
225
210
branch_menuitem = gtk.MenuItem("_Branch")
232
217
help_menuitem = gtk.MenuItem("_Help")
233
218
help_menuitem.set_submenu(help_menu)
235
help_about_menuitem = gtk.ImageMenuItem(gtk.STOCK_ABOUT, self.accel_group)
236
help_about_menuitem.connect('activate', self._about_dialog_cb)
238
help_menu.add(help_about_menuitem)
220
help_menu_about = gtk.ImageMenuItem(gtk.STOCK_ABOUT)
221
help_menu_about.connect('activate', self._show_about_cb)
223
help_menu.add(help_menu_about)
240
225
menubar.add(file_menuitem)
241
226
menubar.add(edit_menuitem)
242
227
menubar.add(view_menuitem)
247
232
menubar.show_all()
236
def construct_loading_msg(self):
237
image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
238
gtk.ICON_SIZE_BUTTON)
241
label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
242
label_loading.set_alignment(0.0, 0.5)
245
self.loading_msg_box = gtk.HBox()
246
self.loading_msg_box.set_spacing(5)
247
self.loading_msg_box.set_border_width(5)
248
self.loading_msg_box.pack_start(image_loading, False, False)
249
self.loading_msg_box.pack_start(label_loading, True, True)
250
self.loading_msg_box.show()
252
return self.loading_msg_box
251
254
def construct_top(self):
252
255
"""Construct the top-half of the window."""
253
256
# FIXME: Make broken_line_length configurable
257
if self.compact_view:
255
self.treeview = TreeView(self.branch, self.start_revs, self.maxnum, self.compact_view)
262
self.treeview = TreeView(self.branch, self.start, self.maxnum, brokenlines)
257
264
self.treeview.connect('revision-selected',
258
265
self._treeselection_changed_cb)
259
self.treeview.connect('revision-activated',
260
self._tree_revision_activated)
262
self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
267
self.treeview.connect('revisions-loaded',
268
lambda x: self.loading_msg_box.hide())
264
270
for col in ["revno", "date"]:
265
271
option = self.config.get_user_option(col + '-column-visible')
266
272
if option is not None:
267
273
self.treeview.set_property(col + '-column-visible', option == 'True')
269
self.treeview.set_property(col + '-column-visible', False)
271
275
self.treeview.show()
288
292
self.next_button = self.next_rev_action.create_tool_item()
289
293
self.toolbar.insert(self.next_button, -1)
291
self.toolbar.insert(gtk.SeparatorToolItem(), -1)
293
refresh_button = gtk.ToolButton(gtk.STOCK_REFRESH)
294
refresh_button.connect('clicked', self._refresh_clicked)
295
self.toolbar.insert(refresh_button, -1)
297
295
self.toolbar.show_all()
299
297
return self.toolbar
301
299
def construct_bottom(self):
302
300
"""Construct the bottom half of the window."""
303
301
from bzrlib.plugins.gtk.revisionview import RevisionView
304
self.revisionview = RevisionView(branch=self.branch)
302
self.revisionview = RevisionView(None, tags=[], show_children=True, branch=self.branch)
305
303
(width, height) = self.get_size()
306
304
self.revisionview.set_size_request(width, int(height / 2.5))
307
305
self.revisionview.show()
308
306
self.revisionview.set_show_callback(self._show_clicked_cb)
309
self.revisionview.connect('notify::revision', self._go_clicked_cb)
310
self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
307
self.revisionview.set_go_callback(self._go_clicked_cb)
311
308
return self.revisionview
313
310
def _tag_selected_cb(self, menuitem, revid):
319
316
parents = self.treeview.get_parents()
320
317
children = self.treeview.get_children()
322
if revision and revision != NULL_REVISION:
319
if revision is not None:
323
320
prev_menu = gtk.Menu()
324
321
if len(parents) > 0:
325
322
self.prev_rev_action.set_sensitive(True)
326
323
for parent_id in parents:
327
if parent_id and parent_id != NULL_REVISION:
328
parent = self.branch.repository.get_revision(parent_id)
330
str = ' (' + parent.properties['branch-nick'] + ')'
324
parent = self.branch.repository.get_revision(parent_id)
326
str = ' (' + parent.properties['branch-nick'] + ')'
334
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
335
item.connect('activate', self._set_revision_cb, parent_id)
330
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
331
item.connect('activate', self._set_revision_cb, parent_id)
337
333
prev_menu.show_all()
339
335
self.prev_rev_action.set_sensitive(False)
362
358
self.next_button.set_menu(next_menu)
364
self.revisionview.set_revision(revision)
365
self.revisionview.set_children(children)
367
def _tree_revision_activated(self, widget, path, col):
368
# TODO: more than one parent
369
"""Callback for when a treeview row gets activated."""
370
revision = self.treeview.get_revision()
371
parents = self.treeview.get_parents()
373
if len(parents) == 0:
376
parent_id = parents[0]
378
self.show_diff(revision.revision_id, parent_id)
379
self.treeview.grab_focus()
381
def _menu_diff_cb(self,w):
382
(path, focus) = self.treeview.treeview.get_cursor()
383
revid = self.treeview.model[path][treemodel.REVID]
385
parentids = self.branch.repository.revision_parents(revid)
387
if len(parentids) == 0:
388
parentid = NULL_REVISION
390
parentid = parentids[0]
392
self.show_diff(revid,parentid)
361
if self.branch.supports_tags():
362
tagdict = self.branch.tags.get_reverse_tag_dict()
363
if tagdict.has_key(revision.revision_id):
364
tags = tagdict[revision.revision_id]
365
self.revisionview.set_revision(revision, tags, children)
394
367
def _back_clicked_cb(self, *args):
395
368
"""Callback for when the back button is clicked."""
399
372
"""Callback for when the forward button is clicked."""
400
373
self.treeview.forward()
402
def _go_clicked_cb(self, w, p):
375
def _go_clicked_cb(self, revid):
403
376
"""Callback for when the go button for a parent is clicked."""
404
if self.revisionview.get_revision() is not None:
405
self.treeview.set_revision(self.revisionview.get_revision())
377
self.treeview.set_revision_id(revid)
407
379
def _show_clicked_cb(self, revid, parentid):
408
380
"""Callback for when the show button for a parent is clicked."""
409
self.show_diff(revid, parentid)
381
self.treeview.show_diff(revid, parentid)
410
382
self.treeview.grab_focus()
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"""
416
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
418
rb = RevisionBrowser(self.branch,self)
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)
428
384
def _set_revision_cb(self, w, revision_id):
429
385
self.treeview.set_revision_id(revision_id)
439
395
self.config.set_user_option('viz-compact-view', option)
440
self.treeview.set_property('compact', self.compact_view)
441
self.treeview.refresh()
397
revision = self.treeview.get_revision()
399
self.paned.get_child1().destroy()
400
self.paned.pack1(self.construct_top(), resize=True, shrink=False)
402
gobject.idle_add(self.set_revision, revision.revision_id)
443
404
def _tag_revision_cb(self, w):
445
406
self.treeview.set_sensitive(False)
446
408
dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
447
409
response = dialog.run()
448
410
if response != gtk.RESPONSE_NONE:
451
413
if response == gtk.RESPONSE_OK:
452
self.treeview.add_tag(dialog.tagname, dialog._revid)
415
self.branch.lock_write()
416
self.branch.tags.set_tag(dialog.tagname, dialog._revid)
423
self.branch.lock_read()
424
self.treeview.emit("revision-selected")
457
425
self.treeview.set_sensitive(True)
459
def _about_dialog_cb(self, w):
460
from bzrlib.plugins.gtk.about import AboutDialog
464
427
def _col_visibility_changed(self, col, property):
465
428
self.config.set_user_option(property + '-column-visible', col.get_active())
466
429
self.treeview.set_property(property + '-column-visible', col.get_active())
475
438
dialog = AboutDialog()
476
439
dialog.connect('response', lambda d,r: d.destroy())
479
def _refresh_clicked(self, w):
480
self.treeview.refresh()
482
def _update_tags(self):
485
if self.branch.supports_tags():
486
tags = self.branch.tags.get_tag_dict().items()
489
for tag, revid in tags:
490
tag_image = gtk.Image()
491
tag_image.set_from_file(icon_path('tag-16.png'))
492
tag_item = gtk.ImageMenuItem(tag.replace('_', '__'))
493
tag_item.set_image(tag_image)
494
tag_item.connect('activate', self._tag_selected_cb, revid)
496
self.go_menu_tags.set_submenu(menu)
498
self.go_menu_tags.set_sensitive(len(tags) != 0)
500
self.go_menu_tags.set_sensitive(False)
502
self.go_menu_tags.show_all()
504
def show_diff(self, revid=None, parentid=None):
505
"""Open a new window to show a diff between the given revisions."""
506
from bzrlib.plugins.gtk.diff import DiffWindow
507
window = DiffWindow(parent=self)
510
parentid = NULL_REVISION
512
rev_tree = self.branch.repository.revision_tree(revid)
513
parent_tree = self.branch.repository.revision_tree(parentid)
515
description = revid + " - " + self.branch.nick
516
window.set_diff(description, rev_tree, parent_tree)