/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
1 by Scott James Remnant
Commit the first version of bzrk.
1
# -*- coding: UTF-8 -*-
2
"""Branch window.
3
4
This module contains the code to manage the branch information window,
5
which contains both the revision graph and details panes.
6
"""
7
8
__copyright__ = "Copyright © 2005 Canonical Ltd."
9
__author__    = "Scott James Remnant <scott@ubuntu.com>"
10
11
12
import gtk
13
import gobject
14
import pango
15
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
16
from bzrlib.plugins.gtk.window import Window
365 by Daniel Schierbeck
Fixed locks and made tagging work.
17
from bzrlib.plugins.gtk.tags import AddTagDialog
338 by Daniel Schierbeck
Added Preferences menu item.
18
from bzrlib.plugins.gtk.preferences import PreferencesWindow
352.1.1 by Daniel Schierbeck
Added dropdown menu to Back button.
19
from bzrlib.revision import Revision
361 by Daniel Schierbeck
Added branch settings menu item.
20
from bzrlib.config import BranchConfig
333 by Daniel Schierbeck
Removed unnecessary imports.
21
from treeview import TreeView
1 by Scott James Remnant
Commit the first version of bzrk.
22
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
23
class BranchWindow(Window):
1 by Scott James Remnant
Commit the first version of bzrk.
24
    """Branch window.
25
26
    This object represents and manages a single window containing information
27
    for a particular branch.
28
    """
29
315 by Daniel Schierbeck
Removed BranchWindow.set_branch(), used constructor instead.
30
    def __init__(self, branch, start, maxnum, parent=None):
322 by Jelmer Vernooij
Add docstrings.
31
        """Create a new BranchWindow.
32
33
        :param branch: Branch object for branch to show.
34
        :param start: Revision id of top revision.
35
        :param maxnum: Maximum number of revisions to display, 
36
                       None for no limit.
37
        """
38
298.2.1 by Daniel Schierbeck
Refactored the GTK window code, creating a single base window class that handles keyboard events.
39
        Window.__init__(self, parent=parent)
1 by Scott James Remnant
Commit the first version of bzrk.
40
        self.set_border_width(0)
315 by Daniel Schierbeck
Removed BranchWindow.set_branch(), used constructor instead.
41
42
        self.branch = branch
43
        self.start  = start
44
        self.maxnum = maxnum
45
46
        self.set_title(branch.nick + " - revision history")
1 by Scott James Remnant
Commit the first version of bzrk.
47
48
        # Use three-quarters of the screen by default
49
        screen = self.get_screen()
4 by Scott James Remnant
Use the size of the first monitor rather than the entire screen
50
        monitor = screen.get_monitor_geometry(0)
51
        width = int(monitor.width * 0.75)
52
        height = int(monitor.height * 0.75)
1 by Scott James Remnant
Commit the first version of bzrk.
53
        self.set_default_size(width, height)
54
55
        # FIXME AndyFitz!
56
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
57
        self.set_icon(icon)
58
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
59
        self.accel_group = gtk.AccelGroup()
60
        self.add_accel_group(self.accel_group)
61
1 by Scott James Remnant
Commit the first version of bzrk.
62
        self.construct()
63
64
    def construct(self):
65
        """Construct the window contents."""
331 by Daniel Schierbeck
Added basic menu bar.
66
        vbox = gtk.VBox(spacing=0)
44 by David Allouche
reorganise branch window
67
        self.add(vbox)
68
358 by Daniel Schierbeck
Generalized the hiding/showing code.
69
        top = self.construct_top()
70
331 by Daniel Schierbeck
Added basic menu bar.
71
        vbox.pack_start(self.construct_menubar(), expand=False, fill=True)
44 by David Allouche
reorganise branch window
72
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
73
        vbox.pack_start(self.construct_loading_msg(), expand=False, fill=True)
74
        
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
75
        paned = gtk.VPaned()
358 by Daniel Schierbeck
Generalized the hiding/showing code.
76
        paned.pack1(top, resize=True, shrink=False)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
77
        paned.pack2(self.construct_bottom(), resize=False, shrink=True)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
78
        paned.show()
44 by David Allouche
reorganise branch window
79
        vbox.pack_start(paned, expand=True, fill=True)
80
        vbox.set_focus_child(paned)
81
82
        vbox.show()
