/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
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
18
from graph import distances, graph, 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
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
29
    def __init__(self, app=None):
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
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
34
        self.app = app
35
1 by Scott James Remnant
Commit the first version of bzrk.
36
        # Use three-quarters of the screen by default
37
        screen = self.get_screen()
4 by Scott James Remnant
Use the size of the first monitor rather than the entire screen
38
        monitor = screen.get_monitor_geometry(0)
39
        width = int(monitor.width * 0.75)
40
        height = int(monitor.height * 0.75)
1 by Scott James Remnant
Commit the first version of bzrk.
41
        self.set_default_size(width, height)
42
43
        # FIXME AndyFitz!
44
        icon = self.render_icon(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
45
        self.set_icon(icon)
46
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
47
        self.accel_group = gtk.AccelGroup()
48
        self.add_accel_group(self.accel_group)
49
1 by Scott James Remnant
Commit the first version of bzrk.
50
        self.construct()
51
52
    def construct(self):
53
        """Construct the window contents."""
44 by David Allouche
reorganise branch window
54
        vbox = gtk.VBox(spacing=0)
55
        self.add(vbox)
56
57
        vbox.pack_start(self.construct_navigation(), expand=False, fill=True)
58
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
59
        paned = gtk.VPaned()
60
        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,
61
        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
62
        paned.show()
44 by David Allouche
reorganise branch window
63
        vbox.pack_start(paned, expand=True, fill=True)
64
        vbox.set_focus_child(paned)
65
66
        vbox.show()
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
67
68
    def construct_top(self):
69
        """Construct the top-half of the window."""
1 by Scott James Remnant
Commit the first version of bzrk.
70
        scrollwin = gtk.ScrolledWindow()
71
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
72
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
73
        scrollwin.show()
74
75
        self.treeview = gtk.TreeView()
76
        self.treeview.set_rules_hint(True)
77
        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
78
        self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
79
        self.treeview.connect("row-activated", self._treeview_row_activated_cb)
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)
98
        column.add_attribute(cell, "text", 4)
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)
107
        column.add_attribute(cell, "text", 5)
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)
115
        column.add_attribute(cell, "text", 6)
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()
152
        self.logview.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
153
        self.logview.set_shadow_type(gtk.SHADOW_NONE)
44 by David Allouche
reorganise branch window
154
        (width, height) = self.get_size()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
155
        self.logview.set_size_request(width, int(height / 2.5))
156
        self.logview.show()
157
        self.logview.set_show_callback(self._show_clicked_cb)
158
        self.logview.set_go_callback(self._go_clicked_cb)
159
        return self.logview
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
160
40 by David Allouche
remove --robust, pyflakes fixes, update README
161
    def set_branch(self, branch, start, maxnum):
1 by Scott James Remnant
Commit the first version of bzrk.
162
        """Set the branch and start position for this window.
163
164
        Creates a new TreeModel and populates it with information about
165
        the new branch before updating the window title and model of the
166
        treeview itself.
167
        """
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
168
        self.branch = branch
169
1 by Scott James Remnant
Commit the first version of bzrk.
170
        # [ 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
171
        self.model = gtk.ListStore(gobject.TYPE_PYOBJECT,
172
                                   gobject.TYPE_PYOBJECT,
173
                                   gobject.TYPE_PYOBJECT,
174
                                   gobject.TYPE_PYOBJECT,
175
                                   str, str, str)
176
        self.index = {}
177
        index = 0
1 by Scott James Remnant
Commit the first version of bzrk.
178
179
        last_lines = []
40 by David Allouche
remove --robust, pyflakes fixes, update README
180
        (self.revisions, colours, self.children, self.parent_ids,
41 by David Allouche
restore --maxnum functionality, reflush some comments
181
         merge_sorted) = distances(branch, start)
182
        for (index, (revision, node, lines)) in enumerate(graph(
183
                self.revisions, colours, merge_sorted)):
184
            # FIXME: at this point we should be able to show the graph order
185
            # and lines with no message or commit data - and then incrementally
186
            # fill the timestamp, committer etc data as desired.
