/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to viz/branchwin.py

  • Committer: Daniel Schierbeck
  • Date: 2007-11-07 14:19:09 UTC
  • mfrom: (330.3.5 trunk)
  • Revision ID: daniel.schierbeck@gmail.com-20071107141909-3zxf7nw5laldvfxi
Merged with mainline.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
23
 
 
24
class BranchWindow(Window):
 
25
    """Branch window.
 
26
 
 
27
    This object represents and manages a single window containing information
 
28
    for a particular branch.
 
29
    """
 
30
 
 
31
    def __init__(self, branch, start, maxnum, parent=None):
 
32
        """Create a new BranchWindow.
 
33
 
 
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, 
 
37
                       None for no limit.
 
38
        """
 
39
 
 
40
        Window.__init__(self, parent=parent)
 
41
        self.set_border_width(0)
 
42
 
 
43
        self.branch      = branch
 
44
        self.start       = start
 
45
        self.maxnum      = maxnum
 
46
        self.config      = GlobalConfig()
 
47
 
 
48
        if self.config.get_user_option('viz-compact-view') == 'yes':
 
49
            self.compact_view = True
 
50
        else:
 
51
            self.compact_view = False
 
52
 
 
53
        self.set_title(branch.nick + " - revision history")
 
54
 
 
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)
 
61
 
 
62
        # FIXME AndyFitz!
 
63
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
 
64
        self.set_icon(icon)
 
65
 
 
66
        self.accel_group = gtk.AccelGroup()
 
67
        self.add_accel_group(self.accel_group)
 
68
 
 
69
        self.construct()
 
70
 
 
71
    def set_revision(self, revision):
 
72
        self.treeview.set_revision(revision)
 
73
 
 
74
    def construct(self):
 
75
        """Construct the window contents."""
 
76
        vbox = gtk.VBox(spacing=0)
 
77
        self.add(vbox)
 
78
 
 
79
        top = self.construct_top()
 
80
 
 
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)
 
84
        
 
85
        paned = gtk.VPaned()
 
86
        paned.pack1(top, resize=True, shrink=False)
 
87
        paned.pack2(self.construct_bottom(), resize=False, shrink=True)
 
88
        paned.show()
 
89
        vbox.pack_start(paned, expand=True, fill=True)
 
90
        vbox.set_focus_child(paned)
 
91
 
 
92
        vbox.show()
 
93
 
 
94
    def construct_menubar(self):
 
95
        menubar = gtk.MenuBar()
 
96
 
 
97
        file_menu = gtk.Menu()
 
98
        file_menuitem = gtk.MenuItem("_File")
 
99
        file_menuitem.set_submenu(file_menu)
 
100
 
 
101
        file_menu_close = gtk.ImageMenuItem(gtk.STOCK_CLOSE, self.accel_group)
 
102
        file_menu_close.connect('activate', lambda x: self.destroy())
 
103
        
 
104
        file_menu_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.accel_group)
 
105
        file_menu_quit.connect('activate', lambda x: gtk.main_quit())
 
106
        
 
107
        file_menu.add(file_menu_close)
 
108
        file_menu.add(file_menu_quit)
 
109
 
 
110
        edit_menu = gtk.Menu()
 
111
        edit_menuitem = gtk.MenuItem("_Edit")
 
112
        edit_menuitem.set_submenu(edit_menu)
 
113
 
 
114
        edit_menu_find = gtk.ImageMenuItem(gtk.STOCK_FIND)
 
115
 
 
116
        edit_menu_branchopts = gtk.MenuItem("Branch Settings")
 
117
        edit_menu_branchopts.connect('activate', lambda x: PreferencesWindow(self.branch.get_config()).show())
 
118
 
 
119
        edit_menu_prefs = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES)
 
120
        edit_menu_prefs.connect('activate', lambda x: PreferencesWindow().show())
 
121
 
 
122
        edit_menu.add(edit_menu_find)
 
123
        edit_menu.add(edit_menu_branchopts)
 
124
        edit_menu.add(edit_menu_prefs)
 
125
 
 
126
        view_menu = gtk.Menu()
 
