# # # add_file "res/forms/file_history.ui" # content [1dda121627d78bc7d2eedd22f134c967ac4db66c] # # add_file "src/model/GetContentChanged.cpp" # content [f3b84782ab44fdf363e2af70d5bee4b961afeefe] # # add_file "src/model/GetContentChanged.h" # content [441bbf74054ad6b6c8d316db82096d3b62fcedb1] # # add_file "src/view/dialogs/FileHistory.cpp" # content [822c638698d0c97987e1bc2c58e9a9e144391f84] # # add_file "src/view/dialogs/FileHistory.h" # content [a55e76d5c71b96d4ed70a74ab97a4e5ebcec8fcc] # # patch "guitone.pro" # from [aca01447662a0cd5ace5f48f12d15759f1f6cb17] # to [62bc1f270a3784fd51110c8236bc2aac67344929] # # patch "src/monotone/MonotoneDelegate.cpp" # from [84dbd3a0dff4a0ffddf39e6a7e25d1735d3b5f14] # to [97e18875b8b50bf0d64b6e5d6bedfba1c77a24e6] # # patch "src/view/InventoryView.cpp" # from [9ab95e9d6627610fb2567709fb8a912e93eeb281] # to [058bd961e53ade94bbe566cf309f57a1ea3d4298] # # patch "src/view/InventoryView.h" # from [0ad2ef23cc24538fcd3fd656b712f7b6dca17e3e] # to [fd0d9c5eb87a628057d22b2a41426dcbbe84ca03] # ============================================================ --- res/forms/file_history.ui 1dda121627d78bc7d2eedd22f134c967ac4db66c +++ res/forms/file_history.ui 1dda121627d78bc7d2eedd22f134c967ac4db66c @@ -0,0 +1,135 @@ + + FileHistoryDialog + + + + 0 + 0 + 470 + 372 + + + + History of %1 + + + :/icons/guitone.png + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + Qt::Vertical + + + + true + + + QAbstractItemView::SingleSelection + + + false + + + false + + + + + true + + + QAbstractItemView::NoSelection + + + false + + + false + + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + + TreeView + QTreeView +
TreeView.h
+
+ + Splitter + QSplitter +
Splitter.h
+
+
+ + + + + + closeButton + clicked() + FileHistoryDialog + close() + + + 229 + 252 + + + 199 + 149 + + + + +
============================================================ --- src/model/GetContentChanged.cpp f3b84782ab44fdf363e2af70d5bee4b961afeefe +++ src/model/GetContentChanged.cpp f3b84782ab44fdf363e2af70d5bee4b961afeefe @@ -0,0 +1,338 @@ +/*************************************************************************** + * 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 "GetContentChanged.h" +#include "BasicIOParser.h" + +#include + +GetContentChanged::GetContentChanged(QObject *parent) + : QAbstractItemModel(parent) +{ + mtnDelegate = new MonotoneDelegate(this); +} + +GetContentChanged::~GetContentChanged() +{ + revisions.clear(); + delete mtnDelegate; +} + +// +// The basic flow is the following: +// +// [ workspace parent revision ] [ path in this revision ] +// \ / +// \ / +// \ / +// | +// V +// |---------------> [ get content changed ] +// | | +// | V +// | [ add the rev(s) to the set ] +// | | +// | V +// |------ < ------ [ get parents of rev(s) ] -> stop if no parents +// | | +// | V +// | [ get corresponding path in the parent ] -> stop if no path +// | | +// -------------- < ------------- +// +bool GetContentChanged::readChanges(const QString & path) +{ + // clear current attributes list + revisions.clear(); + // reset the view + reset(); + + // find a starting point + // FIXME: we assume that the given path is part of this revision! + QString startRev = MonotoneDelegate::getBaseWorkspaceRevision(this); + Q_ASSERT(!startRev.isNull()); + D(QString("Starting with %1").arg(startRev)); + + pathInRevision.insert(startRev, path); + startPath = path; + + return queryContentChanged(startRev, path); +} + +bool GetContentChanged::queryContentChanged(const QString & rev, const QString & path) +{ + D(QString("get_content_changed for %1 starting from %2").arg(path).arg(rev)); + + commandStack.enqueue(ContentChanged); + + QStringList cmd; + cmd << "get_content_changed" << rev << path; + return mtnDelegate->triggerCommand(cmd); +} + +bool GetContentChanged::queryParents(const QString & rev) +{ + D(QString("parents for %1").arg(rev)); + + commandStack.enqueue(Parents); + revisionStack.enqueue(rev); + + QStringList cmd; + cmd << "parents" << rev; + return mtnDelegate->triggerCommand(cmd); +} + +bool GetContentChanged::queryCorrespondingPath(const QString & par) +{ + commandStack.enqueue(CorrespondingPath); + Q_ASSERT(!revisionStack.isEmpty()); + QString rev = revisionStack.dequeue(); + Q_ASSERT(pathInRevision.contains(rev)); + QString path = pathInRevision.value(rev); + + D(QString("get_corresponding_path for %1, base %1, parent %2").arg(path).arg(rev).arg(par)); + + QStringList cmd; + cmd << "get_corresponding_path" << rev << path << par; + return mtnDelegate->triggerCommand(cmd); +} + + +void GetContentChanged::parseOutput() +{ + // this method is called when we either called get_content_changed, + // parents or get_corresponding_path + // to decide what to do next, we need to know what was triggered + // lately in the queue + Command current = commandStack.dequeue(); + + if (current == Parents) + { + if (AutomateCommand::data.isEmpty()) + { + D("No parents found"); + + // no more commands in the queue? we're finished! + if (commandStack.size() == 0) + { + D("Finished"); + reset(); + emit changesRead(); + } + return; + } + + QStringList parents = AutomateCommand::data.split( + '\n', QString::SkipEmptyParts + ); + + D(QString("Found parents %1").arg(parents.join(","))); + + foreach (QString par, parents) + { + parentStack.enqueue(par); + Q_ASSERT(queryCorrespondingPath(par)); + } + return; + } + + if (current == ContentChanged) + { + // since we're looking for a file in a certain revision + // _beforehand_ via get_corresponding_path, we should always + // get a stanza out here + BasicIOParser parser(AutomateCommand::data); + Q_ASSERT(parser.parse()); + StanzaList stanzas = parser.getStanzas(); + foreach (Stanza st, stanzas) + { + Q_ASSERT(st.size() == 1); + QString rev = st.at(0).hash; + Q_ASSERT(!rev.isNull()); + + D(QString("Next rev with content mark %1").arg(rev)); + + if (!revisions.contains(rev)) + { + // ensure that the current revision is also in the + // set of known revisions for this file + if (revisions.size() > 0) + { + QString lastMarkedRev = revisions.last(); + Q_ASSERT(pathInRevision.contains(lastMarkedRev)); + QString lastPath = pathInRevision.value(lastMarkedRev); + pathInRevision.insert(rev, lastPath); + } + else + { + // apparently this is the first marked revision we + // encounter, assign the startPath to it + pathInRevision.insert(rev, startPath); + } + + // now append the revision itself in the ordered list + revisions.append(rev); + } + Q_ASSERT(queryParents(rev)); + } + return; + } + + if (current == CorrespondingPath) + { + // check if the file exists in the current revision, + // if not, stop here + if (AutomateCommand::data.isEmpty()) + { + D("No corresponding path"); + + // no more commands in the queue? we're finished! + if (commandStack.size() == 0) + { + D("Finished"); + reset(); + emit changesRead(); + } + return; + } + + BasicIOParser parser(AutomateCommand::data); + Q_ASSERT(parser.parse()); + StanzaList stanzas = parser.getStanzas(); + Q_ASSERT(stanzas.size() == 1); + Stanza st = stanzas.at(0); + Q_ASSERT(st.size() == 1); + StanzaEntry en = st.at(0); + Q_ASSERT(en.sym == "file" && en.vals.size() == 1); + QString path = en.vals.at(0); + + D(QString("Found path %1").arg(path)); + + Q_ASSERT(!parentStack.isEmpty()); + Q_ASSERT(queryContentChanged(parentStack.dequeue(), path)); + return; + } + + Q_ASSERT(false); +} + +bool GetContentChanged::handleError(int retCode) +{ + if (retCode == 2) + { + Q_ASSERT(commandStack.size() > 0); + + // FIXME: this is a big hack, since we assume that the only error 2 + // we can get here for this command basically reads like + // file "foo" doesn't exists in revision "bar" + // but yeah, localized string parsing is stupid as well + if (commandStack.head() == CorrespondingPath) + { + AutomateCommand::data.clear(); + parseOutput(); + return true; + } + } + + return false; +} + +int GetContentChanged::columnCount(const QModelIndex & parent) const +{ + return 2; +} + +QVariant GetContentChanged::data(const QModelIndex & index, int role) const +{ + if (!index.isValid()) + { + return QVariant(); + } + + int col = index.column(); + + if (role == Qt::FontRole && col == 0) + { + QFont font; + font.setStyleHint(QFont::Courier); + font.setFamily("Courier"); + return QVariant(font); + } + + if (role == Qt::DisplayRole) + { + int row = index.row(); + if (row >= revisions.size()) return QVariant(); + QString rev = revisions.at(row); + Q_ASSERT(pathInRevision.contains(rev)); + + switch (col) + { + case 0: return QVariant(rev); + case 1: return QVariant(pathInRevision.value(rev)); + } + return QVariant(); + } + + return QVariant(); +} + +Qt::ItemFlags GetContentChanged::flags(const QModelIndex & index) const +{ + if (index.isValid()) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + return 0; +} + +QVariant GetContentChanged::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + switch (section) + { + case 0: return QVariant(tr("Revision ID")); + case 1: return QVariant(tr("Path")); + } + } + return QVariant(); +} + +int GetContentChanged::rowCount(const QModelIndex & parent) const +{ + return revisions.size(); +} + +QModelIndex GetContentChanged::index(int row, int column, const QModelIndex & parent) const +{ + if (!hasIndex(row, column, parent)) + { + return QModelIndex(); + } + + return createIndex(row, column, 0); +} + +QModelIndex GetContentChanged::parent(const QModelIndex & index) const +{ + return QModelIndex(); +} + ============================================================ --- src/model/GetContentChanged.h 441bbf74054ad6b6c8d316db82096d3b62fcedb1 +++ src/model/GetContentChanged.h 441bbf74054ad6b6c8d316db82096d3b62fcedb1 @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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 GETCONTENTCHANGED_H +#define GETCONTENTCHANGED_H + +#include "AutomateCommand.h" +#include "MonotoneDelegate.h" + +#include +#include +#include + +typedef QList RevisionList; + +class GetContentChanged : public QAbstractItemModel, public AutomateCommand +{ + Q_OBJECT +public: + GetContentChanged(QObject*); + virtual ~GetContentChanged(); + + // 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; + int rowCount(const QModelIndex&) const; + int columnCount(const QModelIndex&) const; + +public slots: + bool readChanges(const QString &); + +signals: + void changesRead(); + +private: + bool queryContentChanged(const QString &, const QString &); + bool queryParents(const QString &); + bool queryCorrespondingPath(const QString &); + + void parseOutput(); + bool handleError(int); + + RevisionList revisions; + MonotoneDelegate * mtnDelegate; + + enum Command { ContentChanged, CorrespondingPath, Parents }; + + QQueue commandStack; + QQueue revisionStack; + QQueue parentStack; + + QMap pathInRevision; + QString startPath; +}; + +#endif + ============================================================ --- src/view/dialogs/FileHistory.cpp 822c638698d0c97987e1bc2c58e9a9e144391f84 +++ src/view/dialogs/FileHistory.cpp 822c638698d0c97987e1bc2c58e9a9e144391f84 @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2006 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 "FileHistory.h" + +FileHistory::FileHistory(QWidget * parent, const QString & path): Dialog(parent) +{ + setupUi(this); + Dialog::init(); + + // OSX sheet-alike dialog + setWindowFlags(Qt::Sheet); + + splitter->init(); + + changeModel = new GetContentChanged(this); + certsModel = new Certs(this); + + // assign the models to the views + revisionList->setModel(changeModel); + certList->setModel(certsModel); + + // display the certs of a selected revision on click + connect( + revisionList, SIGNAL(clicked(const QModelIndex &)), + this, SLOT(readCerts(const QModelIndex &)) + ); + + QString title = windowTitle(); + setWindowTitle(title.arg(path)); + + // read the changes + Q_ASSERT(changeModel->readChanges(path)); +} + +FileHistory::~FileHistory() +{ + delete changeModel; + delete certsModel; +} + +void FileHistory::readCerts(const QModelIndex & index) +{ + if (!index.isValid()) return; + + QModelIndex revIdx = changeModel->index(index.row(), 0, QModelIndex()); + QString rev(revIdx.data().toString()); + + if (!certsModel->readCerts(rev)) + { + C(QString("Couldn't read certs for %1").arg(rev)); + } +} + ============================================================ --- src/view/dialogs/FileHistory.h a55e76d5c71b96d4ed70a74ab97a4e5ebcec8fcc +++ src/view/dialogs/FileHistory.h a55e76d5c71b96d4ed70a74ab97a4e5ebcec8fcc @@ -0,0 +1,45 @@ +/*************************************************************************** + * 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 FILE_HISTORY_H +#define FILE_HISTORY_H + +#include "Dialog.h" +#include "ui_file_history.h" +#include "Certs.h" +#include "GetContentChanged.h" + +class FileHistory : public Dialog, private Ui::FileHistoryDialog +{ + Q_OBJECT + +public: + FileHistory(QWidget *, const QString &); + ~FileHistory(); + +private: + GetContentChanged * changeModel; + Certs * certsModel; + +private slots: + void readCerts(const QModelIndex &); +}; + +#endif ============================================================ --- guitone.pro aca01447662a0cd5ace5f48f12d15759f1f6cb17 +++ guitone.pro 62bc1f270a3784fd51110c8236bc2aac67344929 @@ -36,6 +36,7 @@ HEADERS += src/view/MainWindow.h \ src/view/dialogs/ChangesetBrowser.h \ src/view/dialogs/RevisionManifest.h \ src/view/dialogs/CommitRevision.h \ + src/view/dialogs/FileHistory.h \ src/monotone/Monotone.h \ src/monotone/MonotoneDelegate.h \ src/monotone/FileExporter.h \ @@ -60,6 +61,7 @@ HEADERS += src/view/MainWindow.h \ src/model/Ancestors.h \ src/model/GetBranchLog.h \ src/model/GetRevision.h \ + src/model/GetContentChanged.h \ src/util/IconProvider.h \ src/util/AbstractParser.h \ src/util/BasicIOParser.h \ @@ -94,6 +96,7 @@ SOURCES += src/view/MainWindow.cpp \ src/view/dialogs/ChangesetBrowser.cpp \ src/view/dialogs/RevisionManifest.cpp \ src/view/dialogs/CommitRevision.cpp \ + src/view/dialogs/FileHistory.cpp \ src/monotone/Monotone.cpp \ src/monotone/MonotoneDelegate.cpp \ src/monotone/FileExporter.cpp \ @@ -118,6 +121,7 @@ SOURCES += src/view/MainWindow.cpp \ src/model/Ancestors.cpp \ src/model/GetBranchLog.cpp \ src/model/GetRevision.cpp \ + src/model/GetContentChanged.cpp \ src/util/IconProvider.cpp \ src/util/AbstractParser.cpp \ src/util/BasicIOParser.cpp \ @@ -145,7 +149,9 @@ FORMS += res/forms/select_revision.ui res/forms/changeset_browser.ui \ res/forms/manifest.ui \ res/forms/commit_revision.ui \ - res/forms/application_update.ui + res/forms/application_update.ui \ + res/forms/file_history.ui + UI_DIR = tmp OBJECTS_DIR = tmp ============================================================ --- src/monotone/MonotoneDelegate.cpp 84dbd3a0dff4a0ffddf39e6a7e25d1735d3b5f14 +++ src/monotone/MonotoneDelegate.cpp 97e18875b8b50bf0d64b6e5d6bedfba1c77a24e6 @@ -91,16 +91,20 @@ QString MonotoneDelegate::getBaseWorkspa Monotone * mtn = MTN(obj); int commandNumber; - if (!mtn->executeCommand(QStringList() << "get_base_revision_id", commandNumber) || - mtn->getReturnCode(commandNumber) > 0) + bool ret = mtn->executeCommand( + QStringList() << "get_base_revision_id", commandNumber + ); + + QString data = mtn->getDecodedData(commandNumber); + + if (!ret || mtn->getReturnCode(commandNumber) > 0) { - qWarning("Could not execute get_base_revision_id"); - return false; + C(QString("Could not execute get_base_revision_id: %1").arg(data)); + return QString(); } - QString baseRevision = mtn->getDecodedData(commandNumber); - baseRevision.chop(1); - return baseRevision; + data.chop(1); + return data; } QString MonotoneDelegate::getOption(QObject * obj, const QString & opt) @@ -114,8 +118,7 @@ QString MonotoneDelegate::getOption(QObj if (mtn->getReturnCode(cmdNum) > 0) { - qCritical("Couldn't retrieve option %s: %s", - qPrintable(opt), qPrintable(data)); + C(QString("Couldn't retrieve option %1: %2").arg(opt).arg(data)); return QString(); } ============================================================ --- src/view/InventoryView.cpp 9ab95e9d6627610fb2567709fb8a912e93eeb281 +++ src/view/InventoryView.cpp 058bd961e53ade94bbe566cf309f57a1ea3d4298 @@ -24,6 +24,7 @@ #include "InventoryItem.h" #include "Monotone.h" #include "FileDiff.h" +#include "FileHistory.h" #include "RevisionDiff.h" #include "Guitone.h" @@ -87,17 +88,93 @@ void InventoryView::setType(Type t) } } +void InventoryView::createAndConnectContextActions() +{ + actChdir = new QAction(tr("Go into"), this); + actChdir->setStatusTip(tr("Go into the directory")); + connect(actChdir, SIGNAL(triggered()), this, SLOT(slotChdir())); + + actOpen = new QAction(tr("Open"), this); + actOpen->setStatusTip(tr("Open in default program")); + connect(actOpen, SIGNAL(triggered()), this, SLOT(slotOpen())); + + actAdd = new QAction(tr("Add"), this); + actAdd->setStatusTip(tr("Add to workspace")); + connect(actAdd, SIGNAL(triggered()), this, SLOT(slotAdd())); + + actRemove = new QAction(tr("Remove"), this); + actRemove->setStatusTip(tr("Remove from workspace")); + connect(actRemove, SIGNAL(triggered()), this, SLOT(slotRemove())); + + actCommit = new QAction(tr("Commit"), this); + actCommit->setStatusTip(tr("Commit")); + connect(actCommit, SIGNAL(triggered()), this, SLOT(slotCommit())); + + actIgnore = new QAction(tr("Ignore"), this); + actIgnore->setStatusTip(tr("Ignore file")); + connect(actIgnore, SIGNAL(triggered()), this, SLOT(slotIgnore())); + + actUnignore = new QAction(tr("Unignore"), this); + actUnignore->setStatusTip(tr("Unignore file")); + connect(actUnignore, SIGNAL(triggered()), this, SLOT(slotUnignore())); + + actRevert = new QAction(tr("Revert"), this); + actRevert->setStatusTip(tr("Revert uncommitted changes")); + connect(actRevert, SIGNAL(triggered()), this, SLOT(slotRevert())); + + actFileDiff = new QAction(tr("Diff"), this); + actFileDiff->setStatusTip(tr("Diff against base revision")); + connect(actFileDiff, SIGNAL(triggered()), this, SLOT(slotFileDiff())); + + actFileHistory = new QAction(tr("History"), this); + actFileHistory->setStatusTip(tr("Display the history of this file")); + connect(actFileHistory, SIGNAL(triggered()), this, SLOT(slotFileHistory())); + + actRevisionDiff = new QAction(tr("Diff all"), this); + actRevisionDiff->setStatusTip(tr("Show all differences")); + connect(actRevisionDiff, SIGNAL(triggered()), this, SLOT(slotRevisionDiff())); + + actRename = new QAction(tr("Rename"), this); + actRename->setStatusTip(tr("Rename file")); + connect(actRename, SIGNAL(triggered()), this, SLOT(slotRename())); + + actAddMultiple = new QAction(tr("Add %1 items"), this); + actAddMultiple->setStatusTip(tr("Add multiple items")); + connect(actAddMultiple, SIGNAL(triggered()), this, SLOT(slotAdd())); + + actRemoveMultiple = new QAction(tr("Remove %1 items"), this); + actRemoveMultiple->setStatusTip(tr("Remove multiple items")); + connect(actRemoveMultiple, SIGNAL(triggered()), this, SLOT(slotRemove())); + + actCommitMultiple = new QAction(tr("Commit %1 items"), this); + actCommitMultiple->setStatusTip(tr("Commit multiple items")); + connect(actCommitMultiple, SIGNAL(triggered()), this, SLOT(slotCommit())); + + actIgnoreMultiple = new QAction(tr("Ignore %1 items"), this); + actIgnoreMultiple->setStatusTip(tr("Ignore multiple items")); + connect(actIgnoreMultiple, SIGNAL(triggered()), this, SLOT(slotIgnore())); + + actUnignoreMultiple = new QAction(tr("Unignore %1 items"), this); + actUnignoreMultiple->setStatusTip(tr("Unignore multiple items")); + connect(actUnignoreMultiple, SIGNAL(triggered()), this, SLOT(slotUnignore())); + + actRevertMultiple = new QAction(tr("Revert %1 items"), this); + actRevertMultiple->setStatusTip(tr("Revert multiple items")); + connect(actRevertMultiple, SIGNAL(triggered()), this, SLOT(slotRevert())); +} + InventoryView::~InventoryView() { delete actChdir; - delete actOpen; - delete actAdd; - delete actRemove; - delete actCommit; - delete actIgnore; - delete actUnignore; + delete actOpen; + delete actAdd; + delete actRemove; + delete actCommit; + delete actIgnore; + delete actUnignore; delete actRevert; - delete actFileDiff; + delete actFileDiff; + delete actFileHistory; delete actRevisionDiff; delete actRename; delete actAddMultiple; @@ -215,6 +292,8 @@ void InventoryView::slotContextMenuReque menu.addAction(actFileDiff); } } + + menu.addAction(actFileHistory); } // @@ -330,77 +409,6 @@ void InventoryView::slotContextMenuReque } } -void InventoryView::createAndConnectContextActions(void) -{ - actChdir = new QAction(tr("Go into"), this); - actChdir->setStatusTip(tr("Go into the directory")); - connect(actChdir, SIGNAL(triggered()), this, SLOT(slotChdir())); - - actOpen = new QAction(tr("Open"), this); - actOpen->setStatusTip(tr("Open in default program")); - connect(actOpen, SIGNAL(triggered()), this, SLOT(slotOpen())); - - actAdd = new QAction(tr("Add"), this); - actAdd->setStatusTip(tr("Add to workspace")); - connect(actAdd, SIGNAL(triggered()), this, SLOT(slotAdd())); - - actRemove = new QAction(tr("Remove"), this); - actRemove->setStatusTip(tr("Remove from workspace")); - connect(actRemove, SIGNAL(triggered()), this, SLOT(slotRemove())); - - actCommit = new QAction(tr("Commit"), this); - actCommit->setStatusTip(tr("Commit")); - connect(actCommit, SIGNAL(triggered()), this, SLOT(slotCommit())); - - actIgnore = new QAction(tr("Ignore"), this); - actIgnore->setStatusTip(tr("Ignore file")); - connect(actIgnore, SIGNAL(triggered()), this, SLOT(slotIgnore())); - - actUnignore = new QAction(tr("Unignore"), this); - actUnignore->setStatusTip(tr("Unignore file")); - connect(actUnignore, SIGNAL(triggered()), this, SLOT(slotUnignore())); - - actRevert = new QAction(tr("Revert"), this); - actRevert->setStatusTip(tr("Revert uncommitted changes")); - connect(actRevert, SIGNAL(triggered()), this, SLOT(slotRevert())); - - actFileDiff = new QAction(tr("Diff"), this); - actFileDiff->setStatusTip(tr("Diff against base revision")); - connect(actFileDiff, SIGNAL(triggered()), this, SLOT(slotFileDiff())); - - actRevisionDiff = new QAction(tr("Diff all"), this); - actRevisionDiff->setStatusTip(tr("Show all differences")); - connect(actRevisionDiff, SIGNAL(triggered()), this, SLOT(slotRevisionDiff())); - - actRename = new QAction(tr("Rename"), this); - actRename->setStatusTip(tr("Rename file")); - connect(actRename, SIGNAL(triggered()), this, SLOT(slotRename())); - - actAddMultiple = new QAction(tr("Add %1 items"), this); - actAddMultiple->setStatusTip(tr("Add multiple items")); - connect(actAddMultiple, SIGNAL(triggered()), this, SLOT(slotAdd())); - - actRemoveMultiple = new QAction(tr("Remove %1 items"), this); - actRemoveMultiple->setStatusTip(tr("Remove multiple items")); - connect(actRemoveMultiple, SIGNAL(triggered()), this, SLOT(slotRemove())); - - actCommitMultiple = new QAction(tr("Commit %1 items"), this); - actCommitMultiple->setStatusTip(tr("Commit multiple items")); - connect(actCommitMultiple, SIGNAL(triggered()), this, SLOT(slotCommit())); - - actIgnoreMultiple = new QAction(tr("Ignore %1 items"), this); - actIgnoreMultiple->setStatusTip(tr("Ignore multiple items")); - connect(actIgnoreMultiple, SIGNAL(triggered()), this, SLOT(slotIgnore())); - - actUnignoreMultiple = new QAction(tr("Unignore %1 items"), this); - actUnignoreMultiple->setStatusTip(tr("Unignore multiple items")); - connect(actUnignoreMultiple, SIGNAL(triggered()), this, SLOT(slotUnignore())); - - actRevertMultiple = new QAction(tr("Revert %1 items"), this); - actRevertMultiple->setStatusTip(tr("Revert multiple items")); - connect(actRevertMultiple, SIGNAL(triggered()), this, SLOT(slotRevert())); -} - void InventoryView::slotChdir() { QItemSelectionModel *selectionModel = this->selectionModel(); @@ -446,7 +454,7 @@ void InventoryView::changeDirectory(cons ); } -void InventoryView::slotOpen(void) +void InventoryView::slotOpen() { QModelIndex index(getSingleSelection()); if (!index.isValid()) return; @@ -478,27 +486,27 @@ void InventoryView::slotOpen(void) } } -void InventoryView::slotAdd(void) +void InventoryView::slotAdd() { qDebug("InventoryView::slotAdd!!!"); } -void InventoryView::slotRemove(void) +void InventoryView::slotRemove() { qDebug("InventoryView::slotRemove!!!"); } -void InventoryView::slotCommit(void) +void InventoryView::slotCommit() { qDebug("InventoryView::slotCommit!!!"); } -void InventoryView::slotRevert(void) +void InventoryView::slotRevert() { qDebug("InventoryView::slotRevert!!!"); } -void InventoryView::slotRename(void) +void InventoryView::slotRename() { qDebug("InventoryView::slotRename!!!"); } @@ -509,17 +517,17 @@ void InventoryView::slotRename(void) // Q: If this file is under version control, should a change // be committed in the background? // -void InventoryView::slotIgnore(void) +void InventoryView::slotIgnore() { qDebug("InventoryView::slotIgnore!!!"); } -void InventoryView::slotUnignore(void) +void InventoryView::slotUnignore() { qDebug("InventoryView::slotUnignore!!!"); } -void InventoryView::slotFileDiff(void) +void InventoryView::slotFileDiff() { QModelIndex index(getSingleSelection()); if (!index.isValid()) return; @@ -538,13 +546,41 @@ void InventoryView::slotFileDiff(void) clearSelection(); } -void InventoryView::slotRevisionDiff(void) +void InventoryView::slotFileHistory() { QModelIndex index(getSingleSelection()); if (!index.isValid()) return; InventoryItem * item = static_cast(index.internalPointer()); + QString path = item->getPath(); + // determine the original path, if needed + if (item->hasStatus(InventoryItem::RenamedFrom)) + { + InventoryItem * newItem = item->getRenamedTo(); + Q_ASSERT(newItem); + path = newItem->getPath(); + } + if (item->hasStatus(InventoryItem::RenamedTo)) + { + InventoryItem * oldItem = item->getRenamedFrom(); + Q_ASSERT(oldItem); + path = oldItem->getPath(); + } + + FileHistory dlg(this, path); + dlg.exec(); + + clearSelection(); +} + +void InventoryView::slotRevisionDiff() +{ + QModelIndex index(getSingleSelection()); + if (!index.isValid()) return; + + InventoryItem * item = static_cast(index.internalPointer()); + RevisionDiff dlg(this); dlg.init(item->getPath(), QString(), QString()); dlg.exec(); ============================================================ --- src/view/InventoryView.h 0ad2ef23cc24538fcd3fd656b712f7b6dca17e3e +++ src/view/InventoryView.h fd0d9c5eb87a628057d22b2a41426dcbbe84ca03 @@ -31,15 +31,15 @@ class InventoryView : public TreeView class InventoryView : public TreeView { - Q_OBJECT + Q_OBJECT public: - enum Type { FolderTree, FileList }; - - InventoryView(QWidget*); - ~InventoryView(); + enum Type { FolderTree, FileList }; + + InventoryView(QWidget*); + ~InventoryView(); - void setModel(QSortFilterProxyModel *); + void setModel(QSortFilterProxyModel *); void setType(Type); signals: @@ -47,20 +47,21 @@ private: private: void setModel(QAbstractItemModel *); - void createAndConnectContextActions(void); - void closeEvent(void); + void createAndConnectContextActions(); + void closeEvent(); QModelIndex getSingleSelection(bool mapToSource = true); QAction * actChdir; QAction * actOpen; - QAction * actAdd; - QAction * actRemove; - QAction * actCommit; - QAction * actIgnore; + QAction * actAdd; + QAction * actRemove; + QAction * actCommit; + QAction * actIgnore; QAction * actUnignore; QAction * actRevert; QAction * actRename; QAction * actFileDiff; + QAction * actFileHistory; QAction * actRevisionDiff; QAction * actAddMultiple; @@ -82,17 +83,18 @@ private slots: void itemClicked(const QModelIndex & index); void slotContextMenuRequested(const QModelIndexList &, const QPoint &); - void slotChdir(void); - void slotOpen(void); - void slotAdd(void); - void slotRemove(void); - void slotCommit(void); - void slotIgnore(void); - void slotUnignore(void); - void slotRevert(void); - void slotRename(void); - void slotFileDiff(void); - void slotRevisionDiff(void); + void slotChdir(); + void slotOpen(); + void slotAdd(); + void slotRemove(); + void slotCommit(); + void slotIgnore(); + void slotUnignore(); + void slotRevert(); + void slotRename(); + void slotFileDiff(); + void slotFileHistory(); + void slotRevisionDiff(); }; #endif