1 package de.tud.plt.r43ples.visualisation;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Dimension;
6 import java.awt.Graphics2D;
7 import java.awt.geom.Dimension2D;
8 import java.awt.geom.GeneralPath;
9 import java.util.HashMap;
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Queue;
14
15 import de.tud.plt.r43ples.revisionTree.Commit;
16
17 public class CommitGraphView {
18
19
20
21
22 private static final int CIRCLE_DIAMETER = 10;
23
24
25
26
27
28 private static final int COLUMN_WIDTH = 15;
29
30
31 private Dimension2D dimension;
32
33 private List<Commit> terminalCommits = new LinkedList<Commit>();
34
35 private Map<Commit, Integer> commit_column = new HashMap<Commit, Integer>();
36
37 private Queue<Color> colorQueue;
38
39 private List<Commit> commits;
40
41 public CommitGraphView(List<Commit> commits) {
42 this.commits = commits;
43 colorQueue = new LinkedList<Color>();
44 colorQueue.add(new Color(0.5f, 0.1f, 0.1f));
45 colorQueue.add(new Color(0.1f, 0.5f, 0.1f));
46 colorQueue.add(new Color(0.1f, 0.1f, 0.5f));
47 colorQueue.add(new Color(0.5f, 0.5f, 0.1f));
48 colorQueue.add(new Color(0.5f, 0.1f, 0.5f));
49 colorQueue.add(new Color(0.1f, 0.5f, 0.5f));
50 }
51
52 public void drawGraph(Graphics2D g) {
53
54 int currentLine = 0;
55 int maxColumn = 0;
56 g.translate(0, VisualisationTable.LINE_HEIGHT/2);
57 g.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));
58
59 Map<Commit, Color> commit_color = new HashMap<Commit, Color>();
60
61 for (Commit c : commits) {
62
63
64 int currentColumn = getColumnForCommit(c);
65
66
67 Color currentColor = null;
68 for (Commit suc : c.successors) {
69 if (suc.getBranch().equals(c.getBranch()))
70 currentColor = commit_color.get(suc);
71 }
72 if (currentColor == null)
73 currentColor = getNextColor();
74
75
76 for (Commit suc : c.successors) {
77
78
79 GeneralPath path = new GeneralPath();
80 int x = COLUMN_WIDTH * currentColumn + CIRCLE_DIAMETER / 2;
81 int y = VisualisationTable.LINE_HEIGHT * currentLine + CIRCLE_DIAMETER / 2;
82 path.moveTo(x, y);
83
84
85 if (!suc.getBranch().equals(c.getBranch()) && suc.predecessor.size() == 1)
86 g.setColor(commit_color.get(suc));
87 else
88 g.setColor(currentColor);
89
90
91 int endLine = commits.indexOf(suc);
92 int endColumn = commit_column.get(suc);
93
94
95 int column = currentColumn;
96 if (terminalCommits.contains(suc)) {
97
98 column = terminalCommits.indexOf(suc);
99 } else if (!terminalCommits.contains(c)) {
100
101
102
103 column = terminalCommits.size();
104 terminalCommits.add(null);
105 }
106 int line;
107 for (line = currentLine; line > endLine + 1; line--) {
108
109 drawConnectionTo(path, line - 1, column);
110 maxColumn = Math.max(maxColumn, column);
111 }
112 maxColumn = Math.max(maxColumn, column);
113 drawConnectionTo(path, endLine, endColumn);
114 g.draw(path);
115 }
116
117
118 terminalCommits.set(currentColumn, c);
119 commit_column.put(c, currentColumn);
120 commit_color.put(c, currentColor);
121
122
123 currentLine++;
124 }
125
126
127 for (int l = 0; l < commits.size(); l++) {
128 Commit c = commits.get(l);
129 g.setColor(commit_color.get(c));
130 int column = commit_column.get(c);
131 drawCircle(g, l, column);
132 }
133
134 g.translate(0, -VisualisationTable.LINE_HEIGHT/2);
135
136
137 dimension = new Dimension();
138 dimension.setSize((maxColumn+1) * COLUMN_WIDTH, commits.size()
139 * VisualisationTable.LINE_HEIGHT);
140
141 }
142
143
144
145
146 public Dimension2D getDimension() {
147 return dimension;
148 }
149
150 private void drawConnectionTo(GeneralPath path, int line,
151 int column) {
152
153 int x1 = (int) path.getCurrentPoint().getX();
154 int y1 = (int) path.getCurrentPoint().getY();
155 int x2 = COLUMN_WIDTH * column + CIRCLE_DIAMETER / 2;
156 int y2 = VisualisationTable.LINE_HEIGHT * line + CIRCLE_DIAMETER / 2;
157
158 if (x1 == x2) {
159
160 path.lineTo(x2, y2);
161 } else {
162
163 int curvedLineBase = (int) (VisualisationTable.LINE_HEIGHT * 0.7);
164 path.curveTo(x1, y1 - curvedLineBase, x2, y2 + curvedLineBase,
165 x2, y2);
166 }
167 }
168
169 private void drawCircle(Graphics2D g, int line, int column) {
170 g.fillOval(COLUMN_WIDTH * column, VisualisationTable.LINE_HEIGHT * line, CIRCLE_DIAMETER,
171 CIRCLE_DIAMETER);
172 }
173
174 private int getColumnForCommit(Commit c) {
175
176 int column = -1;
177
178
179 for (Commit suc : c.successors) {
180 if (terminalCommits.contains(suc) && suc.getBranch().equals(c.getBranch())) {
181 return terminalCommits.indexOf(suc);
182 }
183 }
184
185
186 for (Commit term : terminalCommits) {
187 boolean isReusable = true;
188
189
190 for (Commit term_pre : term.predecessor) {
191 if (commits.indexOf(term_pre) > commits.indexOf(c)) {
192 isReusable = false;
193 break;
194 }
195
196
197 for (Commit suc : c.successors) {
198 if (!terminalCommits.contains(suc) && (commits.indexOf(suc) < commits.indexOf(term_pre))) {
199 isReusable = false;
200 break;
201 }
202 }
203 if (!isReusable)
204 break;
205 }
206
207 if (isReusable)
208 {
209 return terminalCommits.indexOf(term);
210 }
211 }
212
213
214 if (column == -1) {
215 terminalCommits.add(c);
216 column = terminalCommits.indexOf(c);
217 }
218
219 return column;
220 }
221
222 private Color getNextColor() {
223 Color c = colorQueue.poll();
224 colorQueue.add(c);
225 return c;
226 }
227 }