# HG changeset patch # User Chris Cannam # Date 1289325072 0 # Node ID bed7ab59f62e16d87267e8c8ba7a1cc8561836e0 # Parent c32067cd19f8edcd580a98a41648f971d095ff7f * A snatched bit of work on graph layout diff -r c32067cd19f8 -r bed7ab59f62e changeset.h --- a/changeset.h Sun Nov 07 19:59:54 2010 +0000 +++ b/changeset.h Tue Nov 09 17:51:12 2010 +0000 @@ -13,6 +13,7 @@ Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged STORED true); Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged STORED true); Q_PROPERTY(QString branch READ branch WRITE setBranch NOTIFY branchChanged STORED true); + Q_PROPERTY(QString tag READ tag WRITE setTag NOTIFY tagChanged STORED true); Q_PROPERTY(QString date READ date WRITE setDate NOTIFY dateChanged STORED true); Q_PROPERTY(QString age READ age WRITE setAge NOTIFY ageChanged STORED true); Q_PROPERTY(QStringList parents READ parents WRITE setParents NOTIFY parentsChanged STORED true); @@ -24,6 +25,7 @@ QString id() const { return m_id; } QString author() const { return m_author; } QString branch() const { return m_branch; } + QString tag() const { return m_tag; } QString date() const { return m_date; } QString age() const { return m_age; } QStringList parents() const { return m_parents; } @@ -33,10 +35,16 @@ return id().split(':')[0].toInt(); } + QString authorName() const { + QString a = author(); + return a.replace(QRegExp("\\s*<[^>]*>"), ""); + } + signals: void idChanged(QString id); void authorChanged(QString author); void branchChanged(QString branch); + void tagChanged(QString tag); void dateChanged(QString date); void ageChanged(QString age); void parentsChanged(QStringList parents); @@ -46,6 +54,7 @@ void setId(QString id) { m_id = id; emit idChanged(id); } void setAuthor(QString author) { m_author = author; emit authorChanged(author); } void setBranch(QString branch) { m_branch = branch; emit branchChanged(branch); } + void setTag(QString tag) { m_tag = tag; emit tagChanged(tag); } void setDate(QString date) { m_date = date; emit dateChanged(date); } void setAge(QString age) { m_age = age; emit ageChanged(age); } void setParents(QStringList parents) { m_parents = parents; emit parentsChanged(parents); } @@ -55,6 +64,7 @@ QString m_id; QString m_author; QString m_branch; + QString m_tag; QString m_date; QString m_age; QStringList m_parents; diff -r c32067cd19f8 -r bed7ab59f62e changesetitem.cpp --- a/changesetitem.cpp Sun Nov 07 19:59:54 2010 +0000 +++ b/changesetitem.cpp Tue Nov 09 17:51:12 2010 +0000 @@ -14,7 +14,9 @@ ChangesetItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *option, QWidget *w) { - paint->drawText(50, 0, m_changeset->comment()); +// paint->drawText(50, 0, m_changeset->comment()); + paint->drawText(5, 15, m_changeset->authorName()); + paint->drawText(5, 30, m_changeset->branch()); paint->drawRect(QRectF(0, 0, 50, 50)); // paint->drawRect(QRectF(0, 0, 50, 50)); diff -r c32067cd19f8 -r bed7ab59f62e changesetitem.h --- a/changesetitem.h Sun Nov 07 19:59:54 2010 +0000 +++ b/changesetitem.h Tue Nov 09 17:51:12 2010 +0000 @@ -8,13 +8,20 @@ class ChangesetItem : public QGraphicsItem { public: - ChangesetItem(Changeset *cs) : m_changeset(cs) { } + ChangesetItem(Changeset *cs) : m_changeset(cs), m_column(0), m_row(0) { } virtual QRectF boundingRect() const; virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + int column() const { return m_column; } + int row() const { return m_row; } + void setColumn(int c) { m_column = c; } + void setRow(int r) { m_row = r; } + private: Changeset *m_changeset; + int m_column; + int m_row; }; #endif // CHANGESETITEM_H diff -r c32067cd19f8 -r bed7ab59f62e grapher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/grapher.cpp Tue Nov 09 17:51:12 2010 +0000 @@ -0,0 +1,87 @@ + +#include "grapher.h" + +#include +#include + +#include + +typedef QSet ColumnSet; +typedef QMap GridAlloc; +typedef QMap IdChangesetMap; +typedef QSet ChangesetSet; + +ChangesetItem * +layout(Changeset *cs, + IdChangesetMap idCsetMap, + ChangesetItemMap items, + GridAlloc &alloc, + ChangesetSet &handled) +{ + if (!cs) { + throw std::string("Null Changeset"); + } + if (!items.contains(cs)) { + throw std::string("Changeset not in item map"); + } + ChangesetItem *item = items[cs]; + if (handled.contains(cs)) { + return item; + } + int row = 0; + int col = 0; + if (!cs->parents().empty()) { + bool haveRow = false; + foreach (QString parentId, cs->parents()) { + if (parentId == "") continue; //!!! + std::cerr << "recursing to parent \"" << parentId.toStdString() << "\" of \"" << cs->id().toStdString() << "\"" << std::endl; + ChangesetItem *parentItem = + layout(idCsetMap[parentId], + idCsetMap, + items, + alloc, + handled); + if (!haveRow || parentItem->row() < row) { + row = parentItem->row(); + haveRow = true; + } + col += parentItem->column(); + } + col /= cs->parents().size(); + row = row - 1; + while (alloc[row].contains(col)) { + if (col > 0) col = -col; + else col = -col + 1; + } + alloc[row].insert(col); + } + item->setColumn(col); + item->setRow(row); + item->setX(col * 100); + item->setY(row * 100); + handled.insert(cs); + return item; +} + +void +Grapher::layout(Changesets csets, ChangesetItemMap items) +{ + IdChangesetMap idCsetMap; + foreach (Changeset *cs, csets) { + std::cerr << cs->id().toStdString() << std::endl; + if (cs->id() == "") { + throw std::string("Changeset has no ID"); + } + if (idCsetMap.contains(cs->id())) { + throw std::string("Changeset ID is already in map"); + } + idCsetMap[cs->id()] = cs; + } + + GridAlloc alloc; + ChangesetSet handled; + foreach (Changeset *cs, csets) { + ::layout(cs, idCsetMap, items, alloc, handled); + } +} + diff -r c32067cd19f8 -r bed7ab59f62e grapher.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/grapher.h Tue Nov 09 17:51:12 2010 +0000 @@ -0,0 +1,15 @@ +#ifndef GRAPHER_H +#define GRAPHER_H + +#include "changeset.h" +#include "changesetitem.h" + +typedef QMap ChangesetItemMap; + +class Grapher +{ +public: + void layout(Changesets csets, ChangesetItemMap items); +}; + +#endif diff -r c32067cd19f8 -r bed7ab59f62e hgexplorer.pro --- a/hgexplorer.pro Sun Nov 07 19:59:54 2010 +0000 +++ b/hgexplorer.pro Tue Nov 09 17:51:12 2010 +0000 @@ -1,3 +1,6 @@ + +CONFIG += debug + TEMPLATE = app TARGET = hgexplorer unix { @@ -7,6 +10,7 @@ HEADERS = mainwindow.h \ hgexpwidget.h \ common.h \ + grapher.h \ hgrunner.h \ settingsdialog.h \ changeset.h \ @@ -16,6 +20,7 @@ mainwindow.cpp \ hgexpwidget.cpp \ hgrunner.cpp \ + grapher.cpp \ settingsdialog.cpp \ common.cpp \ changeset.cpp \ diff -r c32067cd19f8 -r bed7ab59f62e hgexpwidget.cpp --- a/hgexpwidget.cpp Sun Nov 07 19:59:54 2010 +0000 +++ b/hgexpwidget.cpp Tue Nov 09 17:51:12 2010 +0000 @@ -11,6 +11,9 @@ #include "logparser.h" #include "changeset.h" #include "changesetitem.h" +#include "grapher.h" + +#include #define REMOTE_REPO_STR "Remote repository: " #define LOCAL_REPO_STR "Local repository: " @@ -245,12 +248,51 @@ gv->scene()->deleteLater(); QGraphicsScene *scene = new QGraphicsScene(); Changesets csets = parseChangeSets(hgLogList); + if (csets.empty()) return; + ChangesetItemMap csetItemMap; foreach (Changeset *cs, csets) { ChangesetItem *item = new ChangesetItem(cs); item->setX(0); - item->setY(cs->number() * 100); + item->setY(0); + csetItemMap[cs] = item; scene->addItem(item); } + try { + Grapher().layout(csets, csetItemMap); + } catch (std::string s) { + std::cerr << "Internal error: Layout failed: " << s << std::endl; + } +/* + QMap idCsetMap; + foreach (Changeset *cs, csets) { + if (cs->id() == "") { + throw std::string("Changeset has no ID"); + } + if (idCsetMap.contains(cs->id())) { + throw std::string("Changeset ID is already in map"); + } + idCsetMap[cs->id()] = cs; + } + typedef QSet ColumnSet; + typedef QMap GridAlloc; + typedef QMap ChangesetItemMap; + ChangesetItemMap csetItemMap; + foreach (Changeset *cs, csets) { + ChangesetItem *item = new ChangesetItem(cs); + item->setX(0); + item->setY(-cs->number() * 100); + csetItemMap[cs] = item; + scene->addItem(item); + } + QSet handled; + for (int i = csets.size() - 1; i >= 0; --i) { + Changeset *cs = csets[i]; + if (handled.contains(cs)) continue; + + + handled.insert(cs); + } +*/ gv->setScene(scene); } @@ -326,10 +368,24 @@ foreach (LogEntry e, log) { Changeset *cs = new Changeset(); foreach (QString key, e.keys()) { - cs->setProperty(key.toLocal8Bit().data(), e.value(key)); + if (key == "parents") { + QStringList parents = e.value(key).split + (" ", QString::SkipEmptyParts); + cs->setParents(parents); + } else { + cs->setProperty(key.toLocal8Bit().data(), e.value(key)); + } } csets.push_back(cs); } + for (int i = 0; i+1 < csets.size(); ++i) { + Changeset *cs = csets[i]; + if (cs->parents().empty()) { + QStringList list; + list.push_back(csets[i+1]->id()); + cs->setParents(list); + } + } return csets; } diff -r c32067cd19f8 -r bed7ab59f62e hgrunner.cpp --- a/hgrunner.cpp Sun Nov 07 19:59:54 2010 +0000 +++ b/hgrunner.cpp Tue Nov 09 17:51:12 2010 +0000 @@ -151,7 +151,7 @@ lastHgCommand = hgExePathAndName; lastParams = params.join(" "); - std::cerr << "HgRunner: starting: " << hgExePathAndName.toStdString(); + std::cerr << "HgRunner: starting: " << hgExePathAndName.toStdString() << " "; foreach (QString param, params) std::cerr << param.toStdString() << " "; std::cerr << std::endl; diff -r c32067cd19f8 -r bed7ab59f62e mainwindow.cpp --- a/mainwindow.cpp Sun Nov 07 19:59:54 2010 +0000 +++ b/mainwindow.cpp Tue Nov 09 17:51:12 2010 +0000 @@ -121,7 +121,7 @@ QStringList params; params << "log"; params << "--template"; - params << "id: {rev}:{node|short}\\nauthor: {author}\\nbranch: {branches}\\ndate: {date|isodate}\\nage: {date|age}\\nparents: {parents}\\ncomment: {desc|json}\\n\\n"; + params << "id: {rev}:{node|short}\\nauthor: {author}\\nbranch: {branches}\\ntag: {tag}\\ndate: {date|isodate}\\nage: {date|age}\\nparents: {parents}\\ncomment: {desc|json}\\n\\n"; runner -> startProc(getHgBinaryName(), workFolderPath, params); runningAction = ACT_LOG;