/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
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
15
import treemodel
1 by Scott James Remnant
Commit the first version of bzrk.
16
17
from bzrlib.osutils import format_date
18
256.2.5 by Gary van der Merwe
Oops - Renamed file without changeing import lines
19
from linegraph import linegraph, same_branch
1 by Scott James Remnant
Commit the first version of bzrk.
20
from graphcell import CellRendererGraph
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
21
from treemodel import TreeModel
1 by Scott James Remnant
Commit the first version of bzrk.
22
23
24
class BranchWindow(gtk.Window):
25
    """Branch window.
26
27
    This object represents and manages a single window containing information
28
    for a particular branch.
29
    """
30
152 by Jelmer Vernooij
Cleanup some more code.
31
    def __init__(self):
1 by Scott James Remnant
Commit the first version of bzrk.
32
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
33
        self.set_border_width(0)
34
        self.set_title("bzrk")
35
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)
226 by Jelmer Vernooij
Add context menu in bzrk.
80
        self.treeview.connect("button-release-event", 
81
                self._treeview_row_mouseclick)
1 by Scott James Remnant
Commit the first version of bzrk.
82
        scrollwin.add(self.treeview)
83
        self.treeview.show()
84
256.2.27 by Gary van der Merwe
Show Revision No in tree
85
        cell = gtk.CellRendererText()
86
        #cell.set_property("width-chars", 40)
87
        #cell.set_property("ellipsize", pango.ELLIPSIZE_END)
88
        column = gtk.TreeViewColumn("Revision No")
89
        column.set_resizable(True)
90
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
91
        column.add_attribute(cell, "text", treemodel.REVNO)
256.2.27 by Gary van der Merwe
Show Revision No in tree
92
        self.treeview.append_column(column)
93
1 by Scott James Remnant
Commit the first version of bzrk.
94
        cell = CellRendererGraph()
95
        column = gtk.TreeViewColumn()
45 by David Allouche
resizable graph column
96
        column.set_resizable(True)
1 by Scott James Remnant
Commit the first version of bzrk.
97
        column.pack_start(cell, expand=False)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
98
        column.add_attribute(cell, "node", treemodel.NODE)
99
        column.add_attribute(cell, "in-lines", treemodel.LAST_LINES)
100
        column.add_attribute(cell, "out-lines", treemodel.LINES)
1 by Scott James Remnant
Commit the first version of bzrk.
101
        self.treeview.append_column(column)
102
103
        cell = gtk.CellRendererText()
104
        cell.set_property("width-chars", 40)
105
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
106
        column = gtk.TreeViewColumn("Message")
107
        column.set_resizable(True)
108
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
109
        column.add_attribute(cell, "text", treemodel.MESSAGE)
1 by Scott James Remnant
Commit the first version of bzrk.
110
        self.treeview.append_column(column)
111
112
        cell = gtk.CellRendererText()
113
        cell.set_property("width-chars", 40)
114
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
115
        column = gtk.TreeViewColumn("Committer")
116
        column.set_resizable(True)
117
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
118
        column.add_attribute(cell, "text", treemodel.COMMITER)
1 by Scott James Remnant
Commit the first version of bzrk.
119
        self.treeview.append_column(column)
120
121
        cell = gtk.CellRendererText()
122
        cell.set_property("ellipsize", pango.ELLIPSIZE_END)
123
        column = gtk.TreeViewColumn("Date")
124
        column.set_resizable(True)
125
        column.pack_start(cell, expand=True)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
126
        column.add_attribute(cell, "text", treemodel.TIMESTAMP)
1 by Scott James Remnant
Commit the first version of bzrk.
127
        self.treeview.append_column(column)
128
44 by David Allouche
reorganise branch window
129
        return scrollwin
130
131
    def construct_navigation(self):
132
        """Construct the navigation buttons."""
133
        frame = gtk.Frame()
134
        frame.set_shadow_type(gtk.SHADOW_OUT)
135
        frame.show()
136
        
137
        hbox = gtk.HBox(spacing=12)
138
        frame.add(hbox)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
139
        hbox.show()
140
141
        self.back_button = gtk.Button(stock=gtk.STOCK_GO_BACK)
