/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
16
from bzrlib.osutils import format_date
17
256.2.5 by Gary van der Merwe
Oops - Renamed file without changeing import lines
18
from linegraph import linegraph, same_branch
1 by Scott James Remnant
Commit the first version of bzrk.
19
from graphcell import CellRendererGraph
20
21
22
class BranchWindow(gtk.Window):
23
    """Branch window.
24
25
    This object represents and manages a single window containing information
26
    for a particular branch.
27
    """
28
152 by Jelmer Vernooij
Cleanup some more code.
29
    def __init__(self):
1 by Scott James Remnant
Commit the first version of bzrk.
30
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
31
        self.set_border_width(0)
32
        self.set_title("bzrk")
33
34
        # Use three-quarters of the screen by default
35
        screen = self.get_screen()
4 by Scott James Remnant
Use the size of the first monitor rather than the entire screen
36
        monitor = screen.get_monitor_geometry(0)
37
        width = int(monitor.width * 0.75)
38
        height = int(monitor.height * 0.75)
1 by Scott James Remnant
Commit the first version of bzrk.
39
        self.set_default_size(width, height)
40
41
        # FIXME AndyFitz!
42
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
43
        self.set_icon(icon)
44
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
45
        self.accel_group = gtk.AccelGroup()
46
        self.add_accel_group(self.accel_group)
47
1 by Scott James Remnant
Commit the first version of bzrk.
48
        self.construct()
49
50
    def construct(self):
51
        """Construct the window contents."""
44 by David Allouche
reorganise branch window
52
        vbox = gtk.VBox(spacing=0)
53
        self.add(vbox)
54
55
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
56
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
57
        paned = gtk.VPaned()
58
        paned.pack1(self.construct_top(), resize=True, shrink=False)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
59
        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
60
        paned.show()
44 by David Allouche
reorganise branch window
61
        vbox.pack_start(paned, expand=True, fill=True)
62
        vbox.set_focus_child(paned)
63
64
        vbox.show()
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
65
66
    def construct_top(self):
67
        """Construct the top-half of the window."""
1 by Scott James Remnant
Commit the first version of bzrk.
68
        scrollwin = gtk.ScrolledWindow()
69
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
70
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
71
        scrollwin.show()
72
73
        self.treeview = gtk.TreeView()
74
        self.treeview.set_rules_hint(True)
75
        self.treeview.set_search_column(4)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
76
        self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
77
        self.treeview.connect("row-activated", self._treeview_row_activated_cb)
226 by Jelmer Vernooij
Add context menu in bzrk.
78
        self.treeview.connect("button-release-event", 
79
                self._treeview_row_mouseclick)
1 by Scott James Remnant
Commit the first version of bzrk.
80
        scrollwin.add(self.treeview)
81
        self.treeview.show()
82
256.2.27 by Gary van der Merwe
Show Revision No in tree
83
        cell = gtk.CellRendererText()
84
        #cell.set_property("width-chars", 40)
85
        #cell.set_property("ellipsize", pango.ELLIPSIZE_END)
86
        column = gtk.TreeViewColumn("Revision No")
87
        column.set_resizable(True)
88
        column.pack_start(cell, expand=True)
89
        column.add_attribute(cell, "text", 9)
90
        self.treeview.append_column(column)
91
1 by Scott James Remnant
Commit the first version of bzrk.
92
        cell = CellRendererGraph()
93
        column = gtk.TreeViewColumn()
45 by David Allouche
resizable graph column
94
        column.set_resizable(True)
1 by Scott James Remnant
Commit the first version of bzrk.
95
        column.pack_start(cell, expand=False)
96
        column.add_attribute(cell, "node", 1)
97
        column.add_attribute(cell, "in-lines", 2)
98
        column.add_attribute(cell, "out-lines", 3)
99
        self.treeview.append_column(column)
100
101
        cell = gtk.CellRendererText()
102
        cell.set_property("width-chars", 40)
103
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
104
        column = gtk.TreeViewColumn("Message")
105
        column.set_resizable(True)
106
        column.pack_start(cell, expand=True)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
107
        column.add_attribute(cell, "text", 6)
1 by Scott James Remnant
Commit the first version of bzrk.
108
        self.treeview.append_column(column)
109
110
        cell = gtk.CellRendererText()
111
        cell.set_property("width-chars", 40)
112
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
113
        column = gtk.TreeViewColumn("Committer")
114
        column.set_resizable(True)
115
        column.pack_start(cell, expand=True)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
116
        column.add_attribute(cell, "text", 7)
1 by Scott James Remnant
Commit the first version of bzrk.
117
        self.treeview.append_column(column)
118
119
        cell = gtk.CellRendererText()
120
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
121
        column = gtk.TreeViewColumn("Date")
122
        column.set_resizable(True)
123
        column.pack_start(cell, expand=True)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
124
        column.add_attribute(cell, "text", 8)
1 by Scott James Remnant
Commit the first version of bzrk.
125
        self.treeview.append_column(column)
