# # # add_file "src/model/BranchesProxyModel.cpp" # content [647cd298160826129539224a5192d6c0118322d7] # # add_file "src/model/BranchesProxyModel.h" # content [8dd177898ddbc4f13c570099c0c6fc1beb086808] # # patch "guitone.pro" # from [a5804ea420bcf84ab3a55d21a5fd495809dc6989] # to [dacbaeccebf25116c001b03cd18bdb6cb34cdbb1] # # patch "res/forms/changeset_browser.ui" # from [b305fba833874efa7b6b53773d8cea303c0366d0] # to [a7cae1b4a1bd8ef29f97b89c08d719ac88a0f0eb] # # patch "src/Guitone.cpp" # from [1a9d4af5358b813497cfab222ae2e857df360c95] # to [7bb500e067b3c8e9f934ad9b6620d745b15d62a7] # # patch "src/Guitone.h" # from [7e8655d1197edc661b8d7b5f90b64b957cb04972] # to [6921fe5094d1f04122c6198376224c91b9e76797] # # patch "src/model/Branches.cpp" # from [728808cda07a8491fa0f3f6d7c32c64e6a1dde06] # to [408dc8fe11df9da868ebcf2d67b62bbfdb7c821c] # # patch "src/model/Branches.h" # from [4dc8ac62813551f8ce888bb840ce1676e80aa849] # to [b33bc079edd307d9017d50a09e2f7bfb8e8f0256] # # patch "src/model/ChangesetModel.cpp" # from [9db73c376ae513811f07749800ef40c8f31cdb5d] # to [0f9fe421e51fc945024a15a145bdfe64cb0bec45] # # patch "src/monotone/MonotoneDelegate.cpp" # from [0b1b0ebfaa468cbf89d3ef32a54e9791405b86f5] # to [4e939275d62864ad9cca6e29e3e4925a36c7e7f3] # # patch "src/monotone/MonotoneDelegate.h" # from [6971e5c0d79d50fc766f84fb395cf648da80c8e5] # to [d44780a954122fd14c72e9754b6f77935a0bb01a] # # patch "src/util/TreeBuilder.cpp" # from [c4d4da986645b777ab83d135c3673dc042993d58] # to [b1bfdb7512ba354f189a9eae6c10fbe3dfb1f7be] # # patch "src/util/TreeBuilder.h" # from [1996056b8130b1e46a5ad587ae50e83e956b7cc4] # to [973eb9b33776b1decb6f02312070f1840f1b2942] # # patch "src/view/dialogs/ChangesetBrowser.cpp" # from [f88765a14b2eef403b8609587b95d7cf58a6a4ae] # to [124b68cbfa0ddcb8f6cb2292631aacb62d76edc8] # # patch "src/view/dialogs/ChangesetBrowser.h" # from [9b78450d35f13ae1a57e9475e69e66f975afbc0f] # to [2fd249ec23178857252e9b39f0a1820f30445455] # ============================================================ --- src/model/BranchesProxyModel.cpp 647cd298160826129539224a5192d6c0118322d7 +++ src/model/BranchesProxyModel.cpp 647cd298160826129539224a5192d6c0118322d7 @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2007 by Thomas Keller * + * address@hidden * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "BranchesProxyModel.h" +#include "MonotoneDelegate.h" + +BranchesProxyModel::BranchesProxyModel(QObject * parent) + : QSortFilterProxyModel(parent) +{ + setDynamicSortFilter(true); +} + +BranchesProxyModel::~BranchesProxyModel() {} + +void BranchesProxyModel::setRootRevision(const QString & rev) +{ + rootRevision = rev; + clear(); +} + +bool BranchesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const +{ + // if no filter is set, display all + if (rootRevision.isEmpty()) return true; + + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + QString branch = index.data(Qt::UserRole).toString(); + + // this seems to be a "*" wildcard entry + if (branch.isEmpty()) return true; + + QStringList heads = + MonotoneDelegate::resolveSelector(this, QString("h:") + branch); + QStringList no_ancestors = + MonotoneDelegate::eraseAncestors(this, QStringList(heads) << rootRevision); + + // if the root revision has been erased, rootRevision is an ancestor of + // any of the two heads and thus we have found another valid branch for + // this root + return heads == no_ancestors; +} + ============================================================ --- src/model/BranchesProxyModel.h 8dd177898ddbc4f13c570099c0c6fc1beb086808 +++ src/model/BranchesProxyModel.h 8dd177898ddbc4f13c570099c0c6fc1beb086808 @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2007 by Thomas Keller * + * address@hidden * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef BRANCHESPROXYMODEL_H +#define BRANCHESPROXYMODEL_H + +#include + +class BranchesProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + BranchesProxyModel(QObject *); + virtual ~BranchesProxyModel(); + bool filterAcceptsRow(int, const QModelIndex &) const; + void setRootRevision(const QString &); + +private: + QString rootRevision; +}; + +#endif ============================================================ --- guitone.pro a5804ea420bcf84ab3a55d21a5fd495809dc6989 +++ guitone.pro dacbaeccebf25116c001b03cd18bdb6cb34cdbb1 @@ -53,6 +53,7 @@ HEADERS = src/view/MainWindow.h \ src/model/GetFileProxyModel.h \ src/model/Tags.h \ src/model/Branches.h \ + src/model/BranchesProxyModel.h \ src/model/Keys.h \ src/model/Changeset.h \ src/model/ChangesetModel.h \ @@ -114,6 +115,7 @@ SOURCES += src/view/MainWindow.cpp \ src/model/GetFileProxyModel.cpp \ src/model/Tags.cpp \ src/model/Branches.cpp \ + src/model/BranchesProxyModel.cpp \ src/model/Keys.cpp \ src/model/Changeset.cpp \ src/model/ChangesetModel.cpp \ ============================================================ --- res/forms/changeset_browser.ui b305fba833874efa7b6b53773d8cea303c0366d0 +++ res/forms/changeset_browser.ui a7cae1b4a1bd8ef29f97b89c08d719ac88a0f0eb @@ -5,8 +5,8 @@ 0 0 - 703 - 483 + 646 + 420 @@ -35,7 +35,39 @@ Qt::Horizontal - + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + Filter by project + + + + + + + + + + + + + Qt::Vertical @@ -134,7 +166,7 @@ Splitter QSplitter -
../Splitter.h
+
Splitter.h
TreeView ============================================================ --- src/Guitone.cpp 1a9d4af5358b813497cfab222ae2e857df360c95 +++ src/Guitone.cpp 7bb500e067b3c8e9f934ad9b6620d745b15d62a7 @@ -462,20 +462,20 @@ bool Guitone::removeMonotoneInstance(Mai return true; } -MainWindow * Guitone::findMainWindow(QObject * obj) +MainWindow * Guitone::findMainWindow(const QObject * obj) const { - do + if (!obj->inherits("MainWindow")) { - if (obj->inherits("MainWindow")) break; - obj = obj->parent(); - } while (obj); + return findMainWindow(obj->parent()); + } I(obj); - MainWindow * wnd = qobject_cast(obj); + + MainWindow * wnd = qobject_cast(const_cast(obj)); return wnd; } -Monotone * Guitone::getMonotoneInstance(QObject * obj) +Monotone * Guitone::getMonotoneInstance(const QObject * obj) const { MainWindow * wnd = findMainWindow(obj); I(wnd); ============================================================ --- src/Guitone.h 7e8655d1197edc661b8d7b5f90b64b957cb04972 +++ src/Guitone.h 6921fe5094d1f04122c6198376224c91b9e76797 @@ -41,8 +41,8 @@ public: bool init(); const QList windowList() const; - MainWindow * findMainWindow(QObject *); - Monotone * getMonotoneInstance(QObject *); + MainWindow * findMainWindow(const QObject *) const; + Monotone * getMonotoneInstance(const QObject *) const; bool loadFromPath(const QString &); void lock(); ============================================================ --- src/model/Branches.cpp 728808cda07a8491fa0f3f6d7c32c64e6a1dde06 +++ src/model/Branches.cpp 408dc8fe11df9da868ebcf2d67b62bbfdb7c821c @@ -48,26 +48,33 @@ void Branches::parseOutput() void Branches::parseOutput() { - branches.setHorizontalHeaderItem(0, new QStandardItem(tr("Branches"))); - if(tree) + branches.setHorizontalHeaderItem(0, new QStandardItem(tr("Branches"))); + QStringList branchList = AutomateCommand::data.split("\n"); + + if (tree) { - QStandardItem *root = new QStandardItem("*"); + QStandardItem * root = new QStandardItem("*"); + + // FIXME: this is a big fat hack: whilte GetBranchLog needs branch + // names with an optional wildcard, i.e. for automate select, other + // commands just need the plain branch namespace f.e. to filter out + // branches from the view. "Serving" both needs by overloading + // ToolTipRole for the one group of commands and UserRole for the + // other group is certainly irritating and error prone! root->setData("*", Qt::ToolTipRole); + root->setData("", Qt::UserRole); branches.appendRow(root); builder = new TreeBuilder(root, this); - builder->addList(AutomateCommand::data); + builder->addBranchList(branchList); } else { - QStringList branchList = AutomateCommand::data.split("\n"); - - QStringListIterator iterator(branchList); - while(iterator.hasNext()) + foreach (QString branch, branchList) { - QString it = iterator.next(); - QStandardItem *item = new QStandardItem(it); - item->setData(it, Qt::ToolTipRole); + QStandardItem * item = new QStandardItem(branch); + item->setData(branch, Qt::ToolTipRole); + item->setData(branch, Qt::UserRole); branches.appendRow(item); } } @@ -88,19 +95,12 @@ QVariant Branches::data(const QModelInde QVariant Branches::data(const QModelIndex &index, int role) const { QStandardItem * item = branchFromIndex(index); - if(item) + if (item) return item->data(role); else return QVariant(); } -//FIXME: Do we need this? - -/*Qt::ItemFlags Branches::flags(const QModelIndex &index) const -{ - return branchFromIndex(index)->flags(); -}*/ - QVariant Branches::headerData(int section, Qt::Orientation orientation, int role) const { return branches.headerData(section, orientation, role); @@ -109,7 +109,7 @@ int Branches::rowCount(const QModelIndex int Branches::rowCount(const QModelIndex& parent) const { QStandardItem * item = branchFromIndex(parent); - if(item) + if (item) return item->rowCount(); else return branches.rowCount(); ============================================================ --- src/model/Branches.h 4dc8ac62813551f8ce888bb840ce1676e80aa849 +++ src/model/Branches.h b33bc079edd307d9017d50a09e2f7bfb8e8f0256 @@ -37,7 +37,6 @@ public: // needed Qt Model methods QVariant data(const QModelIndex&, int) const; - //Qt::ItemFlags flags(const QModelIndex&) const; QVariant headerData(int, Qt::Orientation, int) const; QModelIndex index(int, int, const QModelIndex&) const; QModelIndex parent(const QModelIndex&) const; @@ -52,7 +51,7 @@ private: private: bool tree; - TreeBuilder *builder; + TreeBuilder * builder; void parseOutput(); QStandardItemModel branches; void * getBranchItem(int row, int column, const QModelIndex& index) const; ============================================================ --- src/model/ChangesetModel.cpp 9db73c376ae513811f07749800ef40c8f31cdb5d +++ src/model/ChangesetModel.cpp 0f9fe421e51fc945024a15a145bdfe64cb0bec45 @@ -40,7 +40,7 @@ void ChangesetModel::receiveRevisions(bo if(changesetMap[revision] == NULL) { - ChangesetCerts *certs = new ChangesetCerts(currentBranch, revision, i, this); + ChangesetCerts * certs = new ChangesetCerts(currentBranch, revision, i, this); certs->readCerts(revision); c++; } @@ -51,11 +51,11 @@ void ChangesetModel::setBranch(QString b void ChangesetModel::setBranch(QString branch) { currentBranch = branch; - BranchInfo *branchInfo = &branchMap[currentBranch]; + BranchInfo * branchInfo = &branchMap[currentBranch]; if(branchInfo->revisions.count() == 0) { branchInfo->certsRead = 0; - GetBranchLog *glog = new GetBranchLog(branch, this); + GetBranchLog * glog = new GetBranchLog(branch, this); Q_UNUSED(glog); } else ============================================================ --- src/monotone/MonotoneDelegate.cpp 0b1b0ebfaa468cbf89d3ef32a54e9791405b86f5 +++ src/monotone/MonotoneDelegate.cpp 4e939275d62864ad9cca6e29e3e4925a36c7e7f3 @@ -33,7 +33,7 @@ MonotoneDelegate::~MonotoneDelegate() int cnt = commandNumbers.size(); if (cnt > 0) { - W(QString("%1 pending commands").arg(cnt)); + C(QString("%1 pending commands").arg(cnt)); APP->restoreOverrideCursor(); } } @@ -109,7 +109,7 @@ void MonotoneDelegate::commandFinished(i } } -QString MonotoneDelegate::getBaseWorkspaceRevision(QObject * obj) +QString MonotoneDelegate::getBaseWorkspaceRevision(const QObject * obj) { Monotone * mtn = MTN(obj); @@ -134,7 +134,7 @@ QString MonotoneDelegate::getBaseWorkspa return data; } -QString MonotoneDelegate::getOption(QObject * obj, const QString & opt) +QString MonotoneDelegate::getOption(const QObject * obj, const QString & opt) { Monotone * mtn = MTN(obj); @@ -155,7 +155,7 @@ QString MonotoneDelegate::getOption(QObj return data; } -QString MonotoneDelegate::getBranchName(QObject * obj, const QString & defaultBranch) +QString MonotoneDelegate::getBranchName(const QObject * obj, const QString & defaultBranch) { QString branchName = getOption(obj, "branch"); @@ -166,7 +166,7 @@ QString MonotoneDelegate::getBranchName( return branchName; } -QString MonotoneDelegate::getBranchNameShort(QObject * obj) +QString MonotoneDelegate::getBranchNameShort(const QObject * obj) { // FIXME: currently there is only support for the domain branch scheme // tld.domain.project.branch @@ -197,11 +197,30 @@ QString MonotoneDelegate::getBranchNameS return shortBranchName; } -QStringList MonotoneDelegate::resolveSelector(QObject * obj, const QString & selector) +QStringList MonotoneDelegate::getRoots(const QObject * obj) { Monotone * mtn = MTN(obj); int cmdNum; + mtn->executeCommand(QStringList() << "roots", cmdNum); + + QString data = mtn->getDecodedData(cmdNum); + + if (mtn->getReturnCode(cmdNum) > 0) + { + C(QString("Couldn't execute erase_ancestors: %1").arg(data)); + return QStringList(); + } + + QStringList revList = data.split('\n', QString::SkipEmptyParts); + return revList; +} + +QStringList MonotoneDelegate::resolveSelector(const QObject * obj, const QString & selector) +{ + Monotone * mtn = MTN(obj); + + int cmdNum; mtn->executeCommand(QStringList() << "select" << selector, cmdNum); QString data = mtn->getDecodedData(cmdNum); @@ -216,11 +235,30 @@ QStringList MonotoneDelegate::resolveSel return revList; } -RevisionCerts MonotoneDelegate::getRevisionCerts(QObject * obj, const QString & revision) +QStringList MonotoneDelegate::eraseAncestors(const QObject * obj, const QStringList & revs) { Monotone * mtn = MTN(obj); int cmdNum; + mtn->executeCommand(QStringList() << "erase_ancestors" << revs, cmdNum); + + QString data = mtn->getDecodedData(cmdNum); + + if (mtn->getReturnCode(cmdNum) > 0) + { + C(QString("Couldn't execute erase_ancestors: %1").arg(data)); + return QStringList(); + } + + QStringList revList = data.split('\n', QString::SkipEmptyParts); + return revList; +} + +RevisionCerts MonotoneDelegate::getRevisionCerts(const QObject * obj, const QString & revision) +{ + Monotone * mtn = MTN(obj); + + int cmdNum; mtn->executeCommand(QStringList() << "certs" << revision, cmdNum); QString data = mtn->getDecodedData(cmdNum); @@ -262,7 +300,7 @@ RevisionCerts MonotoneDelegate::getRevis return certs; } -QString MonotoneDelegate::getDatabaseFilePath(QObject * obj) +QString MonotoneDelegate::getDatabaseFilePath(const QObject * obj) { Monotone * mtn = MTN(obj); QString path = mtn->getDatabaseFilePath(); @@ -277,7 +315,7 @@ QString MonotoneDelegate::getDatabaseFil return path; } -FileEntryList MonotoneDelegate::getRevisionManifest(QObject * obj, const QString & revision) +FileEntryList MonotoneDelegate::getRevisionManifest(const QObject * obj, const QString & revision) { Monotone * mtn = MTN(obj); @@ -348,7 +386,7 @@ FileEntryList MonotoneDelegate::getRevis return entries; } -QStringList MonotoneDelegate::getPrivateKeyList(QObject * obj) +QStringList MonotoneDelegate::getPrivateKeyList(const QObject * obj) { Monotone * mtn = MTN(obj); @@ -394,7 +432,7 @@ QStringList MonotoneDelegate::getPrivate return keys; } -QString MonotoneDelegate::getFileId(QObject * obj, const QString & path) +QString MonotoneDelegate::getFileId(const QObject * obj, const QString & path) { Monotone * mtn = MTN(obj); ============================================================ --- src/monotone/MonotoneDelegate.h 6971e5c0d79d50fc766f84fb395cf648da80c8e5 +++ src/monotone/MonotoneDelegate.h d44780a954122fd14c72e9754b6f77935a0bb01a @@ -38,16 +38,18 @@ public: bool triggerCommand(const QStringList &); bool triggerCommand(const QStringList &, const QStringList &); - static QString getBaseWorkspaceRevision(QObject *); - static QString getOption(QObject *, const QString &); - static QString getBranchName(QObject *, const QString & defaultBranch = tr("[unknown branch]")); - static QString getBranchNameShort(QObject *); - static QStringList resolveSelector(QObject *, const QString &); - static RevisionCerts getRevisionCerts(QObject *, const QString &); - static QString getDatabaseFilePath(QObject *); - static FileEntryList getRevisionManifest(QObject *, const QString & rev = QString()); - static QStringList getPrivateKeyList(QObject *); - static QString getFileId(QObject *, const QString &); + static QString getBaseWorkspaceRevision(const QObject *); + static QString getOption(const QObject *, const QString &); + static QString getBranchName(const QObject *, const QString & defaultBranch = tr("[unknown branch]")); + static QString getBranchNameShort(const QObject *); + static QStringList getRoots(const QObject *); + static QStringList resolveSelector(const QObject *, const QString &); + static QStringList eraseAncestors(const QObject *, const QStringList &); + static RevisionCerts getRevisionCerts(const QObject *, const QString &); + static QString getDatabaseFilePath(const QObject *); + static FileEntryList getRevisionManifest(const QObject *, const QString & rev = QString()); + static QStringList getPrivateKeyList(const QObject *); + static QString getFileId(const QObject *, const QString &); private: AutomateCommand * cmdModel; ============================================================ --- src/util/TreeBuilder.cpp c4d4da986645b777ab83d135c3673dc042993d58 +++ src/util/TreeBuilder.cpp b1bfdb7512ba354f189a9eae6c10fbe3dfb1f7be @@ -23,131 +23,132 @@ #include -TreeBuilder::TreeBuilder(QStandardItem *root, QObject *parent) : QObject(parent) +TreeBuilder::TreeBuilder(QStandardItem * root, QObject * parent) : QObject(parent) { - TreeBuilder::root = root; - sep = '.'; + TreeBuilder::root = root; + sep = '.'; } -QStandardItem* TreeBuilder::add(const QString &branch) +QStandardItem * TreeBuilder::add(const QString & branch) { - if(branch != "") - return add(branch, root); - else - return NULL; + if(branch != "") + return add(branch, root); + else + return NULL; } -void TreeBuilder::addData(QStandardItem *child) +void TreeBuilder::addData(QStandardItem * child) { - QString branch; - QStandardItem* item = child; - QString text = child->data().toString(); - if(text.right(1) == QString(sep)) - text = text.left(text.length() - 1) + "*"; - child->setText(text); + QString branch; + QStandardItem * item = child; + QString text = child->data().toString(); + + if (text.right(1) == QString(sep)) + text = text.left(text.length() - 1) + "*"; + + child->setText(text); - while(item) - { - branch = item->data().toString() + branch; - item = item->parent(); - } + while (item) + { + branch = item->data().toString() + branch; + item = item->parent(); + } - if(branch.right(1) == QString(sep)) - branch = branch.left(branch.length() - 1) + "*"; - child->setData(branch, Qt::ToolTipRole); + if (branch.right(1) == QString(sep)) + { + child->setData(QString(), Qt::UserRole); + branch = branch.left(branch.length() - 1) + "*"; + } + else + { + child->setData(branch, Qt::UserRole); + } + + child->setData(branch, Qt::ToolTipRole); } -QStandardItem* TreeBuilder::add(const QString &branch, QStandardItem *parent) +QStandardItem * TreeBuilder::add(const QString & branch, QStandardItem * parent) { - if(branch == "") return NULL; + if (branch == "") return NULL; - int len = parent->rowCount(); - for(int index = 0; index < len; index++) - { - int pos = overlap(parent->child(index)->data().toString(), branch) + 1; - if(pos) - { - // Store the child data as we need multiple times - QString tmp = parent->child(index)->data().toString(); + int len = parent->rowCount(); + for (int index = 0; index < len; index++) + { + int pos = overlap(parent->child(index)->data().toString(), branch) + 1; + if (pos) + { + // Store the child data as we need multiple times + QString tmp = parent->child(index)->data().toString(); - if(pos == tmp.length()) - { - // The child contains the branch. - return add(branch.mid(pos), parent->child(index)); - } - else - { - // We found a splitting point. Going to splitt the tree. + if (pos == tmp.length()) + { + // The child contains the branch. + return add(branch.mid(pos), parent->child(index)); + } + else + { + // We found a splitting point. Going to splitt the tree. - // Get the old childs rows - QList row = parent->child(index)->takeColumn(0); + // Get the old childs rows + QList row = parent->child(index)->takeColumn(0); - // Delete the old child - parent->removeRow(index); + // Delete the old child + parent->removeRow(index); - // Create a new parent to replace the old child - QStandardItem *newparent = new QStandardItem(); - newparent->setData(branch.left(pos)); + // Create a new parent to replace the old child + QStandardItem * newparent = new QStandardItem(); + newparent->setData(branch.left(pos)); - // Add the new parent to the parent - parent->appendRow(newparent); - addData(newparent); + // Add the new parent to the parent + parent->appendRow(newparent); + addData(newparent); - // Add the old child to the new parent - QStandardItem* ret; - ret = add(tmp.mid(pos), newparent); + // Add the old child to the new parent + QStandardItem * ret; + ret = add(tmp.mid(pos), newparent); - // Append the old childs rows to the newly added old child - QListIterator iterator(row); - while(iterator.hasNext()) - ret->appendRow(iterator.next()); + // Append the old childs rows to the newly added old child + QListIterator iterator(row); + while(iterator.hasNext()) + ret->appendRow(iterator.next()); - // Add the new child to the new parent - add(branch.mid(pos), newparent); - - return newparent; - } - } - } + // Add the new child to the new parent + add(branch.mid(pos), newparent); + + return newparent; + } + } + } - QStandardItem *it = new QStandardItem(); - it->setData(branch); - parent->appendRow(it); - addData(it); - return it; + QStandardItem * it = new QStandardItem(); + it->setData(branch); + parent->appendRow(it); + addData(it); + return it; } -int TreeBuilder::overlap(const QString &a, const QString &b) +int TreeBuilder::overlap(const QString & a, const QString & b) { - const QChar *ac = a.data(); - const QChar *bc = b.data(); - int len = 0; - int max = qMax(a.length(), b.length()); - while(len < max && ac[len] == bc[len]) - len++; - // Important: It only is a splitting point if both a and b have a sep at - // this point! - while(len >= 0 && (ac[len] != sep || bc[len] != sep)) - len--; - return len; + const QChar *ac = a.data(); + const QChar *bc = b.data(); + int len = 0; + int max = qMax(a.length(), b.length()); + + while (len < max && ac[len] == bc[len]) + len++; + + // Important: It only is a splitting point if both a and b have a sep at + // this point! + while (len >= 0 && (ac[len] != sep || bc[len] != sep)) + len--; + + return len; } -void TreeBuilder::addList(const QString &branches) +void TreeBuilder::addBranchList(const QStringList & branches) { - QStringList branchList = branches.split("\n"); - - //Code for testing the algorithm - srand( (unsigned)time( NULL ) ); - - while(int c = branchList.count()) - add(branchList.takeAt(rand() % c)); - - // FIXME: Replace the code above with the code below once it is clear that the algorithm - // is working. Don't forget to remove the #includes. - - /*QStringListIterator iterator(branchList); - while(iterator.hasNext()) - add(iterator.next()); - */ - root->sortChildren(0); + foreach (QString branch, branches) + { + add(branch); + } } ============================================================ --- src/util/TreeBuilder.h 1996056b8130b1e46a5ad587ae50e83e956b7cc4 +++ src/util/TreeBuilder.h 973eb9b33776b1decb6f02312070f1840f1b2942 @@ -25,19 +25,19 @@ class TreeBuilder : public QObject class TreeBuilder : public QObject { - Q_OBJECT + Q_OBJECT public: - TreeBuilder(QStandardItem *root, QObject *parent = 0); - QStandardItem* add(const QString &branch); - QStandardItem* add(const QString &branch, QStandardItem *parent); - void addList(const QString &branches); + TreeBuilder(QStandardItem *, QObject * parent = 0); + QStandardItem * add(const QString &); + QStandardItem * add(const QString &, QStandardItem *); + void addBranchList(const QStringList &); private: - void addData(QStandardItem *item); - int overlap(const QString &a, const QString &b); - QStandardItem *root; - QChar sep; + void addData(QStandardItem *); + int overlap(const QString &, const QString &); + QStandardItem * root; + QChar sep; }; #endif //TREEBUILDER_H ============================================================ --- src/view/dialogs/ChangesetBrowser.cpp f88765a14b2eef403b8609587b95d7cf58a6a4ae +++ src/view/dialogs/ChangesetBrowser.cpp 124b68cbfa0ddcb8f6cb2292631aacb62d76edc8 @@ -25,39 +25,40 @@ ChangesetBrowser::ChangesetBrowser(QWidg ChangesetBrowser::ChangesetBrowser(QWidget *parent) : Dialog(parent) { - setupUi(this); + setupUi(this); Dialog::init(); // OSX sheet-alike dialog setWindowFlags(Qt::Sheet); - this->setWindowFlags(this->windowFlags() | Qt::WindowMaximizeButtonHint); - this->setWindowFlags(this->windowFlags() | Qt::WindowMinimizeButtonHint); - innerSplitter->init(); - outerSplitter->init(); + this->setWindowFlags(this->windowFlags() | Qt::WindowMaximizeButtonHint); + this->setWindowFlags(this->windowFlags() | Qt::WindowMinimizeButtonHint); + innerSplitter->init(); + outerSplitter->init(); - tree = Settings::getBool("ChangesetBrowserTree", false); + tree = Settings::getBool("ChangesetBrowserTree", false); displayBranchesAsTree->setText( !tree ? tr("display branches as tree") : tr("display branches flat") ); - + branchModel = 0; + branchProxyModel = 0; - initTreeWidget(); + initTreeWidget(); - connect( + connect( branches, SIGNAL(clicked(const QModelIndex &)), this, SLOT(branchesClicked(const QModelIndex &)) ); - + connect( displayBranchesAsTree, SIGNAL(clicked()), this, SLOT(toggleTree()) ); - changesetModel = new ChangesetModel(this); - changesets->setModel(changesetModel); - changesets->setRootIsDecorated(false); + changesetModel = new ChangesetModel(this); + changesets->setModel(changesetModel); + changesets->setRootIsDecorated(false); revisionModel = new GetRevision(this); revisionView->setModel(revisionModel); @@ -67,11 +68,11 @@ ChangesetBrowser::ChangesetBrowser(QWidg this, SLOT(changesetsClicked(const QModelIndex &)) ); - connect( + connect( pushAll, SIGNAL(clicked()), this, SLOT(receiveAll()) ); - + connect( pushMore, SIGNAL(clicked()), this, SLOT(receiveMore()) @@ -86,45 +87,83 @@ ChangesetBrowser::ChangesetBrowser(QWidg changesets, SIGNAL(contextMenuRequested(const QModelIndexList &, const QPoint &)), this, SLOT(contextMenuRequested(const QModelIndexList &, const QPoint &)) ); + + QStringList rootRevisions = MonotoneDelegate::getRoots(this); + + int count = 0; + projectList->insertItem(count++, tr("All projects"), QVariant(QString())); + + foreach (QString rev, rootRevisions) + { + RevisionCerts certs = MonotoneDelegate::getRevisionCerts(this, rev); + + QString branch; + // in case a root revision already has more than one single branch cert + // we're only returning the first + foreach (RevisionCert cert, certs) + { + if (cert.first == "branch") + { + branch = cert.second; + break; + } + } + + if (branch.isEmpty()) + { + branch = tr("No branch cert (%1)").arg(rev); + } + + projectList->insertItem(count++, branch, QVariant(rev)); + } + + connect( + projectList, SIGNAL(currentIndexChanged(int)), + this, SLOT(filterProjectBranches(int)) + ); } void ChangesetBrowser::receiveAll() { - changesetModel->receiveRevisions(true); + changesetModel->receiveRevisions(true); } void ChangesetBrowser::receiveMore() { - changesetModel->receiveRevisions(false); + changesetModel->receiveRevisions(false); } ChangesetBrowser::~ChangesetBrowser() { delete changesetModel; delete revisionModel; + if (branchModel) delete branchModel; - Settings::setBool("ChangesetBrowserTree", tree); + if (branchProxyModel) delete branchProxyModel; + + Settings::setBool("ChangesetBrowserTree", tree); } void ChangesetBrowser::toggleTree() { - tree = !tree; + tree = !tree; displayBranchesAsTree->setText( !tree ? tr("display branches as tree") : tr("display branches flat") ); - initTreeWidget(); + initTreeWidget(); } void ChangesetBrowser::branchesClicked(const QModelIndex & idx) { - QString branch = branchModel->data(idx, Qt::ToolTipRole).toString(); - changesetModel->setBranch(branch); + QModelIndex sourceIdx = branchProxyModel->mapToSource(idx); + QString branch = branchModel->data(sourceIdx, Qt::ToolTipRole).toString(); + changesetModel->setBranch(branch); } void ChangesetBrowser::changesetsClicked(const QModelIndex & idx) { QModelIndex revIdx = changesetModel->index(idx.row(), 3, QModelIndex()); QString revision = changesetModel->data(revIdx, Qt::DisplayRole).toString(); - revisionModel->readRevision(revision); + revisionModel->readRevision(revision); } void ChangesetBrowser::initTreeWidget() @@ -135,23 +174,32 @@ void ChangesetBrowser::initTreeWidget() branchModel, SIGNAL(branchesRead(void)), this, SLOT(branchesRead(void)) ); + delete branchModel; + delete branchProxyModel; } - branchModel = new Branches(this, tree); - branchModel->readBranches(); - branches->setRootIsDecorated(false); - branches->setModel(branchModel); + branchModel = new Branches(this, tree); + branchModel->readBranches(); + + branchProxyModel = new BranchesProxyModel(this); + branchProxyModel->setSourceModel(branchModel); + branchProxyModel->setRootRevision( + projectList->itemData(projectList->currentIndex()).toString() + ); + + branches->setRootIsDecorated(false); + branches->setModel(branchProxyModel); - connect( + connect( branchModel, SIGNAL(branchesRead(void)), - this, SLOT(branchesRead(void)) + this, SLOT(branchesRead(void)) ); } void ChangesetBrowser::branchesRead() { - branches->setExpanded(branchModel->index(0, 0, QModelIndex()), true); + branches->setExpanded(branchProxyModel->index(0, 0, QModelIndex()), true); } void ChangesetBrowser::openManifestDialog(const QString & rev) @@ -192,3 +240,11 @@ void ChangesetBrowser::contextMenuReques // etc. } +void ChangesetBrowser::filterProjectBranches(int index) +{ + QString rev = projectList->itemData(index).toString(); + if (branchProxyModel) + { + branchProxyModel->setRootRevision(rev); + } +} ============================================================ --- src/view/dialogs/ChangesetBrowser.h 9b78450d35f13ae1a57e9475e69e66f975afbc0f +++ src/view/dialogs/ChangesetBrowser.h 2fd249ec23178857252e9b39f0a1820f30445455 @@ -24,35 +24,38 @@ #include "ui_changeset_browser.h" #include "Monotone.h" #include "Branches.h" +#include "BranchesProxyModel.h" #include "Dialog.h" #include "ChangesetModel.h" #include "GetRevision.h" class ChangesetBrowser : public Dialog, private Ui::ChangesetBrowser { - Q_OBJECT + Q_OBJECT public: - ChangesetBrowser(QWidget *); - ~ChangesetBrowser(); + ChangesetBrowser(QWidget *); + ~ChangesetBrowser(); private slots: - void branchesClicked(const QModelIndex &); + void branchesClicked(const QModelIndex &); void changesetsClicked(const QModelIndex &); - void branchesRead(); - void toggleTree(); - void receiveAll(); - void receiveMore(); + void branchesRead(); + void toggleTree(); + void receiveAll(); + void receiveMore(); void changesetsDoubleClicked(const QModelIndex &); void contextMenuRequested(const QModelIndexList &, const QPoint &); + void filterProjectBranches(int); private: void initTreeWidget(); void openManifestDialog(const QString &); bool tree; - Branches * branchModel; - ChangesetModel * changesetModel; + Branches * branchModel; + BranchesProxyModel * branchProxyModel; + ChangesetModel * changesetModel; GetRevision * revisionModel; };