/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
198 by Jelmer Vernooij
Add tests for DummyRevision.
13
from bzrlib.revision import Revision
37.1.2 by Robert Collins
Make revision sorting and linking use merge_sorted from latest bzr.dev. This
14
from bzrlib.tsort import merge_sort
1 by Scott James Remnant
Commit the first version of bzrk.
15
256.2.6 by Gary van der Merwe
Implement color selection
16
def linegraph(revisions, revisionparents, revindex):
3 by Scott James Remnant
Split the display in two with a pane, we'll use the bottom half to show
17
    """Produce a directed graph of a bzr branch.
18
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
19
    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
20
21
    Node is a tuple of (column, colour) with column being a zero-indexed
22
    column number of the graph that this revision represents and colour
23
    being a zero-indexed colour (which doesn't specify any actual colour
24
    in particular) to draw the node in.
25
26
    Lines is a list of tuples which represent lines you should draw away
27
    from the revision, if you also need to draw lines into the revision
28
    you should use the lines list from the previous iteration.  Each
29
    typle in the list is in the form (start, end, colour) with start and
30
    end being zero-indexed column numbers and colour as in node.
31
32
    It's up to you how to actually draw the nodes and lines (straight,
33
    curved, kinked, etc.) and to pick the actual colours for each index.
34
    """
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
35
    
256.2.6 by Gary van der Merwe
Implement color selection
36
    directparentcache = [None for revision in revisions]
37
    def getdirectparent(childindex, childsparents):
38
        """Return the revision id of the direct parent
39
        
40
        The direct parent is the first parent with the same committer"""
41
        childrevision = revisions[childindex]
42
        directparent = directparentcache[childindex]
43
        if directparent is None:
44
            for parentrevid in childsparents:
45
                parentrevision = revisions[revindex[parentrevid]]
46
                if childrevision.committer == parentrevision.committer:
47
                    directparent = parentrevid
48
                    break
49
            #no parents have the same commiter
50
            if directparent is None:
51
                directparent = ""
52
            directparentcache[childindex] = directparent
53
        return directparent
54
        
55
56
    
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
57
    #This will hold the lines we have not yet added to lines
58
    #The position of the item in this list indicates the column, and it
59
    #it may change if we need to make space for other branches.
60
    #Each typle in the list is in the form (child index, parent revision)
61
    #A item may be None to indicate that there is no line for a column
62
    activelines = []
63
    
64
    linegraph = []
65
    
256.2.6 by Gary van der Merwe
Implement color selection
66
    lastcolor = 0
67
    
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
68
    for (index, revision) in enumerate(revisions):
69
        parents = [parent for parent in revisionparents[index]\
70
                   if parent!="null:"]
71
        
72
        revnodecolumn = None
73
        
74
        #This will hold a list of lines whose parent is this rev
75
        linesforcurrentrev = []
76
        
77
        children = []
78
        
79
        #We should maybe should pop None's at the end of activelines.
80
        #I'm not sure what will cost more: resizing the list, or
81
        #have this loop ittrate more.
82
        
83
        #Find lines that end at this rev
84
        for (column, activeline) in enumerate(activelines):
85
            if (activeline is not None):
86
                (childindex, parentrevid) = activeline
87
                if parentrevid == revision.revision_id:
88
                    linesforcurrentrev.append((childindex, parentrevid, column))
89
                    activelines[column] = None
90
                    children.append(linegraph[childindex][0].revision_id)
91
                    
92
                    #The node column for this rev will be the smallest
93
                    #column for the lines that end at this rev
94
                    #The smallest column is the first one we get to.
95
                    if revnodecolumn is None:
96
                        revnodecolumn = column
97
        
98
        #This will happen for the latest revision
99
        if revnodecolumn is None:
100
            revnodecolumn = 0
101
        
256.2.6 by Gary van der Merwe
Implement color selection
102
        color = None
103
        
104
        #Try and see if we are the same "branch" as one of our children
105
        #If we are, use the childs color
106
        for childrevid in children:
107
            childindex = revindex[childrevid]
108
            childsparents = revisionparents[childindex]
109
            if len(children) == 1 and len(childsparents) == 1: 
110
                # one-one relationship between parent and child, same colour
111
                #1st [1] selects the node
112
                #2nd [1] selects the color
113
                color = linegraph[childindex][1][1]
114
                break
115
            
116
            #Is the current revision the direct parent of the child?
117
            if revision.revision_id == getdirectparent(childindex, childsparents):
118
                color = linegraph[childindex][1][1]
119
                break
120
        
121
        if color is None:
122
            color = lastcolor = lastcolor + 1
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
123
        
124
        #We now have every thing (except for the lines) so we can add
125
        #our tuple to our list.
126
        linegraph.append((revision, (revnodecolumn, color),
127
                          [], parents, children))
128
        
129
        #add all the line bits to the rev that the line passes
130
        for (childindex, parentrevid, column) in linesforcurrentrev:
131
            if index>childindex+1:
132
                #out from the child to line
133
                linegraph[childindex][2].append(
134
                    (linegraph[childindex][1][0], #the column of the child
135
                     column,                      #the column of the line
136
                     color))
137
                
138
                #down the line
139
                for linepartindex in range(childindex+1, index-1):
140
                    linegraph[linepartindex][2].append(
141
                        (column,                  #the column of the line
142
                         column,                  #the column of the line
143
                         color))
144
                
145
                #in to the parent
146
                linegraph[index-1][2].append(
147
                    (column,                      #the column of the line
148
                     revnodecolumn,               #the column of the parent
149
                     color))
150
            else:
151
                #child to parent
152
                linegraph[childindex][2].append(
153
                    (linegraph[childindex][1][0], #the column of the child
154
                     revnodecolumn,               #the column of the parent
155
                     color))
156
                
157
        for parentrevid in parents:
158
            column = revnodecolumn
159
            line = (index,parentrevid)
160
            while True:
161
                if column<len(activelines):
162
                    if activelines[column] is None:
163
                        #An empty column. Put line here
164
                        activelines[column] = line
165
                        break
166
                    else:
167
                        if activelines[column][0] == index:
168
                            #This column is allready used for a line for
169
                            #this rev, Move along.
170
                            column += 1
171
                        else:
172
                            #This column is allready used for a line for
173
                            #another rev. Insert this line at this column,
174
                            #and in the process, move all the other lines out.
175
                            activelines.insert(column, line)
176
                            break
37.1.2 by Robert Collins
Make revision sorting and linking use merge_sorted from latest bzr.dev. This
177
                else:
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
178
                    #no more columns, so add one to the end
179
                    activelines.append(line)
180
                    break
1 by Scott James Remnant
Commit the first version of bzrk.
181
256.2.4 by Gary van der Merwe
First go at using bzrlib graph code
182
    return linegraph
2 by Scott James Remnant
Split the same branch functionality out into a separate function so
183
27 by David Allouche
refactor distances
184
2 by Scott James Remnant
Split the same branch functionality out into a separate function so
185
def same_branch(a, b):
186
    """Return whether we think revisions a and b are on the same branch."""
187
    if len(a.parent_ids) == 1:
188
        # Defacto same branch if only parent
189
        return True
190
    elif a.committer == b.committer:
191
        # Same committer so may as well be
192
        return True
193
    else:
194
        return False