126
44 by David Allouche
reorganise branch window
127
        return scrollwin
128
129
    def construct_navigation(self):
130
        """Construct the navigation buttons."""
131
        frame = gtk.Frame()
132
        frame.set_shadow_type(gtk.SHADOW_OUT)
133
        frame.show()
134
        
135
        hbox = gtk.HBox(spacing=12)
136
        frame.add(hbox)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
137
        hbox.show()
138
139
        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
44 by David Allouche
reorganise branch window
140
        self.back_button.set_relief(gtk.RELIEF_NONE)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
141
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
142
                                         0, 0)
143
        self.back_button.connect("clicked", self._back_clicked_cb)
144
        hbox.pack_start(self.back_button, expand=False, fill=True)
145
        self.back_button.show()
146
147
        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
44 by David Allouche
reorganise branch window
148
        self.fwd_button.set_relief(gtk.RELIEF_NONE)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
149
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
150
                                        0, 0)
151
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
152
        hbox.pack_start(self.fwd_button, expand=False, fill=True)
153
        self.fwd_button.show()
154
44 by David Allouche
reorganise branch window
155
        return frame
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
156
157
    def construct_bottom(self):
158
        """Construct the bottom half of the window."""
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
159
        from bzrlib.plugins.gtk.logview import LogView
256.2.23 by Gary van der Merwe
Show Children
160
        self.logview = LogView(None, True, [], True)
44 by David Allouche
reorganise branch window
161
        (width, height) = self.get_size()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
162
        self.logview.set_size_request(width, int(height / 2.5))
163
        self.logview.show()
164
        self.logview.set_show_callback(self._show_clicked_cb)
165
        self.logview.set_go_callback(self._go_clicked_cb)
166
        return self.logview
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
167
40 by David Allouche
remove --robust, pyflakes fixes, update README
168
    def set_branch(self, branch, start, maxnum):
1 by Scott James Remnant
Commit the first version of bzrk.
169
        """Set the branch and start position for this window.
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
170
        
1 by Scott James Remnant
Commit the first version of bzrk.
171
        Creates a new TreeModel and populates it with information about
172
        the new branch before updating the window title and model of the
173
        treeview itself.
174
        """
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
175
        self.branch = branch
176
1 by Scott James Remnant
Commit the first version of bzrk.
177
        # [ revision, node, last_lines, lines, message, committer, timestamp ]
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
178
        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT,
179
                                   gobject.TYPE_PYOBJECT,
180
                                   gobject.TYPE_PYOBJECT,
181
                                   gobject.TYPE_PYOBJECT,
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
182
                                   gobject.TYPE_PYOBJECT,
183
                                   gobject.TYPE_PYOBJECT,
256.2.27 by Gary van der Merwe
Show Revision No in tree
184
                                   str, str, str, str)
265.1.1 by Gary van der Merwe
Show bzr viz interface quickly.
185
        self.set_title(branch.nick + " - bzrk")
186
        gobject.idle_add(self.populate_model, start, maxnum)
187
188
    def populate_model(self, start, maxnum):
256.2.28 by Gary van der Merwe
Better line drawing with info from merge_sort
189
        (linegraphdata, index) = linegraph(self.branch,
190
                                           start,
191
                                           maxnum)
192
        print "linegraph compleate"
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
193
        self.index = index
256.2.28 by Gary van der Merwe
Better line drawing with info from merge_sort
194
        self.revisions = []
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
195
        
1 by Scott James Remnant
Commit the first version of bzrk.
196
        last_lines = []
256.2.28 by Gary van der Merwe
Better line drawing with info from merge_sort
197
        for (index,(revid,
256.2.27 by Gary van der Merwe
Show Revision No in tree
198
                    node,
199
                    lines,
200
                    parents,
201
                    children,
202
                    revno_sequence)) in enumerate(linegraphdata):
41 by David Allouche
restore --maxnum functionality, reflush some comments
203
            # FIXME: at this point we should be able to show the graph order
204
            # and lines with no message or commit data - and then incrementally
205
            # fill the timestamp, committer etc data as desired.
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
206
            
256.2.28 by Gary van der Merwe
Better line drawing with info from merge_sort
207
            revision = self.branch.repository.get_revisions([revid])[0]
208
            self.revisions.append(revision)
209
            