331 by Daniel Schierbeck
Added basic menu bar.
83
84
    def construct_menubar(self):
85
        menubar = gtk.MenuBar()
86
87
        file_menu = gtk.Menu()
334 by Daniel Schierbeck
Added icons to menus.
88
        file_menuitem = gtk.MenuItem("_File")
331 by Daniel Schierbeck
Added basic menu bar.
89
        file_menuitem.set_submenu(file_menu)
90
362 by Daniel Schierbeck
Added accel group to File -> Close menu item.
91
        file_menu_close = gtk.ImageMenuItem(gtk.STOCK_CLOSE, self.accel_group)
331 by Daniel Schierbeck
Added basic menu bar.
92
        file_menu_close.connect('activate', lambda x: self.destroy())
93
        
363 by Daniel Schierbeck
Added File -> Quit menu item.
94
        file_menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accel_group)
95
        file_menu_quit.connect('activate', lambda x: gtk.main_quit())
96
        
331 by Daniel Schierbeck
Added basic menu bar.
97
        file_menu.add(file_menu_close)
363 by Daniel Schierbeck
Added File -> Quit menu item.
98
        file_menu.add(file_menu_quit)
331 by Daniel Schierbeck
Added basic menu bar.
99
338 by Daniel Schierbeck
Added Preferences menu item.
100
        edit_menu = gtk.Menu()
101
        edit_menuitem = gtk.MenuItem("_Edit")
102
        edit_menuitem.set_submenu(edit_menu)
103
340 by Daniel Schierbeck
Added edit->find menu item stub.
104
        edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
105
361 by Daniel Schierbeck
Added branch settings menu item.
106
        edit_menu_branchopts = gtk.MenuItem("Branch Settings")
107
        edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
108
338 by Daniel Schierbeck
Added Preferences menu item.
109
        edit_menu_prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
361 by Daniel Schierbeck
Added branch settings menu item.
110
        edit_menu_prefs.connect('activate', lambda x: PreferencesWindow().show())
338 by Daniel Schierbeck
Added Preferences menu item.
111
340 by Daniel Schierbeck
Added edit->find menu item stub.
112
        edit_menu.add(edit_menu_find)
361 by Daniel Schierbeck
Added branch settings menu item.
113
        edit_menu.add(edit_menu_branchopts)
338 by Daniel Schierbeck
Added Preferences menu item.
114
        edit_menu.add(edit_menu_prefs)
115
348 by Daniel Schierbeck
Added toggle item for revision number column.
116
        view_menu = gtk.Menu()
117
        view_menuitem = gtk.MenuItem("_View")
118
        view_menuitem.set_submenu(view_menu)
119
351 by Daniel Schierbeck
Added option to hide the toolbar.
120
        view_menu_toolbar = gtk.CheckMenuItem("Show Toolbar")
121
        view_menu_toolbar.set_active(True)
122
        view_menu_toolbar.connect('toggled', self._toolbar_visibility_changed)
123
124
        view_menu.add(view_menu_toolbar)
125
        view_menu.add(gtk.SeparatorMenuItem())
358 by Daniel Schierbeck
Generalized the hiding/showing code.
126
127
        for (label, name) in [("Revision _Number", "revno"), ("_Date", "date")]:
128
            col = gtk.CheckMenuItem("Show " + label + " Column")
129
            col.set_active(self.treeview.get_property(name + "-column-visible"))
130
            col.connect('toggled', self._col_visibility_changed, name)
131
            view_menu.add(col)
348 by Daniel Schierbeck
Added toggle item for revision number column.
132
331 by Daniel Schierbeck
Added basic menu bar.
133
        go_menu = gtk.Menu()
334 by Daniel Schierbeck
Added icons to menus.
134
        go_menuitem = gtk.MenuItem("_Go")
331 by Daniel Schierbeck
Added basic menu bar.
135
        go_menuitem.set_submenu(go_menu)
136
        
354 by Daniel Schierbeck
Replaced forward and backward buttons with up and down.
137
        go_menu_back = gtk.ImageMenuItem(gtk.STOCK_GO_DOWN)
334 by Daniel Schierbeck
Added icons to menus.
138
        go_menu_back.connect("activate", self._back_clicked_cb)
139
354 by Daniel Schierbeck
Replaced forward and backward buttons with up and down.
140
        go_menu_forward = gtk.ImageMenuItem(gtk.STOCK_GO_UP)
