16
16
from bzrlib.plugins.gtk.window import Window
17
from bzrlib.plugins.gtk import icon_path
17
18
from bzrlib.plugins.gtk.tags import AddTagDialog
18
19
from bzrlib.plugins.gtk.preferences import PreferencesWindow
19
from bzrlib.plugins.gtk.branchview import TreeView
20
from bzrlib.revision import Revision
20
from bzrlib.plugins.gtk.branchview import TreeView, treemodel
21
from bzrlib.revision import Revision, NULL_REVISION
21
22
from bzrlib.config import BranchConfig
22
23
from bzrlib.config import GlobalConfig
28
29
for a particular branch.
31
def __init__(self, branch, start, maxnum, parent=None):
32
def __init__(self, branch, start_revs, maxnum, parent=None):
32
33
"""Create a new BranchWindow.
34
35
:param branch: Branch object for branch to show.
35
:param start: Revision id of top revision.
36
:param start_revs: Revision ids of top revisions.
36
37
:param maxnum: Maximum number of revisions to display,
66
67
gtk.accel_map_add_entry("<viz>/Go/Next Revision", gtk.keysyms.Up, gtk.gdk.MOD1_MASK)
67
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)
69
71
self.accel_group = gtk.AccelGroup()
70
72
self.add_accel_group(self.accel_group)
83
85
self.next_rev_action.connect("activate", self._fwd_clicked_cb)
84
86
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()
88
96
def set_revision(self, revid):
101
109
vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
102
110
vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
103
vbox.pack_start(self.construct_loading_msg(), expand=False, fill=True)
105
112
vbox.pack_start(self.paned, expand=True, fill=True)
106
113
vbox.set_focus_child(self.paned)
144
151
view_menuitem = gtk.MenuItem("_View")
145
152
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())
147
160
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
148
161
view_menu_toolbar.set_active(True)
149
162
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
156
169
view_menu.add(view_menu_compact)
157
170
view_menu.add(gtk.SeparatorMenuItem())
159
for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
160
col = gtk.CheckMenuItem("Show " + label + " Column")
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")]:
161
182
col.set_active(self.treeview.get_property(name + "-column-visible"))
162
183
col.connect('toggled', self._col_visibility_changed, name)
163
184
view_menu.add(col)
170
191
go_menu_next = self.next_rev_action.create_menu_item()
171
192
go_menu_prev = self.prev_rev_action.create_menu_item()
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)
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)
190
200
go_menu.add(go_menu_next)
191
201
go_menu.add(go_menu_prev)
192
202
go_menu.add(gtk.SeparatorMenuItem())
193
go_menu.add(go_menu_tags)
203
go_menu.add(self.go_menu_tags)
195
205
revision_menu = gtk.Menu()
196
206
revision_menuitem = gtk.MenuItem("_Revision")
199
209
revision_menu_diff = gtk.MenuItem("View Changes")
200
210
revision_menu_diff.connect('activate',
201
lambda w: self.treeview.show_diff())
213
revision_menu_compare = gtk.MenuItem("Compare with...")
214
revision_menu_compare.connect('activate',
215
self._compare_with_cb)
203
217
revision_menu_tag = gtk.MenuItem("Tag Revision")
204
218
revision_menu_tag.connect('activate', self._tag_revision_cb)
206
220
revision_menu.add(revision_menu_tag)
207
221
revision_menu.add(revision_menu_diff)
222
revision_menu.add(revision_menu_compare)
209
224
branch_menu = gtk.Menu()
210
225
branch_menuitem = gtk.MenuItem("_Branch")
213
228
branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
214
229
branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
231
help_menu = gtk.Menu()
232
help_menuitem = gtk.MenuItem("_Help")
233
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)
216
240
menubar.add(file_menuitem)
217
241
menubar.add(edit_menuitem)
218
242
menubar.add(view_menuitem)
219
243
menubar.add(go_menuitem)
220
244
menubar.add(revision_menuitem)
221
245
menubar.add(branch_menuitem)
246
menubar.add(help_menuitem)
222
247
menubar.show_all()
226
def construct_loading_msg(self):
227
image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
228
gtk.ICON_SIZE_BUTTON)
231
label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
232
label_loading.set_alignment(0.0, 0.5)
235
self.loading_msg_box = gtk.HBox()
236
self.loading_msg_box.set_spacing(5)
237
self.loading_msg_box.set_border_width(5)
238
self.loading_msg_box.pack_start(image_loading, False, False)
239
self.loading_msg_box.pack_start(label_loading, True, True)
240
self.loading_msg_box.show()
242
return self.loading_msg_box
244
251
def construct_top(self):
245
252
"""Construct the top-half of the window."""
246
253
# FIXME: Make broken_line_length configurable
248
self.treeview = TreeView(self.branch, self.start, self.maxnum, self.compact_view)
255
self.treeview = TreeView(self.branch, self.start_revs, self.maxnum, self.compact_view)
250
257
self.treeview.connect('revision-selected',
251
258
self._treeselection_changed_cb)
259
self.treeview.connect('revision-activated',
260
self._tree_revision_activated)
253
self.treeview.connect('revisions-loaded',
254
lambda x: self.loading_msg_box.hide())
262
self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
256
264
for col in ["revno", "date"]:
257
265
option = self.config.get_user_option(col + '-column-visible')
258
266
if option is not None:
259
267
self.treeview.set_property(col + '-column-visible', option == 'True')
269
self.treeview.set_property(col + '-column-visible', False)
261
271
self.treeview.show()
297
307
self.revisionview.show()
298
308
self.revisionview.set_show_callback(self._show_clicked_cb)
299
309
self.revisionview.connect('notify::revision', self._go_clicked_cb)
310
self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
300
311
return self.revisionview
302
313
def _tag_selected_cb(self, menuitem, revid):
308
319
parents = self.treeview.get_parents()
309
320
children = self.treeview.get_children()
311
if revision is not None:
322
if revision and revision != NULL_REVISION:
312
323
prev_menu = gtk.Menu()
313
324
if len(parents) > 0:
314
325
self.prev_rev_action.set_sensitive(True)
315
326
for parent_id in parents:
316
parent = self.branch.repository.get_revision(parent_id)
318
str = ' (' + parent.properties['branch-nick'] + ')'
327
if parent_id and parent_id != NULL_REVISION:
328
parent = self.branch.repository.get_revision(parent_id)
330
str = ' (' + parent.properties['branch-nick'] + ')'
322
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
323
item.connect('activate', self._set_revision_cb, parent_id)
334
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
335
item.connect('activate', self._set_revision_cb, parent_id)
325
337
prev_menu.show_all()
327
339
self.prev_rev_action.set_sensitive(False)
352
364
self.revisionview.set_revision(revision)
353
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)
355
394
def _back_clicked_cb(self, *args):
356
395
"""Callback for when the back button is clicked."""
368
407
def _show_clicked_cb(self, revid, parentid):
369
408
"""Callback for when the show button for a parent is clicked."""
370
self.treeview.show_diff(revid, parentid)
409
self.show_diff(revid, parentid)
371
410
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)
373
428
def _set_revision_cb(self, w, revision_id):
374
429
self.treeview.set_revision_id(revision_id)
388
443
def _tag_revision_cb(self, w):
390
445
self.treeview.set_sensitive(False)
392
446
dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
393
447
response = dialog.run()
394
448
if response != gtk.RESPONSE_NONE:
397
451
if response == gtk.RESPONSE_OK:
399
self.branch.lock_write()
400
self.branch.tags.set_tag(dialog.tagname, dialog._revid)
452
self.treeview.add_tag(dialog.tagname, dialog._revid)
407
self.branch.lock_read()
408
self.treeview.emit("revision-selected")
409
457
self.treeview.set_sensitive(True)
459
def _about_dialog_cb(self, w):
460
from bzrlib.plugins.gtk.about import AboutDialog
411
464
def _col_visibility_changed(self, col, property):
412
465
self.config.set_user_option(property + '-column-visible', col.get_active())
413
466
self.treeview.set_property(property + '-column-visible', col.get_active())
426
479
def _refresh_clicked(self, w):
427
self.treeview.update()
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)