diff grapher.cpp @ 53:3c46b2ac45d3

* Put proper labels &c in changeset items; colour branches and users; etc
author Chris Cannam
date Fri, 12 Nov 2010 16:48:18 +0000
parents 384420567575
children 261bfb9481fe
line wrap: on
line diff
--- a/grapher.cpp	Fri Nov 12 11:32:01 2010 +0000
+++ b/grapher.cpp	Fri Nov 12 16:48:18 2010 +0000
@@ -1,6 +1,7 @@
 
 #include "grapher.h"
 #include "connectionitem.h"
+#include "dateitem.h"
 
 #include <QGraphicsScene>
 
@@ -43,7 +44,7 @@
     }
     Changeset *cs = m_changesets[id];
     ChangesetItem *item = m_items[id];
-    std::cerr << "Looking at " << id.toStdString() << std::endl;
+    std::cerr << "layoutRow: Looking at " << id.toStdString() << std::endl;
 
     int row = 0;
     int nparents = cs->parents().size();
@@ -73,11 +74,8 @@
     // above all nodes that have earlier dates (to the nearest day).
     // m_rowDates maps each row to a date: use that.
 
-    QString date = cs->date();
-
-    // n.b. this relies on the fact that the date component of an ISO
-    // date/time sorts correctly in a dictionary sort
-    while (m_rowDates.contains(row) && m_rowDates[row] < date) {
+    QString date = cs->age();
+    while (m_rowDates.contains(row) && m_rowDates[row] != date) {
 	--row;
     }
 
@@ -110,22 +108,11 @@
     if (!m_items.contains(id)) {
 	throw LayoutException(QString("Changeset %1 not in item map").arg(id));
     }
+
     Changeset *cs = m_changesets[id];
+    std::cerr << "layoutCol: Looking at " << id.toStdString() << std::endl;
+
     ChangesetItem *item = m_items[id];
-    std::cerr << "Looking at " << id.toStdString() << std::endl;
-
-    foreach (QString parentId, cs->parents()) {
-	if (!m_changesets.contains(parentId)) continue;
-	if (!m_handled.contains(parentId)) {
-	    layoutCol(parentId);
-	}
-    }
-
-    // Parent may have layed out child in the recursive call
-    if (m_handled.contains(id)) {
-	std::cerr << "Looks like we've dealt with " << id.toStdString() << std::endl;
-	return;
-    }
 
     int col = 0;
     int row = item->row();
@@ -191,19 +178,19 @@
 
     int nchildren = cs->children().size();
 
-    // look for merging children and make sure nobody
-    // is going to overwrite their "merge lines" if they extend further
-    // than a single step
+    // look for merging children and children distant from us but in a
+    // straight line, and make sure nobody is going to overwrite their
+    // connection lines
 
     foreach (QString childId, cs->children()) {
         if (!m_changesets.contains(childId)) continue;
         Changeset *child = m_changesets[childId];
-        if (child->parents().size() > 1) {
-            int childRow = m_items[childId]->row();
+	int childRow = m_items[childId]->row();
+        if (child->parents().size() > 1 || child->branch() == cs->branch()) {
             for (int r = row; r > childRow; --r) {
                 m_alloc[r].insert(col);
             }
-        }
+	}	    
     }
 
     // look for the case where exactly two children have the same
@@ -224,8 +211,11 @@
 	    for (int i = 0; i < 2; ++i) {
 		int off = i * 2 - 1; // 0 -> -1, 1 -> 1
 		ChangesetItem *it = m_items[special[i]];
+		m_alloc[it->row()].insert(col); // avoid our column
 		it->setColumn(findAvailableColumn(it->row(), col + off, true));
-		m_alloc[it->row()].insert(it->column());
+		for (int r = row; r >= it->row(); --r) {
+		    m_alloc[r].insert(it->column());
+		}
 		m_handled.insert(special[i]);
 	    }
 	}
@@ -279,10 +269,21 @@
 		}
 	    }
 	}
