# # # patch "guitone.pro" # from [3352f5d1507c2b8457752575d3e272374316ace7] # to [0a98c582be515a25ee8e4836dc27599838ee4aab] # # patch "res/forms/changeset_browser.ui" # from [64a1b1692f5405c6e94da3a7b99b56f78cd8dade] # to [29092bf3f19af54915933b96152c650dca3c8852] # # patch "src/model/Certs.cpp" # from [8b011be58c9224fb726884374bd3d4941a8c7e36] # to [65d19b8cee3f481aeb0231bf3485b0081e8c714c] # # patch "src/model/Certs.h" # from [187ae7a01ea9ccfe8467875bfe906f4a9f174790] # to [38d6b983c32cbc5bc3cf1bd8096700a7d9269d8d] # # patch "src/model/ChangesetModel.cpp" # from [d2d1f6b94d41e49a6d8127dc110bf02261e54a7d] # to [5c919ba5536d689a10ac6c51c626409a335e8391] # # patch "src/model/ChangesetModel.h" # from [df69879143ce5d16baf7cf7a36f466cd971c6281] # to [bdf89016474dd615bb7f32a80f8ed0044daa32a0] # # patch "src/model/Graph.cpp" # from [fa58d4e3fd6ebe3f1beb05a9682b7efced6ffed1] # to [67916de194bbcb0710dc86888548d2abd23ef003] # # patch "src/model/Graph.h" # from [12331956dd8457649a45dbfe59f4f10b48676d9d] # to [ffc22c50630e7867b6d04028d5c01ddb8b862e7b] # # patch "src/view/MainWindow.cpp" # from [e1e2577bbcce3b8beaa16dd8c855f89b62f18358] # to [7c65de44d72db4d0c74d3a0ddfad0b6bfda5d848] # # patch "src/view/dialogs/ChangesetBrowser.cpp" # from [bb4313d6d73e7cf525442755c01ec05445958927] # to [dc56fe1e42b00ae9ae49f359644f8ed25d6b0829] # # patch "src/view/dialogs/ChangesetBrowser.h" # from [702cb80e34ccd1dd8d17521a4ade28b50743ca14] # to [cc91ca9a24b3f694eb60ace982cc0fc0e4a6bbe0] # ============================================================ --- guitone.pro 3352f5d1507c2b8457752575d3e272374316ace7 +++ guitone.pro 0a98c582be515a25ee8e4836dc27599838ee4aab @@ -86,6 +86,7 @@ HEADERS = src/view/TreeView.h \ src/model/GetRevision.h \ src/model/GetContentChanged.h \ src/model/GetDatabaseVariables.h \ + src/model/Graph.h \ src/util/IconProvider.h \ src/util/AbstractParser.h \ src/util/BasicIOParser.h \ @@ -165,6 +166,7 @@ SOURCES += src/view/TreeView.cpp \ src/model/GetRevision.cpp \ src/model/GetContentChanged.cpp \ src/model/GetDatabaseVariables.cpp \ + src/model/Graph.cpp \ src/util/IconProvider.cpp \ src/util/AbstractParser.cpp \ src/util/BasicIOParser.cpp \ ============================================================ --- res/forms/changeset_browser.ui 64a1b1692f5405c6e94da3a7b99b56f78cd8dade +++ res/forms/changeset_browser.ui 29092bf3f19af54915933b96152c650dca3c8852 @@ -115,33 +115,6 @@ - - - all Changesets - - - - - - - 50 More Changesets - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - close ============================================================ --- src/model/Certs.cpp 8b011be58c9224fb726884374bd3d4941a8c7e36 +++ src/model/Certs.cpp 65d19b8cee3f481aeb0231bf3485b0081e8c714c @@ -48,83 +48,8 @@ void Certs::processTaskResult(const Mono return; } - BasicIOParser parser(task.getOutputUtf8()); - I(parser.parse()); - StanzaList list = parser.getStanzas(); + certs = parseCerts(task.getOutputUtf8()); - for (int i=0, size = list.size(); i < size; ++i) - { - Stanza stanza = list.at(i); - - Cert cert; - - bool isItem = false; - - for (int j=0, size2 = stanza.size(); j < size2; j++) - { - StanzaEntry entry = stanza.at(j); - - // we're now only interested in stanzas starting with a "key" entry - if (j == 0 && entry.sym != "key") break; - - isItem = true; - - if (entry.sym == "key") - { - I(entry.vals.size() == 1); - cert.key = entry.vals.at(0); - continue; - } - - if (entry.sym == "name") - { - I(entry.vals.size() == 1); - cert.name = entry.vals.at(0); - continue; - } - - if (entry.sym == "value") - { - I(entry.vals.size() == 1); - cert.value = entry.vals.at(0).trimmed(); - continue; - } - - if (entry.sym == "signature") - { - I(entry.vals.size() == 1); - QString sig = entry.vals.at(0); - - if (sig == "ok") cert.signature = Cert::Ok; - else if (sig == "bad") cert.signature = Cert::Bad; - else if (sig == "unknown") cert.signature = Cert::Unknown; - else - W(QString("Unknown cert signature state '%1'.").arg(sig)); - - continue; - } - - if (entry.sym == "trust") - { - I(entry.vals.size() == 1); - QString trust = entry.vals.at(0); - - if (trust == "trusted") cert.trust = Cert::Trusted; - else if (trust == "untrusted") cert.trust = Cert::Untrusted; - else - W(QString("Unknown cert trust '%1'.").arg(trust)); - - continue; - } - - W(QString("Unknown symbol %1.").arg(entry.sym)); - } - - // check if we really processed an item entry - if (!isItem) continue; - certs.append(cert); - } - // reset any connected view(s) reset(); @@ -234,3 +159,85 @@ void Certs::clearData() reset(); } +CertList Certs::parseCerts(const QString & input) +{ + BasicIOParser parser(input); + I(parser.parse()); + StanzaList list = parser.getStanzas(); + + CertList certs; + for (int i=0, size = list.size(); i < size; ++i) + { + Stanza stanza = list.at(i); + + Cert cert; + + bool isItem = false; + + for (int j=0, size2 = stanza.size(); j < size2; j++) + { + StanzaEntry entry = stanza.at(j); + + // we're now only interested in stanzas starting with a "key" entry + if (j == 0 && entry.sym != "key") break; + + isItem = true; + + if (entry.sym == "key") + { + I(entry.vals.size() == 1); + cert.key = entry.vals.at(0); + continue; + } + + if (entry.sym == "name") + { + I(entry.vals.size() == 1); + cert.name = entry.vals.at(0); + continue; + } + + if (entry.sym == "value") + { + I(entry.vals.size() == 1); + cert.value = entry.vals.at(0).trimmed(); + continue; + } + + if (entry.sym == "signature") + { + I(entry.vals.size() == 1); + QString sig = entry.vals.at(0); + + if (sig == "ok") cert.signature = Cert::Ok; + else if (sig == "bad") cert.signature = Cert::Bad; + else if (sig == "unknown") cert.signature = Cert::Unknown; + else + W(QString("Unknown cert signature state '%1'.").arg(sig)); + + continue; + } + + if (entry.sym == "trust") + { + I(entry.vals.size() == 1); + QString trust = entry.vals.at(0); + + if (trust == "trusted") cert.trust = Cert::Trusted; + else if (trust == "untrusted") cert.trust = Cert::Untrusted; + else + W(QString("Unknown cert trust '%1'.").arg(trust)); + + continue; + } + + W(QString("Unknown symbol %1.").arg(entry.sym)); + } + + // check if we really processed an item entry + if (!isItem) continue; + certs.append(cert); + } + return certs; +} + ============================================================ --- src/model/Certs.h 187ae7a01ea9ccfe8467875bfe906f4a9f174790 +++ src/model/Certs.h 38d6b983c32cbc5bc3cf1bd8096700a7d9269d8d @@ -31,6 +31,7 @@ public: Certs(QObject *, const DatabaseFile &); virtual ~Certs(); void clearData(); + static CertList parseCerts(const QString &); // needed Qt Model methods QVariant data(const QModelIndex&, int) const; ============================================================ --- src/model/ChangesetModel.cpp d2d1f6b94d41e49a6d8127dc110bf02261e54a7d +++ src/model/ChangesetModel.cpp 5c919ba5536d689a10ac6c51c626409a335e8391 @@ -20,85 +20,42 @@ ChangesetModel::ChangesetModel(QObject * #include ChangesetModel::ChangesetModel(QObject * parent, const DatabaseFile & db) - : QAbstractItemModel(parent), databaseFile(db), currentBranch(""), branchLog(0) -{} - -ChangesetModel::~ChangesetModel() {} - -void ChangesetModel::receiveRevisions(bool all) + : QAbstractItemModel(parent), databaseFile(db), currentBranch("") { - int i = branchMap[currentBranch].certsRead; - int to = branchMap[currentBranch].revisions.count(); - int c = 0; + graph = new Graph(db); + graph->readGraph(); - while (i < to && (c < revPerReceive || all)) - { - QString revision = branchMap[currentBranch].revisions[i]; + connect( + graph, SIGNAL(lineFinished(const QString &)), + this, SLOT(lineFinished(const QString &)) + ); +} - if (!changesetMap.contains(revision)) - { - ChangesetCerts * certs = new ChangesetCerts(this, databaseFile); - connect( - certs, SIGNAL(changesetReady(const Changeset &)), - this, SLOT(changesetReady(const Changeset &)) - ); - certs->readCerts(revision); - c++; - } - i++; - } +ChangesetModel::~ChangesetModel() +{ + delete graph; } void ChangesetModel::setBranch(const QString & branch) { - currentBranch = branch; + revisionOrder = QStringList(); + reset(); - if (branchMap[currentBranch].revisions.count() == 0) - { - branchMap[currentBranch].certsRead = 0; + currentBranch = branch; - if (branchLog) - { - disconnect( - branchLog, SIGNAL(branchLogRead(const QString &, const QStringList &)), - this, SLOT(branchLogRead(const QString &, const QStringList &)) - ); - delete branchLog; - } - - branchLog = new GetBranchLog(this, databaseFile, branch); - connect( - branchLog, SIGNAL(branchLogRead(const QString &, const QStringList &)), - this, SLOT(branchLogRead(const QString &, const QStringList &)) - ); - } - else - { - // just reset the view if we already have queried data - // for this particular branch - reset(); - } + graph->buildLanesForBranch(currentBranch); } -void ChangesetModel::branchLogRead(const QString & branch, const QStringList & revisions) +void ChangesetModel::lineFinished(const QString & rev) { - branchMap[branch].revisions += revisions; - - if (branch == currentBranch) - { - receiveRevisions(false); - } -} - -void ChangesetModel::changesetReady(const Changeset & change) -{ + D(QString("new rev %1 added").arg(rev)); + int newIndex = revisionOrder.size(); beginInsertRows( QModelIndex(), - branchMap[currentBranch].certsRead, - branchMap[currentBranch].certsRead + newIndex, + newIndex ); - changesetMap[change.revision] = change; - branchMap[currentBranch].certsRead += 1; + revisionOrder.push_back(rev); endInsertRows(); } @@ -125,36 +82,27 @@ QVariant ChangesetModel::data(const QMod if (role == Qt::UserRole) { - BranchInfo branchInfo = branchMap[currentBranch]; int row = index.row(); - QString rev = branchInfo.revisions[row]; - if (!changesetMap.contains(rev)) return QVariant(); - return QVariant(changesetMap[rev].htmllog()); + QString rev = revisionOrder[row]; + return QVariant(graph->getRevision(rev)->htmllog); } if (role == Qt::DisplayRole) { - BranchInfo branchInfo = branchMap[currentBranch]; int row = index.row(); + if (row >= revisionOrder.size()) return QVariant(); - if (branchInfo.revisions.count() > row) + RevisionData * rev = graph->getRevision(revisionOrder[row]); + switch(index.column()) { - int col = index.column(); - QString rev = branchInfo.revisions[row]; - - if (!changesetMap.contains(rev)) return QVariant(); - - switch(col) - { - case(0): - return QVariant(changesetMap[rev].date); - case(1): - return QVariant(changesetMap[rev].author); - case(2): - return QVariant(changesetMap[rev].plainlog()); - case(3): - return QVariant(rev); - } + case(0): + return QVariant(rev->date); + case(1): + return QVariant(rev->author); + case(2): + return QVariant(rev->plainlog); + case(3): + return QVariant(rev->hash); } } @@ -192,21 +140,18 @@ int ChangesetModel::rowCount(const QMode int ChangesetModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent); - if (branchMap[currentBranch].revisions.count() > 0) - { - return branchMap[currentBranch].certsRead; - } - return 0; + return revisionOrder.size(); } QModelIndex ChangesetModel::index(int row, int column, const QModelIndex & parent) const { - if (!hasIndex(row, column, parent)) + if (!hasIndex(row, column, parent) || row >= revisionOrder.size()) { return QModelIndex(); } - return createIndex(row, column, 0); + RevisionData * rev = graph->getRevision(revisionOrder[row]); + return createIndex(row, column, rev); } QModelIndex ChangesetModel::parent(const QModelIndex & index) const ============================================================ --- src/model/ChangesetModel.h df69879143ce5d16baf7cf7a36f466cd971c6281 +++ src/model/ChangesetModel.h bdf89016474dd615bb7f32a80f8ed0044daa32a0 @@ -1,6 +1,6 @@ /*************************************************************************** - * Copyright (C) 2006 by Jean-Louis Fuchs * - * address@hidden * + * Copyright (C) 2006 by Jean-Louis Fuchs * + * Copyright (C) 2007 by Thomas Keller * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -8,7 +8,7 @@ * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; withhtmllog even the implied warranty of * + * but WITHOUT ANY WARRANTY; withhtmllog even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * @@ -20,160 +20,17 @@ #define CHANGESETMODEL_H #include "Certs.h" -#include "GetBranchLog.h" +#include "Graph.h" -#include -#include - -struct BranchInfo -{ - QStringList revisions; - int certsRead; -}; - -struct Changeset -{ - QString revision; - QDateTime date; - QString author; - QString changelog; - - QString htmllog() const - { - QStringList lines = changelog.split(QRegExp("(\\r\\n|\\n|\\n\\r)")); - QString htmllog; - bool inList = false; - - foreach (QString line, lines) - { - if (line.isEmpty()) - { - if (inList) - { - htmllog += "\n\n"; - inList = false; - continue; - } - - htmllog += "
\n"; - continue; - } - - bool listStart = (0 == line.indexOf(QRegExp("^[*-]"))); - if (listStart) - { - if (inList) - { - htmllog += "\n"; - } - else - { - inList = true; - htmllog += "
    \n"; - } - - htmllog += "
  • " + line.mid(1).trimmed(); - continue; - } - - if (inList) - { - htmllog += " " + line.trimmed(); - continue; - } - - htmllog += line.trimmed() + "
    \n"; - } - - if (inList) - { - htmllog += "
  • \n