334 by Daniel Schierbeck
Added icons to menus.
141
        go_menu_forward.connect("activate", self._fwd_clicked_cb)
331 by Daniel Schierbeck
Added basic menu bar.
142
332 by Daniel Schierbeck
Made tag selection work.
143
        tags_menu = gtk.Menu()
334 by Daniel Schierbeck
Added icons to menus.
144
        go_menu_tags = gtk.MenuItem("_Tags")
145
        go_menu_tags.set_submenu(tags_menu)
332 by Daniel Schierbeck
Made tag selection work.
146
147
        for (tag, revid) in self.branch.tags.get_tag_dict().items():
148
            tag_item = gtk.MenuItem(tag)
149
            tag_item.connect('activate', self._tag_selected_cb, revid)
150
            tags_menu.add(tag_item)
151
334 by Daniel Schierbeck
Added icons to menus.
152
        go_menu.add(go_menu_back)
153
        go_menu.add(go_menu_forward)
154
        go_menu.add(gtk.SeparatorMenuItem())
155
        go_menu.add(go_menu_tags)
156
335 by Daniel Schierbeck
Added Revision menu.
157
        revision_menu = gtk.Menu()
158
        revision_menuitem = gtk.MenuItem("_Revision")
159
        revision_menuitem.set_submenu(revision_menu)
160
364 by Daniel Schierbeck
Simplified TreeView.show_diff() and made the Revision -> View Changes menu item work.
161
        revision_menu_diff = gtk.MenuItem("View Changes")
162
        revision_menu_diff.connect('activate', 
163
                lambda w: self.treeview.show_diff())
164
365 by Daniel Schierbeck
Fixed locks and made tagging work.
165
        revision_menu_tag = gtk.MenuItem("Tag Revision")
166
        revision_menu_tag.connect('activate', self._tag_revision_cb)
167
168
        revision_menu.add(revision_menu_tag)
364 by Daniel Schierbeck
Simplified TreeView.show_diff() and made the Revision -> View Changes menu item work.
169
        revision_menu.add(revision_menu_diff)
335 by Daniel Schierbeck
Added Revision menu.
170
334 by Daniel Schierbeck
Added icons to menus.
171
        branch_menu = gtk.Menu()
172
        branch_menuitem = gtk.MenuItem("_Branch")
173
        branch_menuitem.set_submenu(branch_menu)
174
336 by Daniel Schierbeck
Changed wording to comply with HIG guidelines.
175
        branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
176
        branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
334 by Daniel Schierbeck
Added icons to menus.
177
       
331 by Daniel Schierbeck
Added basic menu bar.
178
        menubar.add(file_menuitem)
338 by Daniel Schierbeck
Added Preferences menu item.
179
        menubar.add(edit_menuitem)
348 by Daniel Schierbeck
Added toggle item for revision number column.
180
        menubar.add(view_menuitem)
331 by Daniel Schierbeck
Added basic menu bar.
181
        menubar.add(go_menuitem)
335 by Daniel Schierbeck
Added Revision menu.
182
        menubar.add(revision_menuitem)
331 by Daniel Schierbeck
Added basic menu bar.
183
        menubar.add(branch_menuitem)
184
        menubar.show_all()
185
186
        return menubar
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
187
    
188
    def construct_loading_msg(self):
189
        image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
190
                                                 gtk.ICON_SIZE_BUTTON)
191
        image_loading.show()
192
        
193
        label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
331 by Daniel Schierbeck
Added basic menu bar.
194
        label_loading.set_alignment(0.0, 0.5)  
280.2.1 by Gary van der Merwe
Add a message to the viz window to indicate that graph is still loading.
195
        label_loading.show()
196
        
197
        self.loading_msg_box = gtk.HBox()
198
        self.loading_msg_box.set_spacing(5)
199
        self.loading_msg_box.set_border_width(5)        
200
        self.loading_msg_box.pack_start(image_loading, False, False)
201
        self.loading_msg_box.pack_start(label_loading, True, True)
202
        self.loading_msg_box.show()
203
        
204
        return self.loading_msg_box
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
205
206
    def construct_top(self):
207
        """Construct the top-half of the window."""
329 by Jelmer Vernooij
Make broken_line_length setting from higher up.
208
        # FIXME: Make broken_line_length configurable
