/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
"""Directed graph production.
3
4
This module contains the code to produce an ordered directed graph of a
5
bzr branch, such as we display in the tree view at the top of the bzrk
6
window.
7
"""
8
9
__copyright__ = "Copyright © 2005 Canonical Ltd."
10
__author__    = "Scott James Remnant <scott@ubuntu.com>"
11
12
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
13
def linegraph(branch, start, maxnum):
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
14
    """Produce a directed graph of a bzr branch.
15
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
16
    Returns a list of tuples of (revision, node, lines, parents, children).
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
17
18
    Node is a tuple of (column, colour) with column being a zero-indexed
19
    column number of the graph that this revision represents and colour
20
    being a zero-indexed colour (which doesn't specify any actual colour
21
    in particular) to draw the node in.
22
23
    Lines is a list of tuples which represent lines you should draw away
24
    from the revision, if you also need to draw lines into the revision
25
    you should use the lines list from the previous iteration.  Each
26
    typle in the list is in the form (start, end, colour) with start and
27
    end being zero-indexed column numbers and colour as in node.
28
29
    It's up to you how to actually draw the nodes and lines (straight,
30
    curved, kinked, etc.) and to pick the actual colours for each index.
31
    """
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
32
    
256.2.16 by Gary van der Merwe
Make sure a revision is only ever a direct parent of one child.
33
    def getdirectparent(childrevid, childindex, childsparents):
256.2.6 by Gary van der Merwe
Implement color selection
34
        """Return the revision id of the direct parent
35
        
36
        The direct parent is the first parent with the same committer"""
37
        childrevision = revisions[childindex]
38
        directparent = directparentcache[childindex]
39
        if directparent is None:
40
            for parentrevid in childsparents:
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
41
                if parentrevid in revindex:
256.2.16 by Gary van der Merwe
Make sure a revision is only ever a direct parent of one child.
42
                    parentindex = revindex[parentrevid]
43
                    parentrevision = revisions[parentindex]
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
44
                    if childrevision.committer == parentrevision.committer:
256.2.16 by Gary van der Merwe
Make sure a revision is only ever a direct parent of one child.
45
                        # This may be a direct parent, but first check that
46
                        # for this parent, there are no other children, who are
47
                        # before us in the children list, for which this parent
48
                        # is also the direct parent.
49
                        # pc in all the below var name stands for parents child
50
                        first = True
51
                        for pcrevid in revisionchildren[parentindex]:
52
                            if pcrevid == childrevid:
53
                                break
54
                            pcindex = revindex[pcrevid]
55
                            pcdirectparent = getdirectparent(pcrevid,
56
                                                    pcindex,
57
                                                    revisionchildren[pcindex])
58
                            if pcdirectparent==parentrevid:
59
                                first = False
60
                                break
61
                        
62
                        if first:
63
                            directparent = parentrevid
64
                            break
256.2.6 by Gary van der Merwe
Implement color selection
65
            #no parents have the same commiter
66
            if directparent is None:
67
                directparent = ""
68
            directparentcache[childindex] = directparent
69
        return directparent
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
70
    
71
    def find_column_from_branchlineid(branchlineid):
72
        for index, column in enumerate(columns):
73
            if column is not None and column["branchlineid"] == branchlineid:
74
                return (index, column)
75
        return (None, None)
76
    
77
    def has_no_nodes_between (column, startindex, endindex):
78
        for nodeindex in column["nodeindexes"]:
79
            if nodeindex > startindex and nodeindex < endindex:
80
                return False
81
        return True
82
    
83
    def append_line (column , startindex, endindex):
84
        column["lines"].append((startindex,endindex))
85
        if endindex > column["maxindex"] :
86
            column["maxindex"] = endindex
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
87
    
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
88
    def append_column (column, minindex):
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
89
        columnindex = None
90
        for (i, c) in enumerate(columns):
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
91
            if c is None or (c["branchlineid"] == "finished" \
92
                             and c["maxindex"] <= minindex):
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
93
                columnindex = i
94
                columns[columnindex] = column
95
                break
96
        if columnindex is None:
97
            columnindex = len(columns)
98
            columns.append(column)
99
        return columnindex
256.2.6 by Gary van der Merwe
Implement color selection
100
    
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
101
    revids = []
102
    revindex = {}
103
    for (index, revid) in enumerate(reversed( \
104
            branch.repository.get_ancestry(start))):
105
        if revid is not None:
106
            revids.append(revid)
107
            revindex[revid] = index
108
        if maxnum is not None and index > maxnum:
109
            break
