# # # patch "src/model/GetRevision.cpp" # from [f9f9f77f0cdd62b2fbe5d06e896db8c954d2b197] # to [10a2cb967b01e82641b3dd7c7be9316db1adcbbe] # # patch "src/model/GetRevision.h" # from [d6d94d54c3a9227e7df4d9603143419944a24691] # to [b5bb677355b8c88fb1bf3096e92433576087ea77] # # patch "src/monotone/WorkspaceCommitter.cpp" # from [8ef7bebbbcdc720ff1aa53ac9090cd3362488620] # to [d2a5ce169d18495c84ed56ecf92732b2c6646812] # # patch "src/monotone/WorkspaceCommitter.h" # from [e868a69ebf244aa67a0d02ef7a9372e798754fd8] # to [c2507e2154158f9745dfb7743d6bf4b0b9544d17] # # patch "src/view/InventoryView.cpp" # from [d66ba062f6aa10dcc2902bfb3cc938677085b884] # to [cfb5a587e2de5102d66c54d272772d8c5588b14b] # # patch "src/view/InventoryView.h" # from [dd276275934c9f0737d6076a745656efa9e1a9e3] # to [ba606e7bfbdd1fdeacd6a0e8d6d5a57828c40027] # # patch "src/view/WorkspaceWindow.cpp" # from [a57527afe8592e57cc8c5deb5d0d1f927b81aa5d] # to [bcffd1a6e62185ad34ee9d9d0013e58c4556252b] # # patch "src/view/dialogs/CommitRevision.cpp" # from [9c06833957c547802f3c3a0873ed10640f2537a1] # to [489a71f2d951d413ae11e62f8c62d9c754c1aa6d] # # patch "src/view/dialogs/CommitRevision.h" # from [fdc575faa9b56117ee49625e3b70242b180ecb9f] # to [c740442a658574064b5895315a08a42af5cc36dc] # # patch "src/view/dialogs/WorkspaceDialogManager.cpp" # from [dd484a907c3f11a9c073fc3fcd7e2778360ee831] # to [b374e93b4c8357cf23e4741a0aa7e05212dc0dd7] # # patch "src/view/dialogs/WorkspaceDialogManager.h" # from [e874a262a700fda55d233642fecb0f7d59ce0240] # to [abc57b99c46faa051f70c870431e300b2edc4a70] # ============================================================ --- src/model/GetRevision.cpp f9f9f77f0cdd62b2fbe5d06e896db8c954d2b197 +++ src/model/GetRevision.cpp 10a2cb967b01e82641b3dd7c7be9316db1adcbbe @@ -18,6 +18,7 @@ #include "GetRevision.h" #include "vocab.h" +#include "MonotoneUtil.h" #include #include @@ -36,10 +37,18 @@ void GetRevision::readDatabaseRevision(c AutomateCommand::enqueueDatabaseTask(db, task); } -void GetRevision::readWorkspaceRevision(const WorkspacePath & ws) +void GetRevision::readWorkspaceRevision(const WorkspacePath & ws, const QStringList & paths) { revision.clear(); - MonotoneTask task( QStringList() << "get_revision"); + + QStringList args; + args << "get_current_revision"; + if (paths.size() > 0) + { + args << paths; + } + + MonotoneTask task(args); AutomateCommand::enqueueWorkspaceTask(ws, task); } @@ -47,8 +56,7 @@ void GetRevision::processTaskResult(cons { if (task.getReturnCode() != 0) { - C(QString("Command returned with a non-zero return code (%1)") - .arg(task.getOutputUtf8())); + emit readFailed(MonotoneUtil::stripMtnPrefix(task.getOutputUtf8())); return; } @@ -289,3 +297,66 @@ void GetRevision::showChangesAgainstPare reset(); } +QMap > GetRevision::getChangedFiles() const +{ + QMap > fileMap; + + if (revision.changesAgainstParent.contains(changesAgainstParent)) + { + QList changes = + revision.changesAgainstParent.value(changesAgainstParent); + foreach (Change ch, changes) + { + Stanza st = ch.stanza; + QString path; + QPair hashes; + bool isPatch = false; + bool isAdd = false; + + foreach (StanzaEntry en, st) + { + if (en.sym == "add_file") + { + path = en.vals.at(0); + isAdd = true; + continue; + } + + if (isAdd && en.sym == "content") + { + hashes.first = en.hash; + fileMap.insert(path, hashes); + break; + } + + if (en.sym == "patch") + { + path = en.vals.at(0); + isPatch = true; + continue; + } + + if (isPatch && en.sym == "from") + { + hashes.second = en.hash; + continue; + } + + if (isPatch && en.sym == "to") + { + hashes.first = en.hash; + fileMap.insert(path, hashes); + break; + } + } + } + } + + return fileMap; +} + +QString GetRevision::getRevisionText() const +{ + return revision.print(); +} + ============================================================ --- src/model/GetRevision.h d6d94d54c3a9227e7df4d9603143419944a24691 +++ src/model/GetRevision.h b5bb677355b8c88fb1bf3096e92433576087ea77 @@ -21,6 +21,7 @@ #include "AutomateCommand.h" #include "BasicIOParser.h" +#include "BasicIOWriter.h" #include @@ -97,6 +98,40 @@ struct Revision new_manifest.clear(); changesAgainstParent.clear(); } + + inline QString print() const + { + StanzaList list; + + StanzaEntry format("format_version", QStringList() << "1"); + Stanza formst; + formst.append(format); + list.append(formst); + + StanzaEntry manifest("new_manifest", new_manifest); + Stanza manst; + manst.append(manifest), + list.append(manst); + + QMapIterator > it(changesAgainstParent); + while (it.hasNext()) + { + it.next(); + + StanzaEntry revision("old_revision", it.key()); + Stanza revst; + revst.append(revision), + list.append(revst); + + foreach (Change ch, it.value()) + { + list.append(ch.stanza); + } + } + + BasicIOWriter writer(list); + return writer.write(); + } }; class GetRevision : public QAbstractItemModel, public AutomateCommand @@ -115,14 +150,17 @@ public: QModelIndex parent(const QModelIndex &) const; int rowCount(const QModelIndex &) const; int columnCount(const QModelIndex &) const; + QMap > getChangedFiles() const; + QString getRevisionText() const; public slots: void readDatabaseRevision(const DatabaseFile &, const QString &); - void readWorkspaceRevision(const WorkspacePath &); + void readWorkspaceRevision(const WorkspacePath &, const QStringList &); void showChangesAgainstParent(const QString &); signals: void revisionRead(); + void readFailed(const QString &); private: void processTaskResult(const MonotoneTask &); ============================================================ --- src/monotone/WorkspaceCommitter.cpp 8ef7bebbbcdc720ff1aa53ac9090cd3362488620 +++ src/monotone/WorkspaceCommitter.cpp d2a5ce169d18495c84ed56ecf92732b2c6646812 @@ -23,8 +23,8 @@ #include -WorkspaceCommitter::WorkspaceCommitter(const WorkspacePath & workspace) - : QObject(0), workspacePath(workspace) {} +WorkspaceCommitter::WorkspaceCommitter(const WorkspacePath & workspace, const GetRevision * model) + : QObject(0), workspacePath(workspace), revModel(model) {} WorkspaceCommitter::~WorkspaceCommitter() {} @@ -55,28 +55,12 @@ bool WorkspaceCommitter::run(const QStri // Check the current revision text for file content changes // - // FIXME: we don't yet check here if this has change since we openend the - // commit dialog! - MonotoneTask out = MonotoneUtil::runSynchronousWorkspaceTask( - workspacePath, - MonotoneTask(QStringList() << "get_revision") - ); - if (!out.isFinished()) F("task aborted"); + QMap > changedFiles = + revModel->getChangedFiles(); - // FIXME: this will probably go wrong for non-utf8 encoded filenames! - QString data = out.getOutputUtf8(); - if (out.getReturnCode() > 0) - { - C(QString("Couldn't query workspace revision: %1").arg(data)); + if (changedFiles.size() == 0) return false; - } - QString fullRevision = data; - QMap > changedFiles; - - if (!getChangedFiles(fullRevision, changedFiles)) - return false; - // // put all found files // @@ -92,31 +76,15 @@ bool WorkspaceCommitter::run(const QStri // // commit revision // - // at first get the revision id for later sanity checking - out = MonotoneUtil::runSynchronousWorkspaceTask( - workspacePath, - MonotoneTask(QStringList() << "get_current_revision_id") - ); - if (!out.isFinished()) F("task aborted"); - data = out.getOutputUtf8(); - if (out.getReturnCode() > 0) - { - C(QString("Couldn't get current revision").arg(data)); - return false; - } - - data.chop(1); - QString expectedRevisionId = data; - - // FIXME: again, this may cause problems with utf-8 encoded filenames - out = MonotoneUtil::runSynchronousWorkspaceTask( + // FIXME: this may cause problems with utf-8 encoded filenames + MonotoneTask out = MonotoneUtil::runSynchronousWorkspaceTask( workspacePath, - MonotoneTask(QStringList() << "put_revision" << fullRevision) + MonotoneTask(QStringList() << "put_revision" << revModel->getRevisionText()) ); if (!out.isFinished()) F("task aborted"); - data = out.getOutputUtf8(); + QString data = out.getOutputUtf8(); if (out.getReturnCode() > 0) { C(QString("Couldn't commit revision: %1").arg(data)); @@ -126,14 +94,6 @@ bool WorkspaceCommitter::run(const QStri data.chop(1); revisionId = data; - // did put_revision bring the expected result? - if (revisionId.compare(expectedRevisionId) != 0) - { - C(QString("Revision mismatch: expected %1, got %2") - .arg(expectedRevisionId).arg(revisionId)); - return false; - } - // attach certificates QMapIterator i(certs); while (i.hasNext()) @@ -297,62 +257,3 @@ bool WorkspaceCommitter::putCert(const Q return true; } -bool WorkspaceCommitter::getChangedFiles( - const QString & revisionText, - QMap > & changedFiles) -{ - BasicIOParser revparser(revisionText); - if (!revparser.parse()) - { - C("Could not parse basic_io."); - return false; - } - - StanzaList stanzas = revparser.getStanzas(); - foreach (Stanza st, stanzas) - { - QString path; - QPair hashes; - bool isPatch = false; - bool isAdd = false; - - foreach (StanzaEntry en, st) - { - if (en.sym == "add_file") - { - path = en.vals.at(0); - isAdd = true; - continue; - } - - if (isAdd && en.sym == "content") - { - hashes.first = en.hash; - changedFiles.insert(path, hashes); - break; - } - - if (en.sym == "patch") - { - path = en.vals.at(0); - isPatch = true; - continue; - } - - if (isPatch && en.sym == "from") - { - hashes.second = en.hash; - continue; - } - - if (isPatch && en.sym == "to") - { - hashes.first = en.hash; - changedFiles.insert(path, hashes); - break; - } - } - } - return true; -} - ============================================================ --- src/monotone/WorkspaceCommitter.h e868a69ebf244aa67a0d02ef7a9372e798754fd8 +++ src/monotone/WorkspaceCommitter.h c2507e2154158f9745dfb7743d6bf4b0b9544d17 @@ -20,6 +20,7 @@ #define WORKSPACE_COMMITTER_H #include "vocab.h" +#include "GetRevision.h" #include #include @@ -32,14 +33,13 @@ public: { Q_OBJECT public: - WorkspaceCommitter(const WorkspacePath &); + WorkspaceCommitter(const WorkspacePath &, const GetRevision *); ~WorkspaceCommitter(); bool run(const QString &, const QString &, const QString &, const QString &); inline QString getRevisionId() const { return revisionId; } private: - bool getChangedFiles(const QString &, QMap > &); bool putFile(const QString &, const QString &, const QString &); bool putCert(const QString &, const QString &, const QString &, const QString &); bool writeRevision(const QString &); @@ -47,6 +47,7 @@ private: QString revisionId; WorkspacePath workspacePath; + const GetRevision * revModel; }; #endif ============================================================ --- src/view/InventoryView.cpp d66ba062f6aa10dcc2902bfb3cc938677085b884 +++ src/view/InventoryView.cpp cfb5a587e2de5102d66c54d272772d8c5588b14b @@ -519,11 +519,10 @@ void InventoryView::slotOpen() void InventoryView::slotOpen() { - QModelIndex index(getSingleSelection()); - if (!index.isValid()) return; + QList items = getSelectedItems(); + if (items.size() == 0) return; - ModelItem * item = static_cast(index.internalPointer()); - InventoryItem * invitem = dynamic_cast(item); + InventoryItem * invitem = dynamic_cast(items.at(0)); if (!invitem) return; @@ -543,7 +542,42 @@ void InventoryView::slotCommit() void InventoryView::slotCommit() { - C("Not implemented."); + QList items = getSelectedItems(); + if (items.size() == 0) return; + + QStringList paths; + foreach (ModelItem * item, items) + { + InventoryItem * invitem = dynamic_cast(item); + + // not an inventory item + if (!invitem) continue; + + // check if the node has committable changes + if (!invitem->hasChangedRecursive()) continue; + + // rename the "root" directory to ".", since empty restrictions + // a la "" will make mtn bail out + QString path = invitem->getPath(); + if (path.isEmpty()) + { + path = "."; + } + paths.push_back(path); + } + + if (paths.size() == 0) + { + QMessageBox::information( + this, + tr("Items can't be committed"), + tr("None of the selected items can be committed."), + QMessageBox::Ok + ); + return; + } + + emit commitRevision(paths); } void InventoryView::slotRevert() @@ -574,11 +608,10 @@ void InventoryView::slotFileDiff() void InventoryView::slotFileDiff() { - QModelIndex index(getSingleSelection()); - if (!index.isValid()) return; + QList items = getSelectedItems(); + if (items.size() == 0) return; - ModelItem * item = static_cast(index.internalPointer()); - InventoryItem * invitem = dynamic_cast(item); + InventoryItem * invitem = dynamic_cast(items.at(0)); if (!invitem) return; @@ -594,11 +627,10 @@ void InventoryView::slotFileHistory() void InventoryView::slotFileHistory() { - QModelIndex index(getSingleSelection()); - if (!index.isValid()) return; + QList items = getSelectedItems(); + if (items.size() == 0) return; - ModelItem * item = static_cast(index.internalPointer()); - InventoryItem * invitem = dynamic_cast(item); + InventoryItem * invitem = dynamic_cast(items.at(0)); if (!invitem) return; @@ -620,11 +652,10 @@ void InventoryView::slotRevisionDiff() void InventoryView::slotRevisionDiff() { - QModelIndex index(getSingleSelection()); - if (!index.isValid()) return; + QList items = getSelectedItems(); + if (items.size() == 0) return; - ModelItem * item = static_cast(index.internalPointer()); - InventoryItem * invitem = dynamic_cast(item); + InventoryItem * invitem = dynamic_cast(items.at(0)); if (!invitem) return; @@ -632,25 +663,30 @@ void InventoryView::slotRevisionDiff() emit diffRevision(invitem->getPath(), QString(), QString()); } -QModelIndex InventoryView::getSingleSelection(bool mapToSource /* = true */) const +QList InventoryView::getSelectedItems() const { QItemSelectionModel * selectionModel = this->selectionModel(); QList list(selectionModel->selectedIndexes()); + QList items; + if (list.size() == 0) { - D("No item selected."); - return QModelIndex(); + return items; } - if (list.size() > 1) + const QSortFilterProxyModel * proxyModel = + dynamic_cast(model()); + + foreach (QModelIndex index, list) { - D("Multiple items selected, only returning the first."); + if (proxyModel) + { + index = proxyModel->mapToSource(index); + } + items.push_back(static_cast(index.internalPointer())); } - - if (!mapToSource) return list[0]; - - return static_cast(list[0].model())->mapToSource(list[0]); + return items; } void InventoryView::itemClicked(const QModelIndex & index) ============================================================ --- src/view/InventoryView.h dd276275934c9f0737d6076a745656efa9e1a9e3 +++ src/view/InventoryView.h ba606e7bfbdd1fdeacd6a0e8d6d5a57828c40027 @@ -21,6 +21,7 @@ #include "TreeView.h" #include "InventoryViewDelegate.h" +#include "InventoryItem.h" #include #include @@ -46,12 +47,13 @@ signals: void diffRevision(const QString &, const QString &, const QString &); void diffFile(const QString &); void fileHistory(const QString &); + void commitRevision(const QStringList &); private: enum DefaultAction { None, Chdir, Open, FileDiff, Commit }; void setModel(QAbstractItemModel *); - QModelIndex getSingleSelection(bool mapToSource = true) const; + QList getSelectedItems() const; DefaultAction getDefaultAction(const QModelIndex &) const; void createAndConnectContextActions(); void closeEvent(); ============================================================ --- src/view/WorkspaceWindow.cpp a57527afe8592e57cc8c5deb5d0d1f927b81aa5d +++ src/view/WorkspaceWindow.cpp bcffd1a6e62185ad34ee9d9d0013e58c4556252b @@ -146,6 +146,11 @@ void WorkspaceWindow::setup() ); connect( + listView, SIGNAL(commitRevision(const QStringList &)), + dialogManager, SLOT(showCommitRevision(const QStringList &)) + ); + + connect( listView, SIGNAL(openFile(const QString &)), this, SLOT(openFile(const QString &)) ); @@ -158,6 +163,11 @@ void WorkspaceWindow::setup() ); connect( + treeView, SIGNAL(commitRevision(const QStringList &)), + dialogManager, SLOT(showCommitRevision(const QStringList &)) + ); + + connect( treeView, SIGNAL(openFile(const QString &)), this, SLOT(openFile(const QString &)) ); ============================================================ --- src/view/dialogs/CommitRevision.cpp 9c06833957c547802f3c3a0873ed10640f2537a1 +++ src/view/dialogs/CommitRevision.cpp 489a71f2d951d413ae11e62f8c62d9c754c1aa6d @@ -41,6 +41,11 @@ CommitRevision::CommitRevision(QWidget * ); connect( + revModel, SIGNAL(readFailed(const QString &)), + this, SLOT(readFailed(const QString &)) + ); + + connect( previousChangelogEntryList, SIGNAL(currentIndexChanged(int)), this, SLOT(setChangelogEntryFromList(int)) ); @@ -56,9 +61,9 @@ CommitRevision::~CommitRevision() delete revModel; } -void CommitRevision::readWorkspaceRevision() +void CommitRevision::readWorkspaceRevision(const QStringList & paths) { - revModel->readWorkspaceRevision(workspacePath); + revModel->readWorkspaceRevision(workspacePath, paths); QStringList entries = Settings::getItemList("ChangelogEntries"); QRegExp re("\\s+"); @@ -167,7 +172,7 @@ void CommitRevision::accept() selectedKey = key; } - WorkspaceCommitter committer(workspacePath); + WorkspaceCommitter committer(workspacePath, revModel); if (!committer.run(selectedKey, branch, author, changelogEntry->toPlainText())) { @@ -189,17 +194,18 @@ void CommitRevision::revisionRead() void CommitRevision::revisionRead() { - if (revModel->rowCount(QModelIndex()) == 0) - { - QMessageBox::information( - this, - tr("No changes"), - tr("The current workspace has no committable changes."), - QMessageBox::Ok - ); - reject(); - } + changesAgainstParent->addItems(revModel->getParentRevisions()); +} - changesAgainstParent->addItems(revModel->getParentRevisions()); +void CommitRevision::readFailed(const QString & error) +{ + QMessageBox::information( + this, + tr("Error reading workspace revision"), + tr("The workspace revision could not be read. monotone returned:\n%1") + .arg(error), + QMessageBox::Ok + ); + reject(); } ============================================================ --- src/view/dialogs/CommitRevision.h fdc575faa9b56117ee49625e3b70242b180ecb9f +++ src/view/dialogs/CommitRevision.h c740442a658574064b5895315a08a42af5cc36dc @@ -32,7 +32,7 @@ public slots: ~CommitRevision(); public slots: - void readWorkspaceRevision(); + void readWorkspaceRevision(const QStringList &); signals: void revisionCommitted(const QString &); @@ -44,6 +44,7 @@ private slots: private slots: void setChangelogEntryFromList(int); void revisionRead(); + void readFailed(const QString &); void accept(); }; ============================================================ --- src/view/dialogs/WorkspaceDialogManager.cpp dd484a907c3f11a9c073fc3fcd7e2778360ee831 +++ src/view/dialogs/WorkspaceDialogManager.cpp b374e93b4c8357cf23e4741a0aa7e05212dc0dd7 @@ -52,8 +52,14 @@ void WorkspaceDialogManager::init(const cleanup(); } + void WorkspaceDialogManager::showCommitRevision() { + showCommitRevision(QStringList()); +} + +void WorkspaceDialogManager::showCommitRevision(const QStringList & paths) +{ if (!commitRevision) { commitRevision = new CommitRevision(parentWidget(), workspacePath); @@ -64,7 +70,7 @@ void WorkspaceDialogManager::showCommitR ); } - commitRevision->readWorkspaceRevision(); + commitRevision->readWorkspaceRevision(paths); showDialog(commitRevision); } ============================================================ --- src/view/dialogs/WorkspaceDialogManager.h e874a262a700fda55d233642fecb0f7d59ce0240 +++ src/view/dialogs/WorkspaceDialogManager.h abc57b99c46faa051f70c870431e300b2edc4a70 @@ -42,6 +42,7 @@ public slots: public slots: void showCommitRevision(); + void showCommitRevision(const QStringList &); void showUnaccountedRenames(const QMap &); void showUpdateWorkspace(); void showFileDiff(const QString &);