comparison src/grapher.cpp @ 517:fb196c016a9f

More rigorous approach to finding the set of closed changesets
author Chris Cannam
date Thu, 20 Oct 2011 15:30:42 +0100
parents 2981d2defa61
children 533519ebc0cb
comparison
equal deleted inserted replaced
516:2981d2defa61 517:fb196c016a9f
375 { 375 {
376 if (!m_items.contains(id)) return 0; 376 if (!m_items.contains(id)) return 0;
377 return m_items[id]; 377 return m_items[id];
378 } 378 }
379 379
380 void
381 Grapher::markClosedChangesets()
382 {
383 // Ensure the closed branch changesets are all marked as closed.
384
385 QSet<QString> deferred;
386
387 foreach (QString id, m_closedIds) {
388 markClosedChangesetsFrom(id, deferred);
389 // std::cerr << "after closed id " << id << ": candidates now contains " << deferred.size() << " element(s)" << std::endl;
390 }
391
392 while (!deferred.empty()) {
393 foreach (QString id, deferred) {
394 markClosedChangesetsFrom(id, deferred);
395 deferred.remove(id);
396 // std::cerr << "after id " << id << ": deferred now contains " << deferred.size() << " element(s)" << std::endl;
397 }
398 }
399 }
400
401 void
402 Grapher::markClosedChangesetsFrom(QString id, QSet<QString> &deferred)
403 {
404 // A changeset should be marked as closed (i) if it is in the list
405 // of closed heads [and has no children]; or (ii) all of its
406 // children that have the same branch name as it are marked as
407 // closed [and there is at least one of those]
408
409 if (!m_changesets.contains(id)) {
410 // std::cerr << "no good" << std::endl;
411 return;
412 }
413
414 // std::cerr << "looking at id " << id << std::endl;
415
416 Changeset *cs = m_changesets[id];
417 QString branch = cs->branch();
418
419 bool closed = false;
420
421 if (m_closedIds.contains(id)) {
422
423 closed = true;
424
425 } else {
426
427 closed = false;
428 foreach (QString childId, cs->children()) {
429 if (!m_changesets.contains(childId)) {
430 continue;
431 }
432 Changeset *ccs = m_changesets[childId];
433 if (ccs->isOnBranch(branch)) {
434 if (ccs->closed()) {
435 // closed becomes true only when we see a closed
436 // child on the same branch
437 closed = true;
438 } else {
439 // and it becomes false as soon as we see any
440 // un-closed child on the same branch
441 closed = false;
442 break;
443 }
444 }
445 }
446 }
447
448 if (closed) {
449 // set closed on this cset and its direct simple parents
450 QString csid = id;
451 while (cs) {
452 cs->setClosed(true);
453 if (cs->parents().size() == 1) {
454 QString pid = cs->parents()[0];
455 if (!m_changesets.contains(pid)) break;
456 cs = m_changesets[pid];
457 if (cs->children().size() > 1) {
458 // std::cerr << "adding pid " << pid << " (it has more than one child)" << std::endl;
459 deferred.insert(pid); // examine later
460 cs = 0;
461 }
462 } else if (cs->parents().size() > 1) {
463 foreach (QString pid, cs->parents()) {
464 // std::cerr << "recursing to pid " << pid << " (it is one of multiple parents)" << std::endl;
465 markClosedChangesetsFrom(pid, deferred);
466 }
467 cs = 0;
468 } else {
469 cs = 0;
470 }
471 }
472 } else {
473 cs->setClosed(false);
474 }
475
476 // std::cerr << "finished with id " << id << std::endl;
477 }
478
380 void Grapher::layout(Changesets csets, 479 void Grapher::layout(Changesets csets,
381 QStringList uncommittedParents, 480 QStringList uncommittedParents,
382 QString uncommittedBranch) 481 QString uncommittedBranch)
383 { 482 {
384 m_changesets.clear(); 483 m_changesets.clear();
423 parent->addChild(id); 522 parent->addChild(id);
424 } 523 }
425 } 524 }
426 525
427 // Ensure the closed branch changesets are all marked as closed. 526 // Ensure the closed branch changesets are all marked as closed.
428 // A changeset should be marked as closed (i) if it is in the list 527
429 // of closed heads [and has no children]; or (ii) all of its 528 markClosedChangesets();
430 // children that have the same branch name as it are marked as
431 // closed [and there is at least one of those]
432
433 QStringList potentiallyClosed;
434 potentiallyClosed = QStringList::fromSet(m_closedIds);
435
436 while (!potentiallyClosed.empty()) {
437
438 QString id = *potentiallyClosed.begin();
439
440 if (m_changesets.contains(id)) {
441
442 Changeset *cs = m_changesets[id];
443 QString branch = cs->branch();
444
445 bool closed = false;
446
447 if (m_closedIds.contains(id)) {
448 closed = true;
449 } else {
450 closed = true;
451 foreach (QString childId, cs->children()) {
452 if (!m_changesets.contains(childId)) continue;
453 Changeset *ccs = m_changesets[childId];
454 if (ccs->isOnBranch(branch)) {
455 if (!ccs->closed()) {
456 closed = false;
457 break;
458 }
459 }
460 }
461 }
462
463 if (closed) {
464 // set closed on this cset and its direct simple parents
465 while (cs) {
466 cs->setClosed(true);
467 if (cs->parents().size() == 1) {
468 QString pid = cs->parents()[0];
469 if (!m_changesets.contains(pid)) break;
470 cs = m_changesets[pid];
471 if (cs->children().size() > 1) {
472 potentiallyClosed.push_back(pid); // examine later
473 cs = 0;
474 }
475 } else if (cs->parents().size() > 1) {
476 foreach (QString pid, cs->parents()) {
477 potentiallyClosed.push_back(pid); // examine later
478 }
479 cs = 0;
480 } else {
481 cs = 0;
482 }
483 }
484 }
485 }
486
487 potentiallyClosed.erase(potentiallyClosed.begin());
488 }
489 529
490 // Create (but don't yet position) the changeset items 530 // Create (but don't yet position) the changeset items
491 531
492 foreach (Changeset *cs, csets) { 532 foreach (Changeset *cs, csets) {
493 if (cs->closed() && !m_showClosedBranches) continue; 533 if (cs->closed() && !m_showClosedBranches) continue;