209
        self.treeview = TreeView(self.branch, self.start, self.maxnum, 32)
315 by Daniel Schierbeck
Removed BranchWindow.set_branch(), used constructor instead.
210
310 by Daniel Schierbeck
Moved to using custom signal for handling revision selections.
211
        self.treeview.connect("revision-selected",
303 by Daniel Schierbeck
Made basic signaling work.
212
                self._treeselection_changed_cb)
213
307 by Daniel Schierbeck
Made load notification work again.
214
        self.treeview.connect('revisions-loaded', 
215
                lambda x: self.loading_msg_box.hide())
216
1 by Scott James Remnant
Commit the first version of bzrk.
217
        self.treeview.show()
218
303 by Daniel Schierbeck
Made basic signaling work.
219
        return self.treeview
44 by David Allouche
reorganise branch window
220
221
    def construct_navigation(self):
222
        """Construct the navigation buttons."""
325 by Daniel Schierbeck
Switched to using a real toolbar for the viz navigation.
223
        self.toolbar = gtk.Toolbar()
224
        self.toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
225
354 by Daniel Schierbeck
Replaced forward and backward buttons with up and down.
226
        self.back_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_DOWN)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
227
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
228
                                         0, 0)
229
        self.back_button.connect("clicked", self._back_clicked_cb)
325 by Daniel Schierbeck
Switched to using a real toolbar for the viz navigation.
230
        self.toolbar.insert(self.back_button, -1)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
231
        self.back_button.show()
232
354 by Daniel Schierbeck
Replaced forward and backward buttons with up and down.
233
        self.fwd_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_UP)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
234
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
235
                                        0, 0)
236
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
325 by Daniel Schierbeck
Switched to using a real toolbar for the viz navigation.
237
        self.toolbar.insert(self.fwd_button, -1)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
238
        self.fwd_button.show()
239
325 by Daniel Schierbeck
Switched to using a real toolbar for the viz navigation.
240
        self.toolbar.show()
241
242
        return self.toolbar
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
243
244
    def construct_bottom(self):
245
        """Construct the bottom half of the window."""
330.3.1 by Daniel Schierbeck
Renamed logview 'revisionview'.
246
        from bzrlib.plugins.gtk.revisionview import RevisionView
247
        self.revisionview = RevisionView(None, tags=[], show_children=True, branch=self.branch)
44 by David Allouche
reorganise branch window
248
        (width, height) = self.get_size()
330.3.1 by Daniel Schierbeck
Renamed logview 'revisionview'.
249
        self.revisionview.set_size_request(width, int(height / 2.5))
250
        self.revisionview.show()
251
        self.revisionview.set_show_callback(self._show_clicked_cb)
252
        self.revisionview.set_go_callback(self._go_clicked_cb)
253
        return self.revisionview
332 by Daniel Schierbeck
Made tag selection work.
254
255
    def _tag_selected_cb(self, menuitem, revid):
356 by Daniel Schierbeck
Made revision a property on TreeView.
256
        self.treeview.set_revision_id(revid)
341 by Daniel Schierbeck
Merged with trunk.
257
280.1.2 by Daniel Schierbeck
Switched to handle the 'changed' signal from the treeview's treeselection instead of the 'cursor-changed' signal from the treeview itself, allowing more flexibility (particularly the ability to handle programmatic selections)
258
    def _treeselection_changed_cb(self, selection, *args):
303 by Daniel Schierbeck
Made basic signaling work.
259
        """callback for when the treeview changes."""
260
        revision = self.treeview.get_revision()
261
        parents  = self.treeview.get_parents()
262
        children = self.treeview.get_children()
263
264
        if revision is not None:
352.1.1 by Daniel Schierbeck
Added dropdown menu to Back button.
265
            back_menu = gtk.Menu()
266
            if len(parents) > 0:
267
                self.back_button.set_sensitive(True)
268
                for parent_id in parents:
269
                    parent = self.branch.repository.get_revision(parent_id)
355 by Daniel Schierbeck
Appended branch nick to parent and child popup menus.
270
                    try:
271
                        str = ' (' + parent.properties['branch-nick'] + ')'
272
                    except KeyError:
273
                        str = ""
274
275
                    item = gtk.MenuItem(parent.message.split("\n")[0] + str)
