1
# -*- coding: UTF-8 -*-
4
This module contains the code to manage the branch information window,
5
which contains both the revision graph and details panes.
8
__copyright__ = "Copyright © 2005 Canonical Ltd."
9
__author__ = "Scott James Remnant <scott@ubuntu.com>"
16
from bzrlib.plugins.gtk.window import Window
17
from bzrlib.plugins.gtk.tags import AddTagDialog
18
from bzrlib.plugins.gtk.preferences import PreferencesWindow
19
from bzrlib.plugins.gtk.branchview import TreeView
20
from bzrlib.revision import Revision
21
from bzrlib.config import BranchConfig
22
from bzrlib.config import GlobalConfig
24
class BranchWindow(Window):
27
This object represents and manages a single window containing information
28
for a particular branch.
31
def __init__(self, branch, start, maxnum, parent=None):
32
"""Create a new BranchWindow.
34
:param branch: Branch object for branch to show.
35
:param start: Revision id of top revision.
36
:param maxnum: Maximum number of revisions to display,
40
Window.__init__(self, parent=parent)
41
self.set_border_width(0)
46
self.config = GlobalConfig()
48
if self.config.get_user_option('viz-compact-view') == 'yes':
49
self.compact_view = True
51
self.compact_view = False
53
self.set_title(branch.nick + " - revision history")
55
# Use three-quarters of the screen by default
56
screen = self.get_screen()
57
monitor = screen.get_monitor_geometry(0)
58
width = int(monitor.width * 0.75)
59
height = int(monitor.height * 0.75)
60
self.set_default_size(width, height)
63
icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
66
gtk.accel_map_add_entry("<viz>/Go/Next Revision", gtk.keysyms.Up, gtk.gdk.MOD1_MASK)
67
gtk.accel_map_add_entry("<viz>/Go/Previous Revision", gtk.keysyms.Down, gtk.gdk.MOD1_MASK)
69
self.accel_group = gtk.AccelGroup()
70
self.add_accel_group(self.accel_group)
72
gtk.Action.set_tool_item_type(gtk.MenuToolButton)
74
self.prev_rev_action = gtk.Action("prev-rev", "_Previous Revision", "Go to the previous revision", gtk.STOCK_GO_DOWN)
75
self.prev_rev_action.set_accel_path("<viz>/Go/Previous Revision")
76
self.prev_rev_action.set_accel_group(self.accel_group)
77
self.prev_rev_action.connect("activate", self._back_clicked_cb)
78
self.prev_rev_action.connect_accelerator()
80
self.next_rev_action = gtk.Action("next-rev", "_Next Revision", "Go to the next revision", gtk.STOCK_GO_UP)
81
self.next_rev_action.set_accel_path("<viz>/Go/Next Revision")
82
self.next_rev_action.set_accel_group(self.accel_group)
83
self.next_rev_action.connect("activate", self._fwd_clicked_cb)
84
self.next_rev_action.connect_accelerator()
88
def set_revision(self, revid):
89
self.treeview.set_revision_id(revid)
92
"""Construct the window contents."""
93
vbox = gtk.VBox(spacing=0)
96
self.paned = gtk.VPaned()
97
self.paned.pack1(self.construct_top(), resize=True, shrink=False)
98
self.paned.pack2(self.construct_bottom(), resize=False, shrink=True)
101
vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
102
vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
104
vbox.pack_start(self.paned, expand=True, fill=True)
105
vbox.set_focus_child(self.paned)
109
def construct_menubar(self):
110
menubar = gtk.MenuBar()
112
file_menu = gtk.Menu()
113
file_menuitem = gtk.MenuItem("_File")
114
file_menuitem.set_submenu(file_menu)
116
file_menu_close = gtk.ImageMenuItem(gtk.STOCK_CLOSE, self.accel_group)
117
file_menu_close.connect('activate', lambda x: self.destroy())
119
file_menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accel_group)
120
file_menu_quit.connect('activate', lambda x: gtk.main_quit())
122
if self._parent is not None:
123
file_menu.add(file_menu_close)
124
file_menu.add(file_menu_quit)
126
edit_menu = gtk.Menu()
127
edit_menuitem = gtk.MenuItem("_Edit")
128
edit_menuitem.set_submenu(edit_menu)
130
edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
132
edit_menu_branchopts = gtk.MenuItem("Branch Settings")
133
edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
135
edit_menu_globopts = gtk.MenuItem("Global Settings")
136
edit_menu_globopts.connect('activate', lambda x: PreferencesWindow().show())
138
edit_menu.add(edit_menu_find)
139
edit_menu.add(edit_menu_branchopts)
140
edit_menu.add(edit_menu_globopts)
142
view_menu = gtk.Menu()
143
view_menuitem = gtk.MenuItem("_View")
144
view_menuitem.set_submenu(view_menu)
146
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
147
view_menu_toolbar.set_active(True)
148
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
150
view_menu_compact = gtk.CheckMenuItem("Show Compact Graph")
151
view_menu_compact.set_active(self.compact_view)
152
view_menu_compact.connect('activate', self._brokenlines_toggled_cb)
154
view_menu.add(view_menu_toolbar)
155
view_menu.add(view_menu_compact)
156
view_menu.add(gtk.SeparatorMenuItem())
158
for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
159
col = gtk.CheckMenuItem("Show " + label + " Column")
160
col.set_active(self.treeview.get_property(name + "-column-visible"))
161
col.connect('toggled', self._col_visibility_changed, name)
165
go_menu.set_accel_group(self.accel_group)
166
go_menuitem = gtk.MenuItem("_Go")
167
go_menuitem.set_submenu(go_menu)
169
go_menu_next = self.next_rev_action.create_menu_item()
170
go_menu_prev = self.prev_rev_action.create_menu_item()
172
self.go_menu_tags = gtk.MenuItem("_Tags")
175
go_menu.add(go_menu_next)
176
go_menu.add(go_menu_prev)
177
go_menu.add(gtk.SeparatorMenuItem())
178
go_menu.add(self.go_menu_tags)
180
revision_menu = gtk.Menu()
181
revision_menuitem = gtk.MenuItem("_Revision")
182
revision_menuitem.set_submenu(revision_menu)
184
revision_menu_diff = gtk.MenuItem("View Changes")
185
revision_menu_diff.connect('activate',
186
lambda w: self.treeview.show_diff())
188
revision_menu_tag = gtk.MenuItem("Tag Revision")
189
revision_menu_tag.connect('activate', self._tag_revision_cb)
191
revision_menu.add(revision_menu_tag)
192
revision_menu.add(revision_menu_diff)
194
branch_menu = gtk.Menu()
195
branch_menuitem = gtk.MenuItem("_Branch")
196
branch_menuitem.set_submenu(branch_menu)
198
branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
199
branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
201
help_menu = gtk.Menu()
202
help_menuitem = gtk.MenuItem("_Help")
203
help_menuitem.set_submenu(help_menu)
205
help_about_menuitem = gtk.ImageMenuItem(gtk.STOCK_ABOUT, self.accel_group)
206
help_about_menuitem.connect('activate', self._about_dialog_cb)
208
help_menu.add(help_about_menuitem)
210
menubar.add(file_menuitem)
211
menubar.add(edit_menuitem)
212
menubar.add(view_menuitem)
213
menubar.add(go_menuitem)
214
menubar.add(revision_menuitem)
215
menubar.add(branch_menuitem)
216
menubar.add(help_menuitem)
221
def construct_top(self):
222
"""Construct the top-half of the window."""
223
# FIXME: Make broken_line_length configurable
225
self.treeview = TreeView(self.branch, self.start, self.maxnum, self.compact_view)
227
self.treeview.connect('revision-selected',
228
self._treeselection_changed_cb)
230
self.treeview.connect('tag-added', lambda w, t, r: self._update_tags())
232
for col in ["revno", "date"]:
233
option = self.config.get_user_option(col + '-column-visible')
234
if option is not None:
235
self.treeview.set_property(col + '-column-visible', option == 'True')
239
align = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
240
align.set_padding(5, 0, 0, 0)
241
align.add(self.treeview)
246
def construct_navigation(self):
247
"""Construct the navigation buttons."""
248
self.toolbar = gtk.Toolbar()
249
self.toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ)
251
self.prev_button = self.prev_rev_action.create_tool_item()
252
self.toolbar.insert(self.prev_button, -1)
254
self.next_button = self.next_rev_action.create_tool_item()
255
self.toolbar.insert(self.next_button, -1)
257
self.toolbar.insert(gtk.SeparatorToolItem(), -1)
259
refresh_button = gtk.ToolButton(gtk.STOCK_REFRESH)
260
refresh_button.connect('clicked', self._refresh_clicked)
261
self.toolbar.insert(refresh_button, -1)
263
self.toolbar.show_all()
267
def construct_bottom(self):
268
"""Construct the bottom half of the window."""
269
from bzrlib.plugins.gtk.revisionview import RevisionView
270
self.revisionview = RevisionView(branch=self.branch)
271
(width, height) = self.get_size()
272
self.revisionview.set_size_request(width, int(height / 2.5))
273
self.revisionview.show()
274
self.revisionview.set_show_callback(self._show_clicked_cb)
275
self.revisionview.connect('notify::revision', self._go_clicked_cb)
276
self.treeview.connect('tag-added', lambda w, t, r: self.revisionview.update_tags())
277
return self.revisionview
279
def _tag_selected_cb(self, menuitem, revid):
280
self.treeview.set_revision_id(revid)
282
def _treeselection_changed_cb(self, selection, *args):
283
"""callback for when the treeview changes."""
284
revision = self.treeview.get_revision()
285
parents = self.treeview.get_parents()
286
children = self.treeview.get_children()
288
if revision is not None:
289
prev_menu = gtk.Menu()
291
self.prev_rev_action.set_sensitive(True)
292
for parent_id in parents:
293
parent = self.branch.repository.get_revision(parent_id)
295
str = ' (' + parent.properties['branch-nick'] + ')'
299
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
300
item.connect('activate', self._set_revision_cb, parent_id)
304
self.prev_rev_action.set_sensitive(False)
307
self.prev_button.set_menu(prev_menu)
309
next_menu = gtk.Menu()
310
if len(children) > 0:
311
self.next_rev_action.set_sensitive(True)
312
for child_id in children:
313
child = self.branch.repository.get_revision(child_id)
315
str = ' (' + child.properties['branch-nick'] + ')'
319
item = gtk.MenuItem(child.message.split("\n")[0] + str)
320
item.connect('activate', self._set_revision_cb, child_id)
324
self.next_rev_action.set_sensitive(False)
327
self.next_button.set_menu(next_menu)
329
self.revisionview.set_revision(revision)
330
self.revisionview.set_children(children)
332
def _back_clicked_cb(self, *args):
333
"""Callback for when the back button is clicked."""
336
def _fwd_clicked_cb(self, *args):
337
"""Callback for when the forward button is clicked."""
338
self.treeview.forward()
340
def _go_clicked_cb(self, w, p):
341
"""Callback for when the go button for a parent is clicked."""
342
if self.revisionview.get_revision() is not None:
343
self.treeview.set_revision(self.revisionview.get_revision())
345
def _show_clicked_cb(self, revid, parentid):
346
"""Callback for when the show button for a parent is clicked."""
347
self.treeview.show_diff(revid, parentid)
348
self.treeview.grab_focus()
350
def _set_revision_cb(self, w, revision_id):
351
self.treeview.set_revision_id(revision_id)
353
def _brokenlines_toggled_cb(self, button):
354
self.compact_view = button.get_active()
356
if self.compact_view:
361
self.config.set_user_option('viz-compact-view', option)
362
self.treeview.set_property('compact', self.compact_view)
363
self.treeview.refresh()
365
def _tag_revision_cb(self, w):
367
self.treeview.set_sensitive(False)
368
dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
369
response = dialog.run()
370
if response != gtk.RESPONSE_NONE:
373
if response == gtk.RESPONSE_OK:
374
self.treeview.add_tag(dialog.tagname, dialog._revid)
379
self.treeview.set_sensitive(True)
381
def _about_dialog_cb(self, w):
382
from bzrlib.plugins.gtk.about import AboutDialog
386
def _col_visibility_changed(self, col, property):
387
self.config.set_user_option(property + '-column-visible', col.get_active())
388
self.treeview.set_property(property + '-column-visible', col.get_active())
390
def _toolbar_visibility_changed(self, col):
396
def _show_about_cb(self, w):
397
dialog = AboutDialog()
398
dialog.connect('response', lambda d,r: d.destroy())
401
def _refresh_clicked(self, w):
402
self.treeview.refresh()
404
def _update_tags(self):
407
if self.branch.supports_tags():
408
tags = self.branch.tags.get_tag_dict().items()
411
for tag, revid in tags:
412
tag_item = gtk.MenuItem(tag)
413
tag_item.connect('activate', self._tag_selected_cb, revid)
415
self.go_menu_tags.set_submenu(menu)
417
self.go_menu_tags.set_sensitive(len(tags) != 0)
419
self.go_menu_tags.set_sensitive(False)
421
self.go_menu_tags.show_all()