44 by David Allouche
reorganise branch window
142
        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
143
        self.back_button.add_accelerator("clicked", self.accel_group, ord('['),
144
                                         0, 0)
145
        self.back_button.connect("clicked", self._back_clicked_cb)
146
        hbox.pack_start(self.back_button, expand=False, fill=True)
147
        self.back_button.show()
148
149
        self.fwd_button = gtk.Button(stock=gtk.STOCK_GO_FORWARD)
44 by David Allouche
reorganise branch window
150
        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
151
        self.fwd_button.add_accelerator("clicked", self.accel_group, ord(']'),
152
                                        0, 0)
153
        self.fwd_button.connect("clicked", self._fwd_clicked_cb)
154
        hbox.pack_start(self.fwd_button, expand=False, fill=True)
155
        self.fwd_button.show()
156
44 by David Allouche
reorganise branch window
157
        return frame
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
158
159
    def construct_bottom(self):
160
        """Construct the bottom half of the window."""
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
161
        from bzrlib.plugins.gtk.logview import LogView
256.2.23 by Gary van der Merwe
Show Children
162
        self.logview = LogView(None, True, [], True)
44 by David Allouche
reorganise branch window
163
        (width, height) = self.get_size()
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
164
        self.logview.set_size_request(width, int(height / 2.5))
165
        self.logview.show()
166
        self.logview.set_show_callback(self._show_clicked_cb)
167
        self.logview.set_go_callback(self._go_clicked_cb)
168
        return self.logview
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
169
40 by David Allouche
remove --robust, pyflakes fixes, update README
170
    def set_branch(self, branch, start, maxnum):
1 by Scott James Remnant
Commit the first version of bzrk.
171
        """Set the branch and start position for this window.
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
172
        
1 by Scott James Remnant
Commit the first version of bzrk.
173
        Creates a new TreeModel and populates it with information about
174
        the new branch before updating the window title and model of the
175
        treeview itself.
176
        """
10 by Scott James Remnant
Add an extra window type, clicking the little icons next to a parent
177
        self.branch = branch
265.1.1 by Gary van der Merwe
Show bzr viz interface quickly.
178
        self.set_title(branch.nick + " - bzrk")
179
        gobject.idle_add(self.populate_model, start, maxnum)
180
181
    def populate_model(self, start, maxnum):
256.2.28 by Gary van der Merwe
Better line drawing with info from merge_sort
182
        (linegraphdata, index) = linegraph(self.branch,
183
                                           start,
184
                                           maxnum)
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
185
        self.model = TreeModel(self.branch, linegraphdata)
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
186
        self.index = index
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
187
        self.treeview.set_model(self.model)
256.2.20 by Gary van der Merwe
Merge trunk.
188
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
189
    def _treeview_cursor_cb(self, *args):
190
        """Callback for when the treeview cursor changes."""
191
        (path, col) = self.treeview.get_cursor()
256.2.29 by Gary van der Merwe
Implement a TreeModel that loads revisions incrementaly.
192
        iter = self.model.get_iter(path)
193
        revision = self.model.get_value(iter, treemodel.REVISION)
194
        parents = self.model.get_value(iter, treemodel.PARENTS)
195
        children = self.model.get_value(iter, treemodel.CHILDREN)
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
196
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
197
        self.back_button.set_sensitive(len(parents) > 0)
198
        self.fwd_button.set_sensitive(len(children) > 0)
241 by Jelmer Vernooij
Show tags in bzr viz.
199
        tags = []
200
        if self.branch.supports_tags():
201
            tagdict = self.branch.tags.get_reverse_tag_dict()
202
            if tagdict.has_key(revision.revision_id):
203
                tags = tagdict[revision.revision_id]
256.2.23 by Gary van der Merwe
Show Children
204
        self.logview.set_revision(revision, tags, children)
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
205
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
206
    def _back_clicked_cb(self, *args):
207
        """Callback for when the back button is clicked."""
208
        (path, col) = self.treeview.get_cursor()
209
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
210
        parents = self.model[path][4]
211
        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
212
            return
213
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
214
        for parent_id in parents:
215
            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
216
            if same_branch(revision, parent):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
217
                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
218
                break
219
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
220
            self.treeview.set_cursor(self.index[parents[0]])
