/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
83
        cell = CellRendererGraph()
84
        column = gtk.TreeViewColumn()
45 by David Allouche
resizable graph column
85
        column.set_resizable(True)
1 by Scott James Remnant
Commit the first version of bzrk.
86
        column.pack_start(cell, expand=False)
87
        column.add_attribute(cell, "node", 1)
88
        column.add_attribute(cell, "in-lines", 2)
89
        column.add_attribute(cell, "out-lines", 3)
90
        self.treeview.append_column(column)
91
92
        cell = gtk.CellRendererText()
93
        cell.set_property("width-chars", 40)
94
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
95
        column = gtk.TreeViewColumn("Message")
96
        column.set_resizable(True)
97
        column.pack_start(cell, expand=True)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
98
        column.add_attribute(cell, "text", 6)
1 by Scott James Remnant
Commit the first version of bzrk.
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("Committer")
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", 7)
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("ellipsize", pango.ELLIPSIZE_END)
112
        column = gtk.TreeViewColumn("Date")
113
        column.set_resizable(True)
114
        column.pack_start(cell, expand=True)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
115
        column.add_attribute(cell, "text", 8)
1 by Scott James Remnant
Commit the first version of bzrk.
116
        self.treeview.append_column(column)
117
44 by David Allouche
reorganise branch window
118
        return scrollwin
119
120
    def construct_navigation(self):
121
        """Construct the navigation buttons."""
122
        frame = gtk.Frame()
123
        frame.set_shadow_type(gtk.SHADOW_OUT)
124
        frame.show()
125
        
126
        hbox = gtk.HBox(spacing=12)
127
        frame.add(hbox)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
128
        hbox.show()
129
130
        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
44 by David Allouche
reorganise branch window
131
        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
132
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
133
                                         0, 0)
134
        self.back_button.connect("clicked", self._back_clicked_cb)
135
        hbox.pack_start(self.back_button, expand=False, fill=True)
136
        self.back_button.show()
137
138
        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
44 by David Allouche
reorganise branch window
139
        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
140
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
141
                                        0, 0)
142
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
143
        hbox.pack_start(self.fwd_button, expand=False, fill=True)
144
        self.fwd_button.show()
145
44 by David Allouche
reorganise branch window
146
        return frame
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
147
148
    def construct_bottom(self):
149
        """Construct the bottom half of the window."""
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
150
        from bzrlib.plugins.gtk.logview import LogView
151
        self.logview = LogView()
44 by David Allouche
reorganise branch window
152
        (width, height) = self.get_size()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
153
        self.logview.set_size_request(width, int(height / 2.5))
154
        self.logview.show()
155
        self.logview.set_show_callback(self._show_clicked_cb)
156
        self.logview.set_go_callback(self._go_clicked_cb)
157
        return self.logview
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
158
40 by David Allouche
remove --robust, pyflakes fixes, update README
159
    def set_branch(self, branch, start, maxnum):
1 by Scott James Remnant
Commit the first version of bzrk.
160
        """Set the branch and start position for this window.
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
161
        
1 by Scott James Remnant
Commit the first version of bzrk.
162
        Creates a new TreeModel and populates it with information about
163
        the new branch before updating the window title and model of the
164
        treeview itself.
165
        """
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
166
        self.branch = branch
167
1 by Scott James Remnant
Commit the first version of bzrk.
168
        # [ 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
169
        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT,
170
                                   gobject.TYPE_PYOBJECT,
171
                                   gobject.TYPE_PYOBJECT,
172
                                   gobject.TYPE_PYOBJECT,
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
173
                                   gobject.TYPE_PYOBJECT,
174
                                   gobject.TYPE_PYOBJECT,
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
175
                                   str, str, str)
265.1.1 by Gary van der Merwe
Show bzr viz interface quickly.
176
        self.set_title(branch.nick + " - bzrk")
177
        gobject.idle_add(self.populate_model, start, maxnum)
178
179
    def populate_model(self, start, maxnum):
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
180
        (linegraphdata, index, revisions) = linegraph(self.branch,
181
                                                      start,
182
                                                      maxnum)
183
        self.index = index
184
        self.revisions = revisions
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
185
        
1 by Scott James Remnant
Commit the first version of bzrk.
186
        last_lines = []
256.2.6 by Gary van der Merwe
Implement color selection
187
        for (index,(revision, node, lines, parents, children)) in enumerate( \
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
188
                linegraphdata):
41 by David Allouche
restore --maxnum functionality, reflush some comments
189
            # FIXME: at this point we should be able to show the graph order
190
            # and lines with no message or commit data - and then incrementally
191
            # fill the timestamp, committer etc data as desired.
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
192
            
