Mercurial > hg > easyhg
diff grapher.cpp @ 145:644bd31e8301
* Include the uncommitted item in general graph layout (in case it is not at the head, when other items will need to avoid it)
author | Chris Cannam |
---|---|
date | Wed, 01 Dec 2010 17:41:14 +0000 |
parents | f61f032b06f9 |
children | 38faf16df9b6 |
line wrap: on
line diff
--- a/grapher.cpp Wed Dec 01 11:54:01 2010 +0000 +++ b/grapher.cpp Wed Dec 01 17:41:14 2010 +0000 @@ -27,24 +27,30 @@ { int col = parent; if (preferParentCol) { - if (!m_alloc[row].contains(col)) { - return col; - } + if (isAvailable(row, col)) return col; } while (col > 0) { - if (!m_alloc[row].contains(--col)) return col; + if (isAvailable(row, --col)) return col; } while (col < 0) { - if (!m_alloc[row].contains(++col)) return col; + if (isAvailable(row, ++col)) return col; } col = parent; int sign = (col < 0 ? -1 : 1); while (1) { col += sign; - if (!m_alloc[row].contains(col)) return col; + if (isAvailable(row, col)) return col; } } +bool Grapher::isAvailable(int row, int col) +{ + if (m_alloc.contains(row) && m_alloc[row].contains(col)) return false; + if (!m_haveAllocatedUncommittedColumn) return true; + if (!m_uncommitted) return true; + return !(row <= m_uncommittedParentRow && col == m_uncommitted->column()); +} + void Grapher::layoutRow(QString id) { if (m_handled.contains(id)) { @@ -102,6 +108,12 @@ m_rowDates[row] = date; } + // If we're the parent of the uncommitted item, make a note of our + // row (we need it later, to avoid overwriting the connecting line) + if (m_uncommittedParentId == id) { + m_uncommittedParentRow = row; + } + DEBUG << "putting " << cs->id().toStdString() << " at row " << row << endl; @@ -186,6 +198,15 @@ item->setColumn(col); m_handled.insert(id); + // If we're the parent of the uncommitted item, it should be given + // the same column as us (ideally) + + if (m_uncommittedParentId == id) { + int ucol = findAvailableColumn(row-1, col, true); + m_uncommitted->setColumn(ucol); + m_haveAllocatedUncommittedColumn = true; + } + // Normally the children will lay out themselves, but we can do // a better job in some special cases: @@ -306,39 +327,46 @@ } static bool - compareChangesetsByDate(Changeset *const &a, Changeset *const &b) +compareChangesetsByDate(Changeset *const &a, Changeset *const &b) { return a->timestamp() < b->timestamp(); } ChangesetItem * - Grapher::getItemFor(Changeset *cs) +Grapher::getItemFor(Changeset *cs) { if (!cs || !m_items.contains(cs->id())) return 0; return m_items[cs->id()]; } -void Grapher::layout(Changesets csets) +void Grapher::layout(Changesets csets, QString uncommittedSproutsFrom) { m_changesets.clear(); m_items.clear(); m_alloc.clear(); m_branchHomes.clear(); + m_uncommittedParentId = uncommittedSproutsFrom; + m_haveAllocatedUncommittedColumn = false; + m_uncommittedParentRow = 0; + m_uncommitted = 0; + DEBUG << "Grapher::layout: Have " << csets.size() << " changesets" << endl; if (csets.empty()) return; + // Create (but don't yet position) the changeset items + foreach (Changeset *cs, csets) { QString id = cs->id(); -// DEBUG << id.toStdString() << endl; if (id == "") { throw LayoutException("Changeset has no ID"); } if (m_changesets.contains(id)) { - DEBUG << "Duplicate changeset ID " << id << " in Grapher::layout()" << endl; + DEBUG << "Duplicate changeset ID " << id + << " in Grapher::layout()" << endl; throw LayoutException(QString("Duplicate changeset ID %1").arg(id)); } @@ -368,8 +396,20 @@ m_scene->addItem(conn); } } + + // Add uncommitted item and connecting line as necessary + + if (m_uncommittedParentId != "") { + m_uncommitted = new UncommittedItem(); + m_scene->addItem(m_uncommitted); + ConnectionItem *conn = new ConnectionItem(); + conn->setParent(m_items[m_uncommittedParentId]); + conn->setChild(m_uncommitted); + m_scene->addItem(conn); + } // Add the branch labels + foreach (Changeset *cs, csets) { QString id = cs->id(); ChangesetItem *item = m_items[id]; @@ -394,7 +434,8 @@ qStableSort(csets.begin(), csets.end(), compareChangesetsByDate); foreach (Changeset *cs, csets) { - DEBUG << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << endl; + DEBUG << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() + << ", date " << cs->datetime().toStdString() << endl; } m_handled.clear(); @@ -415,16 +456,10 @@ layoutCol(cs->id()); } - foreach (Changeset *cs, csets) { - ChangesetItem *item = m_items[cs->id()]; - if (!m_alloc[item->row()].contains(item->column()-1) && - !m_alloc[item->row()].contains(item->column()+1)) { - item->setWide(true); - } - } + // Find row and column extents. 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 - // 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; @@ -438,12 +473,44 @@ } } + // We've given the uncommitted item a column, but not a row yet -- + // it always goes at the top + + if (m_uncommitted) { + --minrow; + DEBUG << "putting uncommitted item at row " << minrow << endl; + m_uncommitted->setRow(minrow); + } + + // Changeset items that have nothing to either side of them can be + // made double-width + + foreach (Changeset *cs, csets) { + ChangesetItem *item = m_items[cs->id()]; + if (isAvailable(item->row(), item->column()-1) && + isAvailable(item->row(), item->column()+1)) { + item->setWide(true); + } + } + + if (m_uncommitted) { + if (isAvailable(m_uncommitted->row(), m_uncommitted->column()-1) && + isAvailable(m_uncommitted->row(), m_uncommitted->column()+1)) { + m_uncommitted->setWide(true); + } + } + QString prevDate; int changeRow = 0; bool even = false; int n = 0; + if (mincol == maxcol) { + --mincol; + ++maxcol; + } + for (int row = minrow; row <= maxrow; ++row) { QString date = m_rowDates[row];