Mercurial > hg > easyhg
comparison grapher.cpp @ 185:ec2baee80833
* Some rather uncertain modifications to grapher logic for branch homes -- try to place branches close to their "parent branches".
Have also experimented with placing popular branches closer to the centre; neither is definitively better. Also, make changeset placement tend towards the branch home for the changeset
author | Chris Cannam |
---|---|
date | Sun, 19 Dec 2010 19:12:52 +0000 |
parents | 4bad3c5c053a |
children | 8fd71f570884 |
comparison
equal
deleted
inserted
replaced
184:1220f26d6f35 | 185:ec2baee80833 |
---|---|
21 #include "debug.h" | 21 #include "debug.h" |
22 #include "changesetscene.h" | 22 #include "changesetscene.h" |
23 | 23 |
24 #include <iostream> | 24 #include <iostream> |
25 | 25 |
26 int Grapher::findAvailableColumn(int row, int parent, bool preferParentCol) | 26 #include <QMultiMap> |
27 | |
28 int Grapher::findAvailableColumn(int row, int parent, int sign, | |
29 bool preferParentCol) | |
27 { | 30 { |
28 int col = parent; | 31 int col = parent; |
29 if (preferParentCol) { | 32 if (preferParentCol) { |
30 if (isAvailable(row, col)) return col; | 33 if (isAvailable(row, col)) return col; |
31 } | 34 } |
34 } | 37 } |
35 while (col < 0) { | 38 while (col < 0) { |
36 if (isAvailable(row, ++col)) return col; | 39 if (isAvailable(row, ++col)) return col; |
37 } | 40 } |
38 col = parent; | 41 col = parent; |
39 int sign = (col < 0 ? -1 : 1); | 42 if (sign == 0) { |
43 sign = (col < 0 ? -1 : 1); | |
44 } | |
40 while (1) { | 45 while (1) { |
41 col += sign; | 46 col += sign; |
42 if (isAvailable(row, col)) return col; | 47 if (isAvailable(row, col)) return col; |
43 } | 48 } |
44 } | 49 } |
140 ChangesetItem *item = m_items[id]; | 145 ChangesetItem *item = m_items[id]; |
141 | 146 |
142 int col = 0; | 147 int col = 0; |
143 int row = item->row(); | 148 int row = item->row(); |
144 QString branch = cs->branch(); | 149 QString branch = cs->branch(); |
150 int branchHome = m_branchHomes[branch]; | |
145 | 151 |
146 int nparents = cs->parents().size(); | 152 int nparents = cs->parents().size(); |
147 QString parentId; | 153 QString parentId; |
148 int parentsOnSameBranch = 0; | 154 int parentsOnSameBranch = 0; |
149 | 155 |
150 switch (nparents) { | 156 switch (nparents) { |
151 | 157 |
152 case 0: | 158 case 0: |
153 col = m_branchHomes[cs->branch()]; | 159 col = findAvailableColumn(row, branchHome, 0, true); |
154 col = findAvailableColumn(row, col, true); | |
155 break; | 160 break; |
156 | 161 |
157 case 1: | 162 case 1: |
158 parentId = cs->parents()[0]; | 163 parentId = cs->parents()[0]; |
159 | 164 |
163 col = m_branchHomes[branch]; | 168 col = m_branchHomes[branch]; |
164 } else { | 169 } else { |
165 col = m_items[parentId]->column(); | 170 col = m_items[parentId]->column(); |
166 } | 171 } |
167 | 172 |
168 col = findAvailableColumn(row, col, true); | 173 col = findAvailableColumn(row, col, branchHome - col, true); |
169 break; | 174 break; |
170 | 175 |
171 case 2: | 176 case 2: |
172 // a merge: behave differently if parents are both on the same | 177 // a merge: behave differently if parents are both on the same |
173 // branch (we also want to behave differently for nodes that | 178 // branch (we also want to behave differently for nodes that |
183 } | 188 } |
184 } | 189 } |
185 | 190 |
186 if (parentsOnSameBranch > 0) { | 191 if (parentsOnSameBranch > 0) { |
187 col /= parentsOnSameBranch; | 192 col /= parentsOnSameBranch; |
188 col = findAvailableColumn(item->row(), col, true); | 193 col = findAvailableColumn(item->row(), col, 0, true); |
189 } else { | 194 } else { |
190 col = findAvailableColumn(item->row(), col, false); | 195 col = findAvailableColumn(item->row(), col, 0, false); |
191 } | 196 } |
192 break; | 197 break; |
193 } | 198 } |
194 | 199 |
195 DEBUG << "putting " << cs->id().toStdString() << " at col " << col << endl; | 200 DEBUG << "putting " << cs->id().toStdString() << " at col " << col << endl; |
202 // given the same column as us (we already noted that its | 207 // given the same column as us (we already noted that its |
203 // connecting line would end at our row) | 208 // connecting line would end at our row) |
204 | 209 |
205 if (m_uncommittedParents.contains(id)) { | 210 if (m_uncommittedParents.contains(id)) { |
206 if (m_uncommittedParents[0] == id) { | 211 if (m_uncommittedParents[0] == id) { |
207 int ucol = findAvailableColumn(row-1, col, true); | 212 int ucol = findAvailableColumn(row-1, col, branchHome - col, true); |
208 m_uncommitted->setColumn(ucol); | 213 m_uncommitted->setColumn(ucol); |
209 m_haveAllocatedUncommittedColumn = true; | 214 m_haveAllocatedUncommittedColumn = true; |
210 } | 215 } |
211 // also, if the uncommitted item has a different branch from | 216 // also, if the uncommitted item has a different branch from |
212 // any of its parents, tell it to show the branch | 217 // any of its parents, tell it to show the branch |
256 if (special.size() == 2) { | 261 if (special.size() == 2) { |
257 DEBUG << "handling split-in-two for children " << special[0] << " and " << special[1] << endl; | 262 DEBUG << "handling split-in-two for children " << special[0] << " and " << special[1] << endl; |
258 for (int i = 0; i < 2; ++i) { | 263 for (int i = 0; i < 2; ++i) { |
259 int off = i * 2 - 1; // 0 -> -1, 1 -> 1 | 264 int off = i * 2 - 1; // 0 -> -1, 1 -> 1 |
260 ChangesetItem *it = m_items[special[i]]; | 265 ChangesetItem *it = m_items[special[i]]; |
261 it->setColumn(findAvailableColumn(it->row(), col + off, true)); | 266 it->setColumn(findAvailableColumn(it->row(), col + off, 0, true)); |
262 for (int r = row-1; r >= it->row(); --r) { | 267 for (int r = row-1; r >= it->row(); --r) { |
263 m_alloc[r].insert(it->column()); | 268 m_alloc[r].insert(it->column()); |
264 } | 269 } |
265 m_handled.insert(special[i]); | 270 m_handled.insert(special[i]); |
266 } | 271 } |
280 return true; | 285 return true; |
281 } | 286 } |
282 | 287 |
283 void Grapher::allocateBranchHomes(Changesets csets) | 288 void Grapher::allocateBranchHomes(Changesets csets) |
284 { | 289 { |
285 foreach (Changeset *cs, csets) { | 290 QMap<QString, int> branchCounts; |
291 QMap<QString, QString> branchParents; | |
292 | |
293 QStringList branches; | |
294 | |
295 foreach (Changeset *cs, csets) { | |
296 | |
286 QString branch = cs->branch(); | 297 QString branch = cs->branch(); |
298 | |
299 if (!branchCounts.contains(branch)) { | |
300 // Guess at the parent branch for this one which we | |
301 // haven't seen before. This is not entirely reliable, but | |
302 // it doesn't need to be | |
303 if (!cs->parents().empty()) { | |
304 QString firstParentId = cs->parents()[0]; | |
305 if (m_changesets.contains(firstParentId)) { | |
306 Changeset *firstParent = m_changesets[firstParentId]; | |
307 branchParents[branch] = firstParent->branch(); | |
308 } | |
309 } | |
310 branches.push_back(branch); | |
311 } | |
312 | |
313 branchCounts[branch]++; | |
314 | |
287 ChangesetItem *item = m_items[cs->id()]; | 315 ChangesetItem *item = m_items[cs->id()]; |
288 if (!item) continue; | 316 if (!item) continue; |
317 | |
289 int row = item->row(); | 318 int row = item->row(); |
290 if (!m_branchRanges.contains(branch)) { | 319 if (!m_branchRanges.contains(branch)) { |
291 m_branchRanges[branch] = Range(row, row); | 320 m_branchRanges[branch] = Range(row, row); |
292 } else { | 321 } else { |
293 Range p = m_branchRanges[branch]; | 322 Range p = m_branchRanges[branch]; |
297 } | 326 } |
298 } | 327 } |
299 | 328 |
300 m_branchHomes[""] = 0; | 329 m_branchHomes[""] = 0; |
301 m_branchHomes["default"] = 0; | 330 m_branchHomes["default"] = 0; |
302 | 331 /* |
303 foreach (QString branch, m_branchRanges.keys()) { | 332 QStringList orderedBranches; // will be ordered by "popularity" |
333 | |
334 QMultiMap<int, QString> branchesByCount; | |
335 foreach (QString branch, branchCounts.keys()) { | |
336 branchesByCount.insert(branchCounts[branch], branch); | |
337 } | |
338 foreach (QString branch, branchesByCount) { | |
339 orderedBranches.push_front(branch); | |
340 } | |
341 */ | |
342 int sign = -1; | |
343 | |
344 foreach (QString branch, branches) { | |
304 if (branch == "") continue; | 345 if (branch == "") continue; |
305 QSet<int> taken; | 346 QSet<int> taken; |
306 taken.insert(0); | 347 taken.insert(0); |
307 Range myRange = m_branchRanges[branch]; | 348 Range myRange = m_branchRanges[branch]; |
308 foreach (QString other, m_branchRanges.keys()) { | 349 foreach (QString other, m_branchRanges.keys()) { |
313 taken.insert(m_branchHomes[other]); | 354 taken.insert(m_branchHomes[other]); |
314 } | 355 } |
315 } | 356 } |
316 } | 357 } |
317 int home = 2; | 358 int home = 2; |
359 QString parent = branchParents[branch]; | |
360 if (parent != "" && parent != "default" && | |
361 m_branchHomes.contains(parent)) { | |
362 home = m_branchHomes[parent]; | |
363 if (home > 0) sign = 1; | |
364 else sign = -1; | |
365 } else { | |
366 sign = -sign; | |
367 } | |
318 while (taken.contains(home)) { | 368 while (taken.contains(home)) { |
319 if (home > 0) { | 369 home = home + 2 * sign; |
320 if (home % 2 == 1) { | |
321 home = -home; | |
322 } else { | |
323 home = home + 1; | |
324 } | |
325 } else { | |
326 if ((-home) % 2 == 1) { | |
327 home = home + 1; | |
328 } else { | |
329 home = -(home-2); | |
330 } | |
331 } | |
332 } | 370 } |
333 m_branchHomes[branch] = home; | 371 m_branchHomes[branch] = home; |
334 } | 372 } |
335 | 373 |
336 foreach (QString branch, m_branchRanges.keys()) { | 374 foreach (QString branch, branches) { |
337 DEBUG << branch.toStdString() << ": " << m_branchRanges[branch].first << " - " << m_branchRanges[branch].second << ", home " << m_branchHomes[branch] << endl; | 375 DEBUG << branch << ": pop " << branchCounts[branch] << ", parent " << branchParents[branch] << ", range " << m_branchRanges[branch].first << " - " << m_branchRanges[branch].second << ", home " << m_branchHomes[branch] << endl; |
338 } | 376 } |
339 } | 377 } |
340 | 378 |
341 static bool | 379 static bool |
342 compareChangesetsByDate(Changeset *const &a, Changeset *const &b) | 380 compareChangesetsByDate(Changeset *const &a, Changeset *const &b) |