352.1.1 by Daniel Schierbeck
Added dropdown menu to Back button.
276
                    item.connect('activate', self._set_revision_cb, parent_id)
277
                    back_menu.add(item)
278
                back_menu.show_all()
279
            else:
280
                self.back_button.set_sensitive(False)
281
                back_menu.hide()
282
283
            self.back_button.set_menu(back_menu)
284
352.1.2 by Daniel Schierbeck
Added dropdown menu to Forward button.
285
            fwd_menu = gtk.Menu()
286
            if len(children) > 0:
287
                self.fwd_button.set_sensitive(True)
288
                for child_id in children:
289
                    child = self.branch.repository.get_revision(child_id)
355 by Daniel Schierbeck
Appended branch nick to parent and child popup menus.
290
                    try:
291
                        str = ' (' + child.properties['branch-nick'] + ')'
292
                    except KeyError:
293
                        str = ""
294
295
                    item = gtk.MenuItem(child.message.split("\n")[0] + str)
352.1.2 by Daniel Schierbeck
Added dropdown menu to Forward button.
296
                    item.connect('activate', self._set_revision_cb, child_id)
297
                    fwd_menu.add(item)
298
                fwd_menu.show_all()
299
            else:
300
                self.fwd_button.set_sensitive(False)
301
                fwd_menu.hide()
302
303
            self.fwd_button.set_menu(fwd_menu)
304
280.1.2 by Daniel Schierbeck
Switched to handle the 'changed' signal from the treeview's treeselection instead of the 'cursor-changed' signal from the treeview itself, allowing more flexibility (particularly the ability to handle programmatic selections)
305
            tags = []
306
            if self.branch.supports_tags():
307
                tagdict = self.branch.tags.get_reverse_tag_dict()
308
                if tagdict.has_key(revision.revision_id):
309
                    tags = tagdict[revision.revision_id]
330.3.1 by Daniel Schierbeck
Renamed logview 'revisionview'.
310
            self.revisionview.set_revision(revision, tags, children)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
311
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
312
    def _back_clicked_cb(self, *args):
313
        """Callback for when the back button is clicked."""
304 by Daniel Schierbeck
Made forward/back buttons work again.
314
        self.treeview.back()
315
        
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
316
    def _fwd_clicked_cb(self, *args):
317
        """Callback for when the forward button is clicked."""
304 by Daniel Schierbeck
Made forward/back buttons work again.
318
        self.treeview.forward()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
319
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
320
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
321
        """Callback for when the go button for a parent is clicked."""
356 by Daniel Schierbeck
Made revision a property on TreeView.
322
        self.treeview.set_revision_id(revid)
152 by Jelmer Vernooij
Cleanup some more code.
323
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
324
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
325
        """Callback for when the show button for a parent is clicked."""
364 by Daniel Schierbeck
Simplified TreeView.show_diff() and made the Revision -> View Changes menu item work.
326
        self.treeview.show_diff(revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
327
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
328
352.1.1 by Daniel Schierbeck
Added dropdown menu to Back button.
329
    def _set_revision_cb(self, w, revision_id):
356 by Daniel Schierbeck
Made revision a property on TreeView.
330
        self.treeview.set_revision_id(revision_id)
352.1.1 by Daniel Schierbeck
Added dropdown menu to Back button.
331
365 by Daniel Schierbeck
Fixed locks and made tagging work.
332
    def _tag_revision_cb(self, w):
333
        dialog = AddTagDialog(self.branch.repository, self.treeview.get_revision().revision_id, self.branch)
334
        response = dialog.run()
335
        if response != gtk.RESPONSE_NONE:
336
            dialog.hide()
337
        
338
            if response == gtk.RESPONSE_OK:
339
                try:
340
                    self.branch.lock_write()
341
                    self.branch.tags.set_tag(dialog.tagname, dialog._revid)
342
                finally:
343
                    self.branch.unlock()
344
            
345
            dialog.destroy()
346
348 by Daniel Schierbeck
Added toggle item for revision number column.
347
    def _col_visibility_changed(self, col, property):
348
        self.treeview.set_property(property + '-column-visible', col.get_active())
351 by Daniel Schierbeck
Added option to hide the toolbar.
349
350
    def _toolbar_visibility_changed(self, col):
351
        if col.get_active():
352
            self.toolbar.show() 
353
        else:
354
            self.toolbar.hide()