\n"; - } - - htmllog = htmllog - .replace(QRegExp("(\\b)([_])(\\w+)\\2"), "\\1\\2\\3\\2") - .replace(QRegExp("(\\b)([*])(\\w+)\\2"), "\\1\\2\\3\\2") - .replace(QRegExp("(https?://[^() ]+)"), "\\1") - .replace(QRegExp("\\t"), "    "); - - return htmllog; - } - - QString plainlog() const - { - QString plainlog = changelog; - return plainlog.replace(QRegExp("\\s+"), " "); - } -}; - -class ChangesetCerts : public Certs -{ - Q_OBJECT -public: - ChangesetCerts(QObject * parent, const DatabaseFile & db) : Certs(parent, db) - { - connect( - this, SIGNAL(certsRead(const CertList &)), - this, SLOT(packIntoChangeset()) - ); - } - void readCerts(const QString & rev) - { - revision = rev; - Certs::readCerts(rev); - } - -signals: - void changesetReady(const Changeset &); - -private slots: - void packIntoChangeset() - { - Changeset change; - change.revision = revision; - - // FIXME: there is no support for multiple certs with the same - // key, i.e. accidential clean merges or multiple author certs - for (int i=0, j=certs.size(); i ChangesetMap; -typedef QMap BranchMap; - class ChangesetModel : public QAbstractItemModel { Q_OBJECT public: - ChangesetMap branchModel; ChangesetModel(QObject *, const DatabaseFile &); ~ChangesetModel(); void setBranch(const QString & branch); - void receiveRevisions(bool); // needed Qt Model methods QVariant data(const QModelIndex &, int) const; @@ -185,17 +42,13 @@ private: int columnCount(const QModelIndex &) const; private: - static const int revPerReceive = 50; - DatabaseFile databaseFile; QString currentBranch; - BranchMap branchMap; - ChangesetMap changesetMap; - GetBranchLog * branchLog; + QStringList revisionOrder; + Graph * graph; private slots: - void branchLogRead(const QString &, const QStringList &); - void changesetReady(const Changeset &); + void lineFinished(const QString &); }; #endif ============================================================ --- src/model/Graph.cpp fa58d4e3fd6ebe3f1beb05a9682b7efced6ffed1 +++ src/model/Graph.cpp 67916de194bbcb0710dc86888548d2abd23ef003 @@ -17,7 +17,120 @@ ***************************************************************************/ #include "Graph.h" +#include "Certs.h" +static void +revlist_info(const QString & label, const QStringList & revs) +{ + QString out; + foreach (QString rev, revs) + { + out.append(rev.left(4)).append(" | "); + } + D(QString("%1: %2").arg(label).arg(out)); +} + +void RevisionData::normalizeCerts(const CertList & certs) +{ + QStringList changelogList; + QStringList dateList; + QStringList authorList; + + foreach (Cert c, certs) + { + if (c.name == "changelog") + { + changelogList.push_back(c.value); + continue; + } + + if (c.name == "date") + { + dateList.push_back( + QDateTime::fromString(c.value, "yyyy-MM-ddThh:mm:ss") + .toString(Qt::SystemLocaleShortDate )); + continue; + } + + if (c.name == "author") + { + authorList.push_back(c.value); + continue; + } + } + + date = dateList.join(", "); + author = authorList.join(", "); + QString changelog = changelogList.join("\n---\n"); + + // + // prepare the plain log + // + plainlog = changelog; + plainlog.replace(QRegExp("\\s+"), " "); + + // + // prepare the html log + // + htmllog = QString(); + bool inList = false; + QStringList lines = changelog.split(QRegExp("(\\r\\n|\\n|\\n\\r)")); + + foreach (QString line, lines) + { + if (line.isEmpty()) + { + if (inList) + { + htmllog += "\n\n"; + inList = false; + continue; + } + + htmllog += "
\n"; + continue; + } + + bool listStart = (0 == line.indexOf(QRegExp("^[*-]"))); + if (listStart) + { + if (inList) + { + htmllog += "\n"; + } + else + { + inList = true; + htmllog += "
    \n"; + } + + htmllog += "
  • " + line.mid(1).trimmed(); + continue; + } + + if (inList) + { + htmllog += " " + line.trimmed(); + continue; + } + + htmllog += line.trimmed() + "
    \n"; + } + + if (inList) + { + htmllog += "
  • \n
\n"; + } + + htmllog = htmllog + .replace(QRegExp("(\\b)([_])(\\w+)\\2"), "\\1\\2\\3\\2") + .replace(QRegExp("(\\b)([*])(\\w+)\\2"), "\\1\\2\\3\\2") + .replace(QRegExp("(https?://[^() ]+)"), "\\1") + .replace(QRegExp("\\t"), "    "); + + certsQueried = true; +} + Graph::Graph(const DatabaseFile & db) : databaseFile(db) {}; Graph::~Graph() {}; @@ -30,12 +143,18 @@ void Graph::readGraph() ); } -void Graph::filterBranch(const QString & branch) +void Graph::buildLanesForBranch(const QString & branch) { + if (topsortedRevs.contains(branch)) + { + buildLanes(topsortedRevs.value(branch)); + return; + } + AutomateCommand::enqueueDatabaseTask( - databaseFile, - MonotoneTask(QStringList() << "select" << "b:"+branch) - ); + databaseFile, + MonotoneTask(QStringList() << "select" << "b:"+branch) + ); } void Graph::processTaskResult(const MonotoneTask & task) @@ -58,20 +177,19 @@ void Graph::processTaskResult(const Mono { QStringList revisions = revisionList.split(" ", QString::SkipEmptyParts); QString rev = revisions.takeFirst(); - I(revisionMap.contains(rev)); - Revision * r = new Revision(); + RevisionData * r = new RevisionData(); revisionMap.insert(rev, r); r->hash = rev; r->parents = revisions; } - QMapIterator it(revisionMap); + QMapIterator it(revisionMap); while (it.hasNext()) { it.next(); - Revision * r = it.value(); + RevisionData * r = it.value(); foreach (QString parent, r->parents) { I(revisionMap.contains(parent)); @@ -81,9 +199,9 @@ void Graph::processTaskResult(const Mono return; } - if (cmd == "branch") + if (cmd == "select") { - QString branch = QString(task.getArguments().at(1)); + QString branch = task.getArguments().at(1).split(':').at(1); QStringList revisions = output.split("\n", QString::SkipEmptyParts); foreach (QString rev, revisions) @@ -91,33 +209,40 @@ void Graph::processTaskResult(const Mono I(revisionMap.contains(rev)); revisionMap[rev]->branches.append(branch); } - - currentBranch = branch; - - AutomateCommand::enqueueDatabaseTask( - databaseFile, - QStringList() << "heads" << branch - ); return; } if (cmd == "heads") { QString branch = QString(task.getArguments().at(1)); - QStringList heads = output.split("\n", QString::SkipEmptyParts); + const QStringList heads = output.split("\n", QString::SkipEmptyParts); branchHeads.insert(branch, heads); - buildLanes(heads, QStringList()); + buildLanes(heads); return; } + + if (cmd == "certs") + { + QString rev = QString(task.getArguments().at(1)); + I(revisionMap.contains(rev)); + revisionMap.value(rev)->normalizeCerts(Certs::parseCerts(task.getOutputUtf8())); + emit lineFinished(rev); + } } +void Graph::buildLanes(const QStringList & heads) +{ + revisionOrder = QStringList(); + QStringList startRevisions(heads); + buildLanes(startRevisions, QStringList()); +} + void Graph::buildLanes(QStringList & newRevisions, const QStringList & lastRevisions) { - QString rev = newRevisions.takeFirst(); QStringList nextRevisions = lastRevisions; - QList lanes; + QList lanes; bool removedDeadLine = false; // initialize all lanes with plain vertical bars first; @@ -125,7 +250,10 @@ void Graph::buildLanes(QStringList & new // their slot for the next revision(s) - but only one lane per row for (int i=0; i 0); @@ -135,30 +263,32 @@ void Graph::buildLanes(QStringList & new } // preserve further dead lines - if (nextRevisions.at(i).isEmpty()) + if (rev.isEmpty()) { - lanes.push_back(Revision::Empty); + lanes.push_back(Empty); } else { - lanes.push_back(removedDeadLine ? Revision::BarToLeft - : Revision::Bar); + lanes.push_back(removedDeadLine ? BarToLeft : Bar); } } - I(lanes.size() == nextRevisions.size()); + I(lanes.size() <= nextRevisions.size()); - Revision * revObj = revisionMap.value(rev); + QString rev = newRevisions.takeFirst(); + RevisionData * revObj = revisionMap.value(rev); + // add revisions for the next round + newRevisions += revObj->parents; + int idx = lastRevisions.indexOf(rev); - if (idx == -1) { - Revision::LaneType type; + LaneType type; switch (revObj->parents.size()) { - case 0: type = Revision::SingleNode; break; - case 1: type = Revision::Head; break; - case 2: type = Revision::HeadMerge; break; + case 0: type = SingleNode; break; + case 1: type = Head; break; + case 2: type = HeadMerge; break; default: I(false); } nextRevisions += revObj->parents; @@ -166,24 +296,21 @@ void Graph::buildLanes(QStringList & new } else { - // add revisions for the next round - newRevisions += revObj->parents; - - Revision::LaneType type, defaultNextType; + LaneType type, defaultNextType; switch (revObj->parents.size()) { case 0: - type = Revision::Tail; - defaultNextType = Revision::BarToLeft; + type = Tail; + defaultNextType = BarToLeft; nextRevisions.replace(idx, QString()); break; case 1: - type = Revision::Node; - defaultNextType = Revision::Bar; + type = Node; + defaultNextType = Bar; nextRevisions.replace(idx, revObj->parents.at(0)); break; case 2: - type = Revision::Merge; + type = Merge; nextRevisions.replace(idx, revObj->parents.at(0)); // check the special case where a dead line is right @@ -192,12 +319,12 @@ void Graph::buildLanes(QStringList & new if (idx + 1 < nextRevisions.size() && nextRevisions.at(idx + 1).isEmpty()) { - defaultNextType = Revision::Bar; + defaultNextType = Bar; nextRevisions.replace(idx + 1, revObj->parents.at(1)); } else { - defaultNextType = Revision::BarToRight; + defaultNextType = BarToRight; nextRevisions.insert(idx + 1, revObj->parents.at(1)); } break; @@ -212,14 +339,14 @@ void Graph::buildLanes(QStringList & new { switch (defaultNextType) { - case Revision::BarToLeft: - defaultNextType = Revision::BarToLeftCrossing; + case BarToLeft: + defaultNextType = BarToLeftCrossing; break; - case Revision::Bar: - defaultNextType = Revision::Crossing; + case Bar: + defaultNextType = Crossing; break; - case Revision::BarToRight: - defaultNextType = Revision::BarToRightCrossing; + case BarToRight: + defaultNextType = BarToRightCrossing; break; default: I(false); } @@ -227,11 +354,11 @@ void Graph::buildLanes(QStringList & new // do we join the line to a previous fork line? if (!hasFork) { - lanes[i] = Revision::BarToFork; + lanes[i] = BarToFork; } else { - lanes[i] = Revision::BarToForkJoin; + lanes[i] = BarToForkJoin; } // mark this line as not being continued @@ -250,9 +377,9 @@ void Graph::buildLanes(QStringList & new { switch (type) { - case Revision::Tail: type = Revision::TailFork; break; - case Revision::Node: type = Revision::Fork; break; - case Revision::Merge: type = Revision::MergeFork; break; + case Tail: type = TailFork; break; + case Node: type = Fork; break; + case Merge: type = MergeFork; break; default: I(false); } } @@ -262,10 +389,20 @@ void Graph::buildLanes(QStringList & new revObj->lanes = lanes; + if (!revObj->certsQueried) + { + AutomateCommand::enqueueDatabaseTask( + databaseFile, + MonotoneTask(QStringList() << "certs" << rev) + ); + } + else + { + emit lineFinished(rev); + } + if (newRevisions.size() == 0) { - // FIXME: next thing is to draw the mess - emit lanesCreated(); return; } @@ -273,3 +410,9 @@ void Graph::buildLanes(QStringList & new buildLanes(newRevisions, nextRevisions); } +RevisionData * Graph::getRevision(const QString & rev) +{ + I(revisionMap.contains(rev)); + return revisionMap.value(rev); +} + ============================================================ --- src/model/Graph.h 12331956dd8457649a45dbfe59f4f10b48676d9d +++ src/model/Graph.h ffc22c50630e7867b6d04028d5c01ddb8b862e7b @@ -22,94 +22,166 @@ #include "AutomateCommand.h" #include "vocab.h" -class Revision +#include +#include + +/** + * possible lane types - the *Broken parts denote the same line type + * with a different line style (¦ instead of |) which means that + * revision on this line do not have the filtered branch cert attached + * Any node whose parents and childs are not on the current branch are + * completly invisible and are not rendered. + */ + +enum LaneType { + Empty, /* ( ) */ + Bar, + /* | + | + | */ + BarForkLeft, + /* | + -| + | */ + BarForkRight, + /* | + |- + | */ + BarToLeft, + /* | + / + | */ + BarToRight, + /* | + \ + | */ + Link, + /* + --- + */ + BarLinkCross, + /* | + -^- + | */ + BarToLeftLinkCross, + /* | + -^-- + | */ + BarToRightLinkCross, + /* | + --^- + | */ + LinkToLeft, + /* | + _/ + */ + LinkToRight, + /* | + \_ + */ + LinkToLeftJoin, + /* | + _/-- + */ + LinkToRightJoin, + /* | + --\_ + */ + SingleNode, /* + o + */ + Node, + /* | + o + | */ + NodeForkLeft, + /* | + -o + | */ + NodeForkRight, + /* | + o- + | */ + Merge, + /* | + o + |\ */ + MergeForkLeft, + /* | + -o + |\ */ + MergeForkRight, + /* | + o- + |\ */ + Head, + /* + o + | */ + HeadMerge, + /* + o + |\ */ + Tail, + /* | + o + */ + TailForkLeft, + /* | + -o + */ + TailForkRight, + /* | + o- + */ +}; + +class RevisionData { public: + RevisionData() : certsQueried(false) {} + + void normalizeCerts(const CertList &); + + inline bool onBranch(const QString & branch) + { + return branches.contains(branch); + } + QString hash; QStringList parents; QStringList children; QStringList branches; + QList lanes; - /** - * possible lane typess - */ - enum LaneType { Empty, /* ( ) */ - Bar, /* | - | - | */ - Crossing, /* | - -^- - | */ - BarToLeft, /* | - / - | */ - BarToRight, /* | - \ - | */ - BarToLeftCrossing, /* | - -^-- - | */ - BarToRightCrossing, /* | - --^- - | */ - BarToFork, /* | - _/ - */ - BarToForkJoin, /* | - _/-- - */ - SingleNode, /* - o - */ - Node, /* | - o - | */ - Fork, /* | - o- - | */ - Merge, /* | - o - |\ */ - MergeFork, /* | - o- - |\ */ - Head, /* - o - | */ - HeadMerge, /* - o - |\ */ - Tail, /* | - o - */ - TailFork, /* | - o- - */ - }; - - QList lanes; + bool certsQueried; + QString author; + QString date; + QString htmllog; + QString plainlog; }; -class Graph : public AutomateCommand +class Graph : public QObject, public AutomateCommand { + Q_OBJECT public: Graph(const DatabaseFile &); virtual ~Graph(); void readGraph(); + void buildLanesForBranch(const QString &); + RevisionData * getRevision(const QString &); - void filterBranch(const QString &); - signals: - void lanesCreated(); + void lineFinished(const QString &); private: void processTaskResult(const MonotoneTask &); + void buildLanes(const QStringList &); void buildLanes(QStringList &, const QStringList &); - QMap revisionMap; - QMap branchHeads; - QString currentBranch; + QMap revisionMap; + QMap topsortedRevs; DatabaseFile databaseFile; }; ============================================================ --- src/view/MainWindow.cpp e1e2577bbcce3b8beaa16dd8c855f89b62f18358 +++ src/view/MainWindow.cpp 7c65de44d72db4d0c74d3a0ddfad0b6bfda5d848 @@ -118,6 +118,9 @@ void MainWindow::init() restoreGeometry(Settings::getWindowGeometry(objectName())); setup(); + + raise(); + activateWindow(); } void MainWindow::closeEvent(QCloseEvent * event) ============================================================ --- src/view/dialogs/ChangesetBrowser.cpp bb4313d6d73e7cf525442755c01ec05445958927 +++ src/view/dialogs/ChangesetBrowser.cpp dc56fe1e42b00ae9ae49f359644f8ed25d6b0829 @@ -74,16 +74,6 @@ ChangesetBrowser::ChangesetBrowser(QWidg ); connect( - pushAll, SIGNAL(clicked()), - this, SLOT(receiveAll()) - ); - - connect( - pushMore, SIGNAL(clicked()), - this, SLOT(receiveMore()) - ); - - connect( changesets, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(changesetsDoubleClicked(const QModelIndex &)) ); @@ -99,16 +89,6 @@ ChangesetBrowser::ChangesetBrowser(QWidg ); } -void ChangesetBrowser::receiveAll() -{ - changesetModel->receiveRevisions(true); -} - -void ChangesetBrowser::receiveMore() -{ - changesetModel->receiveRevisions(false); -} - ChangesetBrowser::~ChangesetBrowser() { branchesSplitter->saveState(); ============================================================ --- src/view/dialogs/ChangesetBrowser.h 702cb80e34ccd1dd8d17521a4ade28b50743ca14 +++ src/view/dialogs/ChangesetBrowser.h cc91ca9a24b3f694eb60ace982cc0fc0e4a6bbe0 @@ -41,8 +41,6 @@ private slots: void changesetsClicked(const QModelIndex &); void branchesRead(); void toggleTree(); - void receiveAll(); - void receiveMore(); void changesetsDoubleClicked(const QModelIndex &); void contextMenuRequested(const QModelIndexList &, const QPoint &); void changeViewDoubleClicked(const QModelIndex &);