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)