110
    
256.2.22 by Gary van der Merwe
Use branch.revision_history as a mainline
111
    mainline = branch.revision_history()
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
112
    revisions = branch.repository.get_revisions(revids)
113
    revisionparents = branch.repository.get_graph().get_parents(revids)    
114
    directparentcache = [None for revision in revisions]
115
    
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
116
    # This will hold what we plan to put in each column.
117
    # The position of the item in this list indicates the column, and it
118
    # it may change if we need to make space for other things.
119
    # Each typle in the list is in the form:
120
    # (branchlineid, nodeindexes, lines, maxindex)
121
    # A item may be None to indicate that there is nothing in the column
122
    columns = []
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
123
    
124
    linegraph = []
125
    
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
126
    lastbranchlineid = 0
127
    branchlineids = []
128
    revisionchildren = [[] for revision in revisions]
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
129
    notdrawnlines = []
256.2.6 by Gary van der Merwe
Implement color selection
130
    
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
131
    for (index, revision) in enumerate(revisions):
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
132
        parents = [parent for parent in revisionparents[index] \
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
133
                   if parent!="null:"]
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
134
        for parentrevid in parents:
135
            if parentrevid in revindex:
136
                revisionchildren[revindex[parentrevid]]\
137
                    .append(revision.revision_id)
138
        
139
        children = revisionchildren[index]
256.2.18 by Gary van der Merwe
small optimization
140
        
141
        #We use childrevid, childindex, childbranchlineid often, so cache it
142
        children_ext = []
143
        for childrevid in children:
144
            childindex = revindex[childrevid]
145
            children_ext.append((childrevid,
146
                                 childindex,
147
                                 branchlineids[childindex]))
148
        
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
149
        linegraph.append([revision, None,
150
                          [], parents, children])
151
        
152
        branchlineid = None
256.2.22 by Gary van der Merwe
Use branch.revision_history as a mainline
153
        
154
        if revision.revision_id in mainline:
155
            branchlineid = 0
156
        else:
157
            #Try and see if we are the same branchline as one of our children
158
            #If we are, use the same branchlineid
159
            for (childrevid, childindex, childbranchlineid) in children_ext: 
160
                childsparents = revisionparents[childindex]
161
                
162
                if len(children) == 1 and len(childsparents) == 1: 
163
                    # one-one relationship between parent and child
164
                    branchlineid = childbranchlineid
165
                    break
166
                
167
                #Is the current revision the direct parent of the child?
168
                if childbranchlineid != 0 and revision.revision_id == \
169
                        getdirectparent(childrevid, childindex, childsparents):
170
                    branchlineid = childbranchlineid
171
                    break
256.2.6 by Gary van der Merwe
Implement color selection
172
        
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
173
        if branchlineid is None:
174
            branchlineid = lastbranchlineid = lastbranchlineid + 1
175
        
176
        branchlineids.append(branchlineid)
177
        
178
        (columnindex, column) = find_column_from_branchlineid(branchlineid)
179
        
180
        if columnindex is None:
256.2.18 by Gary van der Merwe
small optimization
181
            for (childrevid, childindex, childbranchlineid) in children_ext:
182
                (i, c) = find_column_from_branchlineid(childbranchlineid)
183
                if c is not None and c["maxindex"] <= index:
184
                    (columnindex, column) = (i, c)
185
                    break
186
    
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
187
188
        
189
        if columnindex is None:
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
190
            minindex = index
191
            for childrevid in children:
192
                childindex = revindex[childrevid]
193
                if childindex<minindex:
194
                    minindex = childindex
195
            
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
196
            column = {"branchlineid": branchlineid,
197
                      "nodeindexes": [index],
198
                      "lines": [],
199
                      "maxindex": index}
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
200
            columnindex = append_column(column, minindex)
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
201
        else:
202
            column["branchlineid"] = branchlineid
203
            column["nodeindexes"].append(index)
204
        
256.2.16 by Gary van der Merwe
Make sure a revision is only ever a direct parent of one child.
205
        opentillparent = getdirectparent(revision.revision_id, index, parents)
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
206
        if opentillparent == "":
207
            if len(parents)>0:
208
                opentillparent = parents[0]
256.2.10 by Gary van der Merwe
Ensure that we don't give a child a same color when we don't mean to becuase we have run through all the other colors in the wheel.
209
            else:
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
210
                opentillparent = None
211
        
212
        if opentillparent is not None and opentillparent in revindex:
213
            parentindex = revindex[opentillparent]
214
            if parentindex > column["maxindex"]:
215
                column["maxindex"] = parentindex
216
        
256.2.18 by Gary van der Merwe
small optimization
217
        for (childrevid, childindex, childbranchlineid) in children_ext: 
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
218
            (childcolumnindex, childcolumn) = \
219
                find_column_from_branchlineid(childbranchlineid)
256.2.10 by Gary van der Merwe
Ensure that we don't give a child a same color when we don't mean to becuase we have run through all the other colors in the wheel.
220
            
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
221
            if index-childindex == 1 or childcolumnindex is None:
222
                append_line(column,childindex,index)
223
            elif childcolumnindex >= columnindex and \
224
                    has_no_nodes_between(childcolumn, childindex, index):
225
                append_line(childcolumn,childindex,index)
226
            elif childcolumnindex > columnindex and \
227
                    has_no_nodes_between(column, childindex, index):
228
                append_line(column,childindex,index)
229
            elif childcolumnindex < columnindex and \
230
                    has_no_nodes_between(column, childindex, index):
231
                append_line(column,childindex,index)
232
            elif childcolumnindex < columnindex and \
233
                    has_no_nodes_between(childcolumn, childindex, index):
234
                append_line(childcolumn,childindex,index)
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
235
            else:
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
236
                append_column({"branchlineid": "line",
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
237
                                "nodeindexes": [],
238
                                "lines": [(childindex,index)],
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
239
                                "maxindex": index}, childindex)
256.2.11 by Gary van der Merwe
New viz lines algorithm. Not 100% yet - but close.
240
        
241
        for (columnindex, column) in enumerate(columns):
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
242
            if column is not None and column["maxindex"] <= index \
243
                    and column["branchlineid"] != "finished":
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
244
                for nodeindex in column["nodeindexes"]:
245
                    linegraph[nodeindex][1] = (columnindex,
246
                                               branchlineids[nodeindex])
247
            
256.2.13 by Gary van der Merwe
better lines
248
                for (childindex, parentindex) in column["lines"]:
249
                    notdrawnlines.append((columnindex, childindex, parentindex))
250
                
256.2.15 by Gary van der Merwe
Make sure that we don't put lines on top of allready drawn branchlines
251
                column["branchlineid"] = "finished"
252
                column["nodeindexes"] = []
253
                column["lines"] = []
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
254
        
255
        for (lineindex,(columnindex, childindex, parentindex))\
256
                in enumerate(notdrawnlines):
257
            
258
            childnode = linegraph[childindex][1]
259
            parentnode = linegraph[parentindex][1]
260
            if childnode is not None and parentnode is not None:
261
                notdrawnlines[lineindex] = None
262
                if parentindex>childindex+1:
263
                    #out from the child to line
264
                    linegraph[childindex][2].append(
265
                        (childnode[0],    #the column of the child
266
                         columnindex,     #the column of the line
267
                         parentnode[1]))
268
                    
269
                    #down the line
270
                    for linepartindex in range(childindex+1, parentindex-1):
271
                        linegraph[linepartindex][2].append(
272
                            (columnindex, #the column of the line
273
                             columnindex, #the column of the line
274
                             parentnode[1]))
275
                    
276
                    #in to the parent
277
                    linegraph[parentindex-1][2].append(
278
                        (columnindex,     #the column of the line
279
                         parentnode[0],   #the column of the parent
280
                         parentnode[1]))
37.1.2 by Robert Collins
Make revision sorting and linking use merge_sorted from latest bzr.dev. This
281
                else:
256.2.12 by Gary van der Merwe
Impove the folding of the new lines
282
                    #child to parent
283
                    linegraph[childindex][2].append(
284
                        (childnode[0],    #the column of the child
285
                         parentnode[0],   #the column of the parent
286
                         parentnode[1]))
287
        
288
        notdrawnlines = [line for line in notdrawnlines if line is not None]
289
        
1 by Scott James Remnant
Commit the first version of bzrk.
290
256.2.21 by Gary van der Merwe
Refactor so that line graph is more contained.
291
    return (linegraph, revindex, revisions)
2 by Scott James Remnant
Split the same branch functionality out into a separate function so
292
27 by David Allouche
refactor distances
293
2 by Scott James Remnant
Split the same branch functionality out into a separate function so
294
def same_branch(a, b):
295
    """Return whether we think revisions a and b are on the same branch."""
296
    if len(a.parent_ids) == 1:
297
        # Defacto same branch if only parent
298
        return True
299
    elif a.committer == b.committer:
300
        # Same committer so may as well be
301
        return True
302
    else:
303
        return False