-	int home = 3;
+	int home = 2;
 	while (taken.contains(home)) {
-	    if (home > 0) home = -home;
-	    else home = -(home-3);
+	    if (home > 0) {
+		if (home % 2 == 1) {
+		    home = -home;
+		} else {
+		    home = home + 1;
+		}
+	    } else {
+		if ((-home) % 2 == 1) {
+		    home = home + 1;
+		} else {
+		    home = -(home-2);
+		}
+	    }
 	}
 	m_branchHomes[branch] = home;
     }
@@ -298,6 +299,13 @@
     return a->timestamp() < b->timestamp();
 }
 
+ChangesetItem *
+Grapher::getItemFor(Changeset *cs)
+{
+    if (!cs || !m_items.contains(cs->id())) return 0;
+    return m_items[cs->id()];
+}
+
 void
 Grapher::layout(Changesets csets)
 {
@@ -306,6 +314,8 @@
     m_alloc.clear();
     m_branchHomes.clear();
 
+    if (csets.empty()) return;
+
     foreach (Changeset *cs, csets) {
 
 	QString id = cs->id();
@@ -330,11 +340,13 @@
     foreach (Changeset *cs, csets) {
 	QString id = cs->id();
 	ChangesetItem *item = m_items[id];
+	bool merge = (cs->parents().size() > 1);
 	foreach (QString parentId, cs->parents()) {
 	    if (!m_changesets.contains(parentId)) continue;
 	    Changeset *parent = m_changesets[parentId];
 	    parent->addChild(id);
 	    ConnectionItem *conn = new ConnectionItem();
+	    if (merge) conn->setConnectionType(ConnectionItem::Merge);
 	    conn->setChild(item);
 	    conn->setParent(m_items[parentId]);
 	    m_scene->addItem(conn);
@@ -350,16 +362,80 @@
 
     qStableSort(csets.begin(), csets.end(), compareChangesetsByDate);
 
+    foreach (Changeset *cs, csets) {
+	std::cerr << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << std::endl;
+    }
+
     m_handled.clear();
-    for (int i = csets.size() - 1; i >= 0; --i) {
-	layoutRow(csets[i]->id());
+    foreach (Changeset *cs, csets) {
+	layoutRow(cs->id());
     }
 
     allocateBranchHomes(csets);
 
     m_handled.clear();
-    for (int i = csets.size() - 1; i >= 0; --i) {
-	layoutCol(csets[i]->id());
+    foreach (Changeset *cs, csets) {
+	foreach (QString parentId, cs->parents()) {
+	    if (!m_handled.contains(parentId) &&
+		m_changesets.contains(parentId)) {
+		layoutCol(parentId);
+	    }
+	}
+	layoutCol(cs->id());
+    }
+
+    // we know that 0 is an upper bound on row, and that mincol must
+    // be <= 0 and maxcol >= 0, so these initial values are good
+    int minrow = 0, maxrow = 0;
+    int mincol = 0, maxcol = 0;
+
+    foreach (int r, m_alloc.keys()) {
+	if (r < minrow) minrow = r;
+	if (r > maxrow) maxrow = r;
+	ColumnSet &c = m_alloc[r];
+	foreach (int i, c) {
+	    if (i < mincol) mincol = i;
+	    if (i > maxcol) maxcol = i;
+	}
+    }
+
+    QString prevDate;
+    int changeRow = 0;
+
+    bool even = false;
+    int n = 0;
+
+    for (int row = minrow; row <= maxrow; ++row) {
+	
+	QString date = m_rowDates[row];
+	n++;
+
+	if (date != prevDate) {
+	    if (prevDate != "") {
+		DateItem *item = new DateItem();
+		item->setDateString(prevDate);
+		item->setCols(mincol, maxcol - mincol + 1);
+		item->setRows(changeRow, n);
+		item->setEven(even);
+		item->setZValue(-1);
+		m_scene->addItem(item);
+		even = !even;
+	    }
+	    prevDate = date;
+	    changeRow = row;
+	    n = 0;
+	}
+    }
+    
+    if (n > 0) {
+	DateItem *item = new DateItem();
+	item->setDateString(prevDate);
+	item->setCols(mincol, maxcol - mincol + 1);
+	item->setRows(changeRow, n+1);
+	item->setEven(even);
+	item->setZValue(-1);
+	m_scene->addItem(item);
+	even = !even;
     }
 }