1 by Scott James Remnant
Commit the first version of bzrk.
193
            message = revision.message.split("\n")[0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
194
            
1 by Scott James Remnant
Commit the first version of bzrk.
195
            if revision.committer is not None:
196
                timestamp = format_date(revision.timestamp, revision.timezone)
197
            else:
198
                timestamp = None
41 by David Allouche
restore --maxnum functionality, reflush some comments
199
            self.model.append([revision, node, last_lines, lines,
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
200
                               parents, children, 
41 by David Allouche
restore --maxnum functionality, reflush some comments
201
                               message, revision.committer, timestamp])
1 by Scott James Remnant
Commit the first version of bzrk.
202
            last_lines = lines
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
203
        self.treeview.set_model(self.model)
256.2.20 by Gary van der Merwe
Merge trunk.
204
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
205
    def _treeview_cursor_cb(self, *args):
206
        """Callback for when the treeview cursor changes."""
207
        (path, col) = self.treeview.get_cursor()
208
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
209
        parents = self.model[path][4]
210
        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
211
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
212
        self.back_button.set_sensitive(len(parents) > 0)
213
        self.fwd_button.set_sensitive(len(children) > 0)
241 by Jelmer Vernooij
Show tags in bzr viz.
214
        tags = []
215
        if self.branch.supports_tags():
216
            tagdict = self.branch.tags.get_reverse_tag_dict()
217
            if tagdict.has_key(revision.revision_id):
218
                tags = tagdict[revision.revision_id]
219
        self.logview.set_revision(revision, tags)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
220
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
221
    def _back_clicked_cb(self, *args):
222
        """Callback for when the back button is clicked."""
223
        (path, col) = self.treeview.get_cursor()
224
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
225
        parents = self.model[path][4]
226
        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
227
            return
228
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
229
        for parent_id in parents:
230
            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
231
            if same_branch(revision, parent):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
232
                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
233
                break
234
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
235
            self.treeview.set_cursor(self.index[parents[0]])
13 by Scott James Remnant
Keep the focus on the treeview
236
        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
237
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
238
    def _fwd_clicked_cb(self, *args):
239
        """Callback for when the forward button is clicked."""
240
        (path, col) = self.treeview.get_cursor()
241
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
242
        children = self.model[path][5]
243
        if not len(children):
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
244
            return
245
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
246
        for child_id in children:
247
            child = self.revisions[self.index[child_id]]
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
248
            if same_branch(child, revision):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
249
                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
250
                break
251
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
252
            self.treeview.set_cursor(self.index[children[0]])
13 by Scott James Remnant
Keep the focus on the treeview
253
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
254
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
255
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
256
        """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
257
        self.treeview.set_cursor(self.index[revid])
13 by Scott James Remnant
Keep the focus on the treeview
258
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
259
152 by Jelmer Vernooij
Cleanup some more code.
260
    def show_diff(self, branch, revid, parentid):
261
        """Open a new window to show a diff between the given revisions."""
262
        from bzrlib.plugins.gtk.diff import DiffWindow
263
        window = DiffWindow()
226 by Jelmer Vernooij
Add context menu in bzrk.
264
        (parent_tree, rev_tree) = branch.repository.revision_trees([parentid, 
265
                                                                   revid])
152 by Jelmer Vernooij
Cleanup some more code.
266
        description = revid + " - " + branch.nick
267
        window.set_diff(description, rev_tree, parent_tree)
268
        window.show()
269
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
270
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
271
        """Callback for when the show button for a parent is clicked."""
152 by Jelmer Vernooij
Cleanup some more code.
272
        self.show_diff(self.branch, revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
273
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
274
226 by Jelmer Vernooij
Add context menu in bzrk.
275
    def _treeview_row_mouseclick(self, widget, event):
276
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
277
        if event.button == 3:
278
            menu = RevisionPopupMenu(self.branch.repository, 
230 by Jelmer Vernooij
Initial work towards supporting multiple revisions.
279
                [x.revision_id for x in self.selected_revisions()],
280
                self.branch)
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
281
            menu.popup(None, None, None, event.button, event.get_time())
226 by Jelmer Vernooij
Add context menu in bzrk.
282
283
    def selected_revision(self, path):
284
        return self.model[path][0]
285
286
    def selected_revisions(self):
287
        return [self.selected_revision(path) for path in \
288
                self.treeview.get_selection().get_selected_rows()[1]]
289
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
290
    def _treeview_row_activated_cb(self, widget, path, col):
46 by Wouter van Heyst
show diff on row activation, LP# 44591
291
        # TODO: more than one parent
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
292
        """Callback for when a treeview row gets activated."""
229 by Jelmer Vernooij
Fix regression.
293
        revision = self.selected_revision(path)
74 by Jelmer Vernooij
Fix exception when double-clicking revision without parents.
294
        if len(self.parent_ids[revision]) == 0:
295
            # Ignore revisions without parent
296
            return
46 by Wouter van Heyst
show diff on row activation, LP# 44591
297
        parent_id = self.parent_ids[revision][0]
152 by Jelmer Vernooij
Cleanup some more code.
298
        self.show_diff(self.branch, revision.revision_id, parent_id)
46 by Wouter van Heyst
show diff on row activation, LP# 44591
299
        self.treeview.grab_focus()