1 by Scott James Remnant
Commit the first version of bzrk.
187
            message = revision.message.split("\n")[0]
188
            if revision.committer is not None:
189
                timestamp = format_date(revision.timestamp, revision.timezone)
190
            else:
191
                timestamp = None
41 by David Allouche
restore --maxnum functionality, reflush some comments
192
            self.model.append([revision, node, last_lines, lines,
193
                               message, revision.committer, timestamp])
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
194
            self.index[revision] = index
1 by Scott James Remnant
Commit the first version of bzrk.
195
            last_lines = lines
41 by David Allouche
restore --maxnum functionality, reflush some comments
196
            if maxnum is not None and index > maxnum:
197
                break
1 by Scott James Remnant
Commit the first version of bzrk.
198
36.1.2 by Jamie Wilkinson
put the branch nick in the titlebar instead of the path basename (which didn't work anyway)
199
        self.set_title(branch.nick + " - bzrk")
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
200
        self.treeview.set_model(self.model)
201
202
    def _treeview_cursor_cb(self, *args):
203
        """Callback for when the treeview cursor changes."""
204
        (path, col) = self.treeview.get_cursor()
205
        revision = self.model[path][0]
206
20 by David Allouche
ignore redundent parents
207
        self.back_button.set_sensitive(len(self.parent_ids[revision]) > 0)
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
208
        self.fwd_button.set_sensitive(len(self.children[revision]) > 0)
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
209
        self.logview.set_revision(revision)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
210
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
211
    def _back_clicked_cb(self, *args):
212
        """Callback for when the back button is clicked."""
213
        (path, col) = self.treeview.get_cursor()
214
        revision = self.model[path][0]
20 by David Allouche
ignore redundent parents
215
        if not len(self.parent_ids[revision]):
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
216
            return
217
20 by David Allouche
ignore redundent parents
218
        for parent_id in self.parent_ids[revision]:
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
219
            parent = self.revisions[parent_id]
220
            if same_branch(revision, parent):
221
                self.treeview.set_cursor(self.index[parent])
222
                break
223
        else:
20 by David Allouche
ignore redundent parents
224
            next = self.revisions[self.parent_ids[revision][0]]
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
225
            self.treeview.set_cursor(self.index[next])
13 by Scott James Remnant
Keep the focus on the treeview
226
        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
227
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
228
    def _fwd_clicked_cb(self, *args):
229
        """Callback for when the forward button is clicked."""
230
        (path, col) = self.treeview.get_cursor()
231
        revision = self.model[path][0]
232
        if not len(self.children[revision]):
233
            return
234
235
        for child in self.children[revision]:
236
            if same_branch(child, revision):
237
                self.treeview.set_cursor(self.index[child])
238
                break
239
        else:
240
            prev = list(self.children[revision])[0]
241
            self.treeview.set_cursor(self.index[prev])
13 by Scott James Remnant
Keep the focus on the treeview
242
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
243
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
244
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
245
        """Callback for when the go button for a parent is clicked."""
246
        self.treeview.set_cursor(self.index[self.revisions[revid]])
13 by Scott James Remnant
Keep the focus on the treeview
247
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
248
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
249
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
250
        """Callback for when the show button for a parent is clicked."""
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
251
        if self.app is not None:
252
            self.app.show_diff(self.branch, revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
253
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
254
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
255
    def _treeview_row_activated_cb(self, widget, path, col):
46 by Wouter van Heyst
show diff on row activation, LP# 44591
256
        # TODO: more than one parent
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
257
        """Callback for when a treeview row gets activated."""
46 by Wouter van Heyst
show diff on row activation, LP# 44591
258
        revision = self.model[path][0]
74 by Jelmer Vernooij
Fix exception when double-clicking revision without parents.
259
        if len(self.parent_ids[revision]) == 0:
260
            # Ignore revisions without parent
261
            return
46 by Wouter van Heyst
show diff on row activation, LP# 44591
262
        parent_id = self.parent_ids[revision][0]
263
        if self.app is not None:
264
            self.app.show_diff(self.branch, revision.revision_id, parent_id)
265
        self.treeview.grab_focus()