1 by Scott James Remnant
Commit the first version of bzrk.
210
            message = revision.message.split("\n")[0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
211
            
1 by Scott James Remnant
Commit the first version of bzrk.
212
            if revision.committer is not None:
213
                timestamp = format_date(revision.timestamp, revision.timezone)
214
            else:
215
                timestamp = None
256.2.27 by Gary van der Merwe
Show Revision No in tree
216
            revno_string = ".".join(["%d" % (revno) for revno in revno_sequence])
217
            
218
            self.model.append([revision,
219
                               node,
220
                               last_lines,
221
                               lines,
222
                               parents,
223
                               children, 
224
                               message,
225
                               revision.committer,
226
                               timestamp,
227
                               revno_string])
1 by Scott James Remnant
Commit the first version of bzrk.
228
            last_lines = lines
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
229
        self.treeview.set_model(self.model)
256.2.20 by Gary van der Merwe
Merge trunk.
230
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
231
    def _treeview_cursor_cb(self, *args):
232
        """Callback for when the treeview cursor changes."""
233
        (path, col) = self.treeview.get_cursor()
234
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
235
        parents = self.model[path][4]
236
        children = self.model[path][5]
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
237
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
238
        self.back_button.set_sensitive(len(parents) > 0)
239
        self.fwd_button.set_sensitive(len(children) > 0)
241 by Jelmer Vernooij
Show tags in bzr viz.
240
        tags = []
241
        if self.branch.supports_tags():
242
            tagdict = self.branch.tags.get_reverse_tag_dict()
243
            if tagdict.has_key(revision.revision_id):
244
                tags = tagdict[revision.revision_id]
256.2.23 by Gary van der Merwe
Show Children
245
        self.logview.set_revision(revision, tags, children)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
246
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
247
    def _back_clicked_cb(self, *args):
248
        """Callback for when the back button is clicked."""
249
        (path, col) = self.treeview.get_cursor()
250
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
251
        parents = self.model[path][4]
252
        if not len(parents):
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
253
            return
254
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
255
        for parent_id in parents:
256
            parent = self.revisions[self.index[parent_id]]
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
257
            if same_branch(revision, parent):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
258
                self.treeview.set_cursor(self.index[parent_id])
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
259
                break
260
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
261
            self.treeview.set_cursor(self.index[parents[0]])
13 by Scott James Remnant
Keep the focus on the treeview
262
        self.treeview.grab_focus()
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
263
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
264
    def _fwd_clicked_cb(self, *args):
265
        """Callback for when the forward button is clicked."""
266
        (path, col) = self.treeview.get_cursor()
267
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
268
        children = self.model[path][5]
269
        if not len(children):
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
270
            return
271
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
272
        for child_id in children:
273
            child = self.revisions[self.index[child_id]]
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
274
            if same_branch(child, revision):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
275
                self.treeview.set_cursor(self.index[child_id])
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
276
                break
277
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
278
            self.treeview.set_cursor(self.index[children[0]])
13 by Scott James Remnant
Keep the focus on the treeview
279
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
280
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
281
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
282
        """Callback for when the go button for a parent is clicked."""
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
283
        self.treeview.set_cursor(self.index[revid])
13 by Scott James Remnant
Keep the focus on the treeview
284
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
285
152 by Jelmer Vernooij
Cleanup some more code.
286
    def show_diff(self, branch, revid, parentid):
287
        """Open a new window to show a diff between the given revisions."""
288
        from bzrlib.plugins.gtk.diff import DiffWindow
289
        window = DiffWindow()
226 by Jelmer Vernooij
Add context menu in bzrk.
290
        (parent_tree, rev_tree) = branch.repository.revision_trees([parentid, 
291
                                                                   revid])
152 by Jelmer Vernooij
Cleanup some more code.
292
        description = revid + " - " + branch.nick
293
        window.set_diff(description, rev_tree, parent_tree)
294
        window.show()
295
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
296
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
297
        """Callback for when the show button for a parent is clicked."""
152 by Jelmer Vernooij
Cleanup some more code.
298
        self.show_diff(self.branch, revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
299
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
300
226 by Jelmer Vernooij
Add context menu in bzrk.
301
    def _treeview_row_mouseclick(self, widget, event):
302
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
303
        if event.button == 3:
304
            menu = RevisionPopupMenu(self.branch.repository, 
230 by Jelmer Vernooij
Initial work towards supporting multiple revisions.
305
                [x.revision_id for x in self.selected_revisions()],
306
                self.branch)
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
307
            menu.popup(None, None, None, event.button, event.get_time())
226 by Jelmer Vernooij
Add context menu in bzrk.
308
309
    def selected_revision(self, path):
310
        return self.model[path][0]
311
312
    def selected_revisions(self):
313
        return [self.selected_revision(path) for path in \
314
                self.treeview.get_selection().get_selected_rows()[1]]
315
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
316
    def _treeview_row_activated_cb(self, widget, path, col):
46 by Wouter van Heyst
show diff on row activation, LP# 44591
317
        # TODO: more than one parent
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
318
        """Callback for when a treeview row gets activated."""
229 by Jelmer Vernooij
Fix regression.
319
        revision = self.selected_revision(path)
74 by Jelmer Vernooij
Fix exception when double-clicking revision without parents.
320
        if len(self.parent_ids[revision]) == 0:
321
            # Ignore revisions without parent
322
            return
46 by Wouter van Heyst
show diff on row activation, LP# 44591
323
        parent_id = self.parent_ids[revision][0]
152 by Jelmer Vernooij
Cleanup some more code.
324
        self.show_diff(self.branch, revision.revision_id, parent_id)
46 by Wouter van Heyst
show diff on row activation, LP# 44591
325
        self.treeview.grab_focus()