127
        view_menuitem = gtk.MenuItem("_View")
 
128
        view_menuitem.set_submenu(view_menu)
 
129
 
 
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)
 
133
 
 
134
        view_menu.add(view_menu_toolbar)
 
135
        view_menu.add(gtk.SeparatorMenuItem())
 
136
 
 
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)
 
141
            view_menu.add(col)
 
142
 
 
143
        go_menu = gtk.Menu()
 
144
        go_menuitem = gtk.MenuItem("_Go")
 
145
        go_menuitem.set_submenu(go_menu)
 
146
        
 
147
        go_menu_back = gtk.ImageMenuItem(gtk.STOCK_GO_DOWN)
 
148
        go_menu_back.connect("activate", self._back_clicked_cb)
 
149
 
 
150
        go_menu_forward = gtk.ImageMenuItem(gtk.STOCK_GO_UP)
 
151
        go_menu_forward.connect("activate", self._fwd_clicked_cb)
 
152
 
 
153
        tags_menu = gtk.Menu()
 
154
        go_menu_tags = gtk.MenuItem("_Tags")
 
155
        go_menu_tags.set_submenu(tags_menu)
 
156
 
 
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)
 
162
 
 
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)
 
167
 
 
168
        revision_menu = gtk.Menu()
 
169
        revision_menuitem = gtk.MenuItem("_Revision")
 
170
        revision_menuitem.set_submenu(revision_menu)
 
171
 
 
172
        revision_menu_diff = gtk.MenuItem("View Changes")
 
173
        revision_menu_diff.connect('activate', 
 
174
                lambda w: self.treeview.show_diff())
 
175
 
 
176
        revision_menu_tag = gtk.MenuItem("Tag Revision")
 
177
        revision_menu_tag.connect('activate', self._tag_revision_cb)
 
178
 
 
179
        revision_menu.add(revision_menu_tag)
 
180
        revision_menu.add(revision_menu_diff)
 
181
 
 
182
        branch_menu = gtk.Menu()
 
183
        branch_menuitem = gtk.MenuItem("_Branch")
 
184
        branch_menuitem.set_submenu(branch_menu)
 
185
 
 
186
        branch_menu.add(gtk.MenuItem("Pu_ll Revisions"))
 
187
        branch_menu.add(gtk.MenuItem("Pu_sh Revisions"))
 
188
       
 
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)
 
195
        menubar.show_all()
 
196
 
 
197
        return menubar
 
198
    
 
199
    def construct_loading_msg(self):
 
200
        image_loading = gtk.image_new_from_stock(gtk.STOCK_REFRESH,
 
201
                                                 gtk.ICON_SIZE_BUTTON)
 
202
        image_loading.show()
 
203
        
 
204
        label_loading = gtk.Label(_("Please wait, loading ancestral graph..."))
 
205
        label_loading.set_alignment(0.0, 0.5)
 
206
        label_loading.show()
 
207
        
 
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()
 
214
        
 
215
        return self.loading_msg_box
 
216
 
 
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:
 
221
            brokenlines = 32
 
222
        else:
 
223
            brokenlines = None
 
224
 
 
225
        self.treeview = TreeView(self.branch, self.start, self.maxnum, brokenlines)
 
226
 
 
227
        self.treeview.connect("revision-selected",
 
228
                self._treeselection_changed_cb)
 
229
 
 
230
        self.treeview.connect('revisions-loaded', 
 
231
                lambda x: self.loading_msg_box.hide())
 
232
 
 
233
        self.treeview.show()
 
234
 
 
235
        return self.treeview
 
236
 
 
237
    def construct_navigation(self):
 
238
        """Construct the navigation buttons."""
 
239
        self.toolbar = gtk.Toolbar()
 
240
        self.toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ)
 
241
 
 
242
        self.back_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_DOWN)
 
243
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
 
244
                                         0, 0)
 
245
        self.back_button.connect("clicked", self._back_clicked_cb)
 
246
        self.toolbar.insert(self.back_button, -1)
 
247
 
 
248
        self.fwd_button = gtk.MenuToolButton(stock_id=gtk.STOCK_GO_UP)
 