13 by Scott James Remnant
Keep the focus on the treeview
221
        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
222
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
223
    def _fwd_clicked_cb(self, *args):
224
        """Callback for when the forward button is clicked."""
225
        (path, col) = self.treeview.get_cursor()
226
        revision = self.model[path][0]
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
227
        children = self.model[path][5]
228
        if not len(children):
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
229
            return
230
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
231
        for child_id in children:
232
            child = self.revisions[self.index[child_id]]
5 by Scott James Remnant
Reverse the meaning of the Back and Forward buttons so Back actually
233
            if same_branch(child, revision):
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
234
                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
235
                break
236
        else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
237
            self.treeview.set_cursor(self.index[children[0]])
13 by Scott James Remnant
Keep the focus on the treeview
238
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
239
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
240
    def _go_clicked_cb(self, revid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
241
        """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
242
        self.treeview.set_cursor(self.index[revid])
13 by Scott James Remnant
Keep the focus on the treeview
243
        self.treeview.grab_focus()
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
244
152 by Jelmer Vernooij
Cleanup some more code.
245
    def show_diff(self, branch, revid, parentid):
246
        """Open a new window to show a diff between the given revisions."""
247
        from bzrlib.plugins.gtk.diff import DiffWindow
248
        window = DiffWindow()
226 by Jelmer Vernooij
Add context menu in bzrk.
249
        (parent_tree, rev_tree) = branch.repository.revision_trees([parentid, 
250
                                                                   revid])
152 by Jelmer Vernooij
Cleanup some more code.
251
        description = revid + " - " + branch.nick
252
        window.set_diff(description, rev_tree, parent_tree)
253
        window.show()
254
147 by Jelmer Vernooij
Remove a bunch of duplicate functionality.
255
    def _show_clicked_cb(self, revid, parentid):
7 by Scott James Remnant
Put some information about the highlighted revision in the bottom pane,
256
        """Callback for when the show button for a parent is clicked."""
152 by Jelmer Vernooij
Cleanup some more code.
257
        self.show_diff(self.branch, revid, parentid)
13 by Scott James Remnant
Keep the focus on the treeview
258
        self.treeview.grab_focus()
46 by Wouter van Heyst
show diff on row activation, LP# 44591
259
226 by Jelmer Vernooij
Add context menu in bzrk.
260
    def _treeview_row_mouseclick(self, widget, event):
261
        from bzrlib.plugins.gtk.revisionmenu import RevisionPopupMenu
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
262
        if event.button == 3:
263
            menu = RevisionPopupMenu(self.branch.repository, 
230 by Jelmer Vernooij
Initial work towards supporting multiple revisions.
264
                [x.revision_id for x in self.selected_revisions()],
265
                self.branch)
228 by Jelmer Vernooij
Remove unused code, prefer questions to check boxes.
266
            menu.popup(None, None, None, event.button, event.get_time())
226 by Jelmer Vernooij
Add context menu in bzrk.
267
268
    def selected_revision(self, path):
269
        return self.model[path][0]
270
271
    def selected_revisions(self):
272
        return [self.selected_revision(path) for path in \
273
                self.treeview.get_selection().get_selected_rows()[1]]
274
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
275
    def _treeview_row_activated_cb(self, widget, path, col):
46 by Wouter van Heyst
show diff on row activation, LP# 44591
276
        # TODO: more than one parent
47 by Wouter van Heyst
rename _treeview_clicked_cb to correcter _treeview_row_activated_cb
277
        """Callback for when a treeview row gets activated."""
229 by Jelmer Vernooij
Fix regression.
278
        revision = self.selected_revision(path)
74 by Jelmer Vernooij
Fix exception when double-clicking revision without parents.
279
        if len(self.parent_ids[revision]) == 0:
280
            # Ignore revisions without parent
281
            return
46 by Wouter van Heyst
show diff on row activation, LP# 44591
282
        parent_id = self.parent_ids[revision][0]
152 by Jelmer Vernooij
Cleanup some more code.
283
        self.show_diff(self.branch, revision.revision_id, parent_id)
46 by Wouter van Heyst
show diff on row activation, LP# 44591
284
        self.treeview.grab_focus()