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)
151
145
view_menuitem = gtk.MenuItem("_View")
152
146
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
148
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
161
149
view_menu_toolbar.set_active(True)
162
150
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
169
157
view_menu.add(view_menu_compact)
170
158
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")]:
160
for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
161
col = gtk.CheckMenuItem("Show " + label + " Column")
182
162
col.set_active(self.treeview.get_property(name + "-column-visible"))
183
163
col.connect('toggled', self._col_visibility_changed, name)
184
164
view_menu.add(col)
191
171
go_menu_next = self.next_rev_action.create_menu_item()
192
172
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)
174
tags_menu = gtk.Menu()
175
go_menu_tags = gtk.MenuItem("_Tags")
176
go_menu_tags.set_submenu(tags_menu)
178
if self.branch.supports_tags():
179
tags = self.branch.tags.get_tag_dict().items()
182
for tag, revid in tags:
183
tag_item = gtk.MenuItem(tag)
184
tag_item.connect('activate', self._tag_selected_cb, revid)
185
tags_menu.add(tag_item)
187
go_menu_tags.set_sensitive(len(tags) != 0)
189
go_menu_tags.set_sensitive(False)
200
191
go_menu.add(go_menu_next)
201
192
go_menu.add(go_menu_prev)
202
193
go_menu.add(gtk.SeparatorMenuItem())
203
go_menu.add(self.go_menu_tags)
194
go_menu.add(go_menu_tags)
205
196
revision_menu = gtk.Menu()
206
197
revision_menuitem = gtk.MenuItem("_Revision")
209
200
revision_menu_diff = gtk.MenuItem("View Changes")
210
201
revision_menu_diff.connect('activate',
213
revision_menu_compare = gtk.MenuItem("Compare with...")
214
revision_menu_compare.connect('activate',
215
self._compare_with_cb)
202
lambda w: self.treeview.show_diff())
217
204
revision_menu_tag = gtk.MenuItem("Tag Revision")
218
205
revision_menu_tag.connect('activate', self._tag_revision_cb)
220
207
revision_menu.add(revision_menu_tag)
221
208
revision_menu.add(revision_menu_diff)
222
revision_menu.add(revision_menu_compare)
224
210
branch_menu = gtk.Menu()
225
211
branch_menuitem = gtk.MenuItem("_Branch")
228
214
branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
229
215
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)
240
217
menubar.add(file_menuitem)
241
218
menubar.add(edit_menuitem)
242
219
menubar.add(view_menuitem)
243
220
menubar.add(go_menuitem)
244
221
menubar.add(revision_menuitem)
245
222
menubar.add(branch_menuitem)
246
menubar.add(help_menuitem)
247
223
menubar.show_all()
227
def construct_loading_msg(self):
228
image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
229
gtk.ICON_SIZE_BUTTON)
232
label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
233
label_loading.set_alignment(0.0, 0.5)
236
self.loading_msg_box = gtk.HBox()
237
self.loading_msg_box.set_spacing(5)
238
self.loading_msg_box.set_border_width(5)
239
self.loading_msg_box.pack_start(image_loading, False, False)
240
self.loading_msg_box.pack_start(label_loading, True, True)
241
self.loading_msg_box.show()
243
return self.loading_msg_box
251
245
def construct_top(self):
252
246
"""Construct the top-half of the window."""
253
247
# FIXME: Make broken_line_length configurable
255
self.treeview = TreeView(self.branch, self.start_revs, self.maxnum, self.compact_view)
249
self.treeview = TreeView(self.branch, self.start, self.maxnum, self.compact_view)
257
251
self.treeview.connect('revision-selected',
258
252
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())
254
self.treeview.connect('revisions-loaded',
255
lambda x: self.loading_msg_box.hide())
264
257
for col in ["revno", "date"]:
265
258
option = self.config.get_user_option(col + '-column-visible')
266
259
if option is not None:
267
260
self.treeview.set_property(col + '-column-visible', option == 'True')
269
self.treeview.set_property(col + '-column-visible', False)
271
262
self.treeview.show()
301
292
def construct_bottom(self):
302
293
"""Construct the bottom half of the window."""
303
294
from bzrlib.plugins.gtk.revisionview import RevisionView
304
self.revisionview = RevisionView(branch=self.branch)
295
self.revisionview = RevisionView(None, tags=[], show_children=True, branch=self.branch)
305
296
(width, height) = self.get_size()
306
297
self.revisionview.set_size_request(width, int(height / 2.5))
307
298
self.revisionview.show()
308
299
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())
300
self.revisionview.set_go_callback(self._go_clicked_cb)
311
301
return self.revisionview
313
303
def _tag_selected_cb(self, menuitem, revid):
319
309
parents = self.treeview.get_parents()
320
310
children = self.treeview.get_children()
322
if revision and revision != NULL_REVISION:
312
if revision is not None:
323
313
prev_menu = gtk.Menu()
324
314
if len(parents) > 0:
325
315
self.prev_rev_action.set_sensitive(True)
326
316
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'] + ')'
317
parent = self.branch.repository.get_revision(parent_id)
319
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)
323
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
324
item.connect('activate', self._set_revision_cb, parent_id)
337
326
prev_menu.show_all()
339
328
self.prev_rev_action.set_sensitive(False)
362
351
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)
354
if self.branch.supports_tags():
355
tagdict = self.branch.tags.get_reverse_tag_dict()
356
if tagdict.has_key(revision.revision_id):
357
tags = tagdict[revision.revision_id]
358
self.revisionview.set_revision(revision, tags, children)
394
360
def _back_clicked_cb(self, *args):
395
361
"""Callback for when the back button is clicked."""
399
365
"""Callback for when the forward button is clicked."""
400
366
self.treeview.forward()
402
def _go_clicked_cb(self, w, p):
368
def _go_clicked_cb(self, revid):
403
369
"""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())
370
self.treeview.set_revision_id(revid)
407
372
def _show_clicked_cb(self, revid, parentid):
408
373
"""Callback for when the show button for a parent is clicked."""
409
self.show_diff(revid, parentid)
374
self.treeview.show_diff(revid, parentid)
410
375
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
377
def _set_revision_cb(self, w, revision_id):
429
378
self.treeview.set_revision_id(revision_id)
443
392
def _tag_revision_cb(self, w):
445
394
self.treeview.set_sensitive(False)
446
396
dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
447
397
response = dialog.run()
448
398
if response != gtk.RESPONSE_NONE:
451
401
if response == gtk.RESPONSE_OK:
452
self.treeview.add_tag(dialog.tagname, dialog._revid)
403
self.branch.lock_write()
404
self.branch.tags.set_tag(dialog.tagname, dialog._revid)
411
self.branch.lock_read()
412
self.treeview.emit("revision-selected")
457
413
self.treeview.set_sensitive(True)
459
def _about_dialog_cb(self, w):
460
from bzrlib.plugins.gtk.about import AboutDialog
464
415
def _col_visibility_changed(self, col, property):
465
416
self.config.set_user_option(property + '-column-visible', col.get_active())
466
417
self.treeview.set_property(property + '-column-visible', col.get_active())
479
430
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)
431
self.treeview.update()