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.revision import Revision
20
from bzrlib.config import BranchConfig
21
from bzrlib.config import GlobalConfig
22
from treeview import TreeView
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
self.accel_group = gtk.AccelGroup()
67
self.add_accel_group(self.accel_group)
71
def set_revision(self, revision):
72
self.treeview.set_revision(revision)
75
"""Construct the window contents."""
76
vbox = gtk.VBox(spacing=0)
79
top = self.construct_top()
81
vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
82
vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
83
vbox.pack_start(self.construct_loading_msg(), expand=False, fill=True)
86
paned.pack1(top, resize=True, shrink=False)
87
paned.pack2(self.construct_bottom(), resize=False, shrink=True)
89
vbox.pack_start(paned, expand=True, fill=True)
90
vbox.set_focus_child(paned)
94
def construct_menubar(self):
95
menubar = gtk.MenuBar()
97
file_menu = gtk.Menu()
98
file_menuitem = gtk.MenuItem("_File")
99
file_menuitem.set_submenu(file_menu)
101
file_menu_close = gtk.ImageMenuItem(gtk.STOCK_CLOSE, self.accel_group)
102
file_menu_close.connect('activate', lambda x: self.destroy())
104
file_menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accel_group)
105
file_menu_quit.connect('activate', lambda x: gtk.main_quit())
107
file_menu.add(file_menu_close)
108
file_menu.add(file_menu_quit)
110
edit_menu = gtk.Menu()
111
edit_menuitem = gtk.MenuItem("_Edit")
112
edit_menuitem.set_submenu(edit_menu)
114
edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
116
edit_menu_branchopts = gtk.MenuItem("Branch Settings")
117
edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
119
edit_menu_prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
120
edit_menu_prefs.connect('activate', lambda x: PreferencesWindow().show())
122
edit_menu.add(edit_menu_find)
123
edit_menu.add(edit_menu_branchopts)
124
edit_menu.add(edit_menu_prefs)
126
view_menu = gtk.Menu()
127
view_menuitem = gtk.MenuItem("_View")
128
view_menuitem.set_submenu(view_menu)
130
view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
131
view_menu_toolbar.set_active(True)
132
view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
134
view_menu.add(view_menu_toolbar)
135
view_menu.add(gtk.SeparatorMenuItem())
137
for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
138
col = gtk.CheckMenuItem("Show " + label + " Column")
139
col.set_active(self.treeview.get_property(name + "-column-visible"))
140
col.connect('toggled', self._col_visibility_changed, name)
144
go_menuitem = gtk.MenuItem("_Go")
145
go_menuitem.set_submenu(go_menu)
147
go_menu_back = gtk.ImageMenuItem(gtk.STOCK_GO_DOWN)
148
go_menu_back.connect("activate", self._back_clicked_cb)
150
go_menu_forward = gtk.ImageMenuItem(gtk.STOCK_GO_UP)
151
go_menu_forward.connect("activate", self._fwd_clicked_cb)
153
tags_menu = gtk.Menu()
154
go_menu_tags = gtk.MenuItem("_Tags")
155
go_menu_tags.set_submenu(tags_menu)
157
if self.branch.supports_tags():
158
for (tag, revid) in self.branch.tags.get_tag_dict().items():
159
tag_item = gtk.MenuItem(tag)
160
tag_item.connect('activate', self._tag_selected_cb, revid)
161
tags_menu.add(tag_item)
163
go_menu.add(go_menu_back)
164
go_menu.add(go_menu_forward)
165
go_menu.add(gtk.SeparatorMenuItem())
166
go_menu.add(go_menu_tags)
168
revision_menu = gtk.Menu()
169
revision_menuitem = gtk.MenuItem("_Revision")
170
revision_menuitem.set_submenu(revision_menu)
172
revision_menu_diff = gtk.MenuItem("View Changes")
173
revision_menu_diff.connect('activate',
174
lambda w: self.treeview.show_diff())
176
revision_menu_tag = gtk.MenuItem("Tag Revision")
177
revision_menu_tag.connect('activate', self._tag_revision_cb)
179
revision_menu.add(revision_menu_tag)
180
revision_menu.add(revision_menu_diff)
182
branch_menu = gtk.Menu()
183
branch_menuitem = gtk.MenuItem("_Branch")
184
branch_menuitem.set_submenu(branch_menu)
186
branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
187
branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
189
menubar.add(file_menuitem)
190
menubar.add(edit_menuitem)
191
menubar.add(view_menuitem)
192
menubar.add(go_menuitem)
193
menubar.add(revision_menuitem)
194
menubar.add(branch_menuitem)
199
def construct_loading_msg(self):
200
image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
201
gtk.ICON_SIZE_BUTTON)
204
label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
205
label_loading.set_alignment(0.0, 0.5)
208
self.loading_msg_box = gtk.HBox()
209
self.loading_msg_box.set_spacing(5)
210
self.loading_msg_box.set_border_width(5)
211
self.loading_msg_box.pack_start(image_loading, False, False)
212
self.loading_msg_box.pack_start(label_loading, True, True)
213
self.loading_msg_box.show()
215
return self.loading_msg_box
217
def construct_top(self):
218
"""Construct the top-half of the window."""
219
# FIXME: Make broken_line_length configurable
220
if self.compact_view:
225
self.treeview = TreeView(self.branch, self.start, self.maxnum, brokenlines)
227
self.treeview.connect("revision-selected",
228
self._treeselection_changed_cb)
230
self.treeview.connect('revisions-loaded',
231
lambda x: self.loading_msg_box.hide())
237
def construct_navigation(self):
238
"""Construct the navigation buttons."""
239
self.toolbar = gtk.Toolbar()
240
self.toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ)
242
self.back_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_DOWN)
243
self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
245
self.back_button.connect("clicked", self._back_clicked_cb)
246
self.toolbar.insert(self.back_button, -1)
248
self.fwd_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_UP)
249
self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
251
self.fwd_button.connect("clicked", self._fwd_clicked_cb)
252
self.toolbar.insert(self.fwd_button, -1)
254
self.toolbar.insert(gtk.SeparatorToolItem(), -1)
256
brokenlines_button = gtk.ToggleToolButton()
257
brokenlines_button.set_label("Compact View")
258
brokenlines_button.set_active(self.compact_view)
259
brokenlines_button.set_is_important(True)
260
brokenlines_button.connect('toggled', self._brokenlines_toggled_cb)
261
self.toolbar.insert(brokenlines_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(None, tags=[], show_children=True, 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.set_go_callback(self._go_clicked_cb)
276
return self.revisionview
278
def _tag_selected_cb(self, menuitem, revid):
279
self.treeview.set_revision_id(revid)
281
def _treeselection_changed_cb(self, selection, *args):
282
"""callback for when the treeview changes."""
283
revision = self.treeview.get_revision()
284
parents = self.treeview.get_parents()
285
children = self.treeview.get_children()
287
if revision is not None:
288
back_menu = gtk.Menu()
290
self.back_button.set_sensitive(True)
291
for parent_id in parents:
292
parent = self.branch.repository.get_revision(parent_id)
294
str = ' (' + parent.properties['branch-nick'] + ')'
298
item = gtk.MenuItem(parent.message.split("\n")[0] + str)
299
item.connect('activate', self._set_revision_cb, parent_id)
303
self.back_button.set_sensitive(False)
306
self.back_button.set_menu(back_menu)
308
fwd_menu = gtk.Menu()
309
if len(children) > 0:
310
self.fwd_button.set_sensitive(True)
311
for child_id in children:
312
child = self.branch.repository.get_revision(child_id)
314
str = ' (' + child.properties['branch-nick'] + ')'
318
item = gtk.MenuItem(child.message.split("\n")[0] + str)
319
item.connect('activate', self._set_revision_cb, child_id)
323
self.fwd_button.set_sensitive(False)
326
self.fwd_button.set_menu(fwd_menu)
329
if self.branch.supports_tags():
330
tagdict = self.branch.tags.get_reverse_tag_dict()
331
if tagdict.has_key(revision.revision_id):
332
tags = tagdict[revision.revision_id]
333
self.revisionview.set_revision(revision, tags, children)
335
def _back_clicked_cb(self, *args):
336
"""Callback for when the back button is clicked."""
339
def _fwd_clicked_cb(self, *args):
340
"""Callback for when the forward button is clicked."""
341
self.treeview.forward()
343
def _go_clicked_cb(self, revid):
344
"""Callback for when the go button for a parent is clicked."""
345
self.treeview.set_revision_id(revid)
347
def _show_clicked_cb(self, revid, parentid):
348
"""Callback for when the show button for a parent is clicked."""
349
self.treeview.show_diff(revid, parentid)
350
self.treeview.grab_focus()
352
def _set_revision_cb(self, w, revision_id):
353
self.treeview.set_revision_id(revision_id)
355
def _brokenlines_toggled_cb(self, button):
356
self.compact_view = button.get_active()
358
if self.compact_view:
363
self.config.set_user_option('viz-compact-view', option)
365
revision = self.treeview.get_revision()
367
self.treeview.destroy()
368
self.paned.pack1(self.construct_top(), resize=True, shrink=False)
370
gobject.idle_add(self.set_revision, revision.revision_id)
372
def _tag_revision_cb(self, w):
373
dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
374
response = dialog.run()
375
if response != gtk.RESPONSE_NONE:
378
if response == gtk.RESPONSE_OK:
380
self.branch.lock_write()
381
self.branch.tags.set_tag(dialog.tagname, dialog._revid)
387
def _col_visibility_changed(self, col, property):
388
self.treeview.set_property(property + '-column-visible', col.get_active())
390
def _toolbar_visibility_changed(self, col):