249
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
 
250
                                        0, 0)
 
251
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
 
252
        self.toolbar.insert(self.fwd_button, -1)
 
253
 
 
254
        self.toolbar.insert(gtk.SeparatorToolItem(), -1)
 
255
 
 
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)
 
262
 
 
263
        self.toolbar.show_all()
 
264
 
 
265
        return self.toolbar
 
266
 
 
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
 
277
 
 
278
    def _tag_selected_cb(self, menuitem, revid):
 
279
        self.treeview.set_revision_id(revid)
 
280
 
 
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()
 
286
 
 
287
        if revision is not None:
 
288
            back_menu = gtk.Menu()
 
289
            if len(parents) > 0:
 
290
                self.back_button.set_sensitive(True)
 
291
                for parent_id in parents:
 
292
                    parent = self.branch.repository.get_revision(parent_id)
 
293
                    try:
 
294
                        str = ' (' + parent.properties['branch-nick'] + ')'
 
295
                    except KeyError:
 
296
                        str = ""
 
297
 
 
298
                    item = gtk.MenuItem(parent.message.split("\n")[0] + str)
 
299
                    item.connect('activate', self._set_revision_cb, parent_id)
 
300
                    back_menu.add(item)
 
301
                back_menu.show_all()
 
302
            else:
 
303
                self.back_button.set_sensitive(False)
 
304
                back_menu.hide()
 
305
 
 
306
            self.back_button.set_menu(back_menu)
 
307
 
 
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)
 
313
                    try:
 
314
                        str = ' (' + child.properties['branch-nick'] + ')'
 
315
                    except KeyError:
 
316
                        str = ""
 
317
 
 
318
                    item = gtk.MenuItem(child.message.split("\n")[0] + str)
 
319
                    item.connect('activate', self._set_revision_cb, child_id)
 
320
                    fwd_menu.add(item)
 
321
                fwd_menu.show_all()
 
322
            else:
 
323
                self.fwd_button.set_sensitive(False)
 
324
                fwd_menu.hide()
 
325
 
 
326
            self.fwd_button.set_menu(fwd_menu)
 
327
 
 
328
            tags = []
 
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)
 
334
 
 
335
    def _back_clicked_cb(self, *args):
 
336
        """Callback for when the back button is clicked."""
 
337
        self.treeview.back()
 
338
        
 
339
    def _fwd_clicked_cb(self, *args):
 
340
        """Callback for when the forward button is clicked."""
 
341
        self.treeview.forward()
 
342
 
 
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)
 
346
 
 
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()
 
351
 
 
352
    def _set_revision_cb(self, w, revision_id):
 
353
        self.treeview.set_revision_id(revision_id)
 
354
 
 
355
    def _brokenlines_toggled_cb(self, button):
 
356
        self.compact_view = button.get_active()
 
357
 
 
358
        if self.compact_view:
 
359
            option = 'yes'
 
360
        else:
 
361
            option = 'no'
 
362
 
 
363
        self.config.set_user_option('viz-compact-view', option)
 
364
 
 
365
        revision = self.treeview.get_revision()
 
366
 
 
367
        self.treeview.destroy()
 
368
        self.paned.pack1(self.construct_top(), resize=True, shrink=False)
 
369
 
 
370
        gobject.idle_add(self.set_revision, revision.revision_id)
 
371
 
 
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:
 
376
            dialog.hide()
 
377
        
 
378
            if response == gtk.RESPONSE_OK:
 
379
                try:
 
380
                    self.branch.lock_write()
 
381
                    self.branch.tags.set_tag(dialog.tagname, dialog._revid)
 
382
                finally:
 
383
                    self.branch.unlock()
 
384
            
 
385
            dialog.destroy()
 
386
 
 
387
    def _col_visibility_changed(self, col, property):
 
388
        self.treeview.set_property(property + '-column-visible', col.get_active())
 
389
 
 
390
    def _toolbar_visibility_changed(self, col):
 
391
        if col.get_active():
 
392
            self.toolbar.show() 
 
393
        else:
 
394
            self.toolbar.hide()