#
#
# patch "guitone/res/forms/commit_revision.ui"
# from [c91ce1af1162eac46c2c489763cd6738da0f9a1e]
# to [c81cdb40189d873524fd833f832a700006a5394b]
#
# patch "guitone/src/Guitone.cpp"
# from [df2c6d9a3e2178dc9d17c9b15f608d0d15188c13]
# to [429342eb3c190c0350629dfa1d822848a100e3b3]
#
# patch "guitone/src/model/GetRevision.cpp"
# from [f6421a3436ec2f167ed088d707584c9339115902]
# to [3fe7773819ed4ef94ca0bb470b5caf4b2d33caa5]
#
# patch "guitone/src/model/GetRevision.h"
# from [6d277716bb8d73b698e0106d281a1cf626cf01bb]
# to [e6d1d83047029447b8e9d5fb338cf72877458c46]
#
# patch "guitone/src/monotone/Monotone.cpp"
# from [b3a10f1cb905f11321c0ef7abcdab6eefcb659f3]
# to [c022744d0e1f616a544f8702e9bb4ff2b72a4dc6]
#
# patch "guitone/src/monotone/Monotone.h"
# from [8e3e6a9750e2ce4b0c5c42fa20d13a505eb43015]
# to [8ed8e4851e892adfd5c8d445ff798f39a6a0019b]
#
# patch "guitone/src/monotone/MonotoneDelegate.cpp"
# from [0986e7b2551f4ccf87bcecc7da446cb417514d84]
# to [aff2e9c2aa1b91433f4d50d29c58b48ed4a45844]
#
# patch "guitone/src/view/MainWindow.cpp"
# from [fbf63888c531297f7941918ebeb4ee6de9f1ed5c]
# to [3d713da4f0ef02fb7a34fd7839cfc67d7b4a1876]
#
# patch "guitone/src/view/MainWindow.h"
# from [a6eec6cd24f15814a4f00dc46cb458432930a2f1]
# to [1d9646474da2a667ec9b56ce3f30a8fc933b6969]
#
# patch "guitone/src/view/dialogs/CommitRevision.cpp"
# from [b9af9c76a9a56da8ec92fa06fe3a10b2a495046c]
# to [e796042390241526ff2848e24f0bebd8b432dc9c]
#
# patch "guitone/src/view/dialogs/CommitRevision.h"
# from [9dfc94422ee757d0387ad5c82421dc3584bad2bc]
# to [7d02ef0a24613fc88485823db77d5a9cfdbc6b35]
#
============================================================
--- guitone/res/forms/commit_revision.ui c91ce1af1162eac46c2c489763cd6738da0f9a1e
+++ guitone/res/forms/commit_revision.ui c81cdb40189d873524fd833f832a700006a5394b
@@ -5,8 +5,8 @@
0
0
- 423
- 522
+ 468
+ 565
@@ -48,6 +48,26 @@
6
-
+
+
+ 0
+
+
+ 6
+
+
-
+
+
+ Display changes against parent
+
+
+
+ -
+
+
+
+
+ -
QAbstractItemView::ExtendedSelection
============================================================
--- guitone/src/Guitone.cpp df2c6d9a3e2178dc9d17c9b15f608d0d15188c13
+++ guitone/src/Guitone.cpp 429342eb3c190c0350629dfa1d822848a100e3b3
@@ -250,12 +250,6 @@ bool Guitone::addMonotoneInstance(MainWi
bool Guitone::addMonotoneInstance(MainWindow * wnd)
{
Monotone * mtn = new Monotone(wnd);
-
- // catch critical errors from the Monotone class
- connect(
- mtn, SIGNAL(criticalError(const QString &)),
- wnd, SLOT(criticalMtnError(const QString &))
- );
// check the current monotone version and prompt the user
// to enter the correct path if there is a problem
@@ -295,11 +289,6 @@ bool Guitone::removeMonotoneInstance(Mai
Monotone * mtn = monotoneInstances.value(wnd);
- disconnect(
- mtn, SIGNAL(criticalError(const QString &)),
- wnd, SLOT(criticalMtnError(const QString &))
- );
-
delete mtn;
monotoneInstances.remove(wnd);
============================================================
--- guitone/src/model/GetRevision.cpp f6421a3436ec2f167ed088d707584c9339115902
+++ guitone/src/model/GetRevision.cpp 3fe7773819ed4ef94ca0bb470b5caf4b2d33caa5
@@ -39,8 +39,7 @@ bool GetRevision::readRevision(const QSt
bool GetRevision::readRevision(const QString & rev)
{
- oldRevision = QString();
- changelist.clear();
+ revision.clear();
QStringList cmd;
cmd << "get_revision";
@@ -56,7 +55,9 @@ void GetRevision::parseOutput()
{
BasicIOParser parser(AutomateCommand::data);
Q_ASSERT(parser.parse());
+
StanzaList list = parser.getStanzas();
+ QString currentRevision;
for (int i=0, size = list.size(); i < size; ++i)
{
@@ -81,13 +82,19 @@ void GetRevision::parseOutput()
break;
}
- // the calculated manifest is useless if we select parts of the rev
- if (j == 0 && entry.sym == "new_manifest") break;
+ if (j == 0 && entry.sym == "new_manifest")
+ {
+ Q_ASSERT(entry.vals.size() == 1);
+ revision.new_manifest = entry.vals.at(0);
+ break;
+ }
if (entry.sym == "old_revision")
{
Q_ASSERT(entry.vals.size() == 1);
- oldRevision = entry.vals.at(0);
+ currentRevision = entry.vals.at(0);
+ QList changelist;
+ revision.changesAgainstParent.insert(currentRevision, changelist);
break;
}
@@ -156,10 +163,13 @@ void GetRevision::parseOutput()
// check if we really processed an item entry
if (!found_change) continue;
-
- changelist.append(change);
+ Q_ASSERT(revision.changesAgainstParent.contains(currentRevision));
+ revision.changesAgainstParent[currentRevision].append(change);
}
+ // set the first as the default parent against which changes are displayed
+ changesAgainstParent = revision.changesAgainstParent.keys().at(0);
+
// reset the view
reset();
@@ -167,24 +177,6 @@ void GetRevision::parseOutput()
emit revisionRead();
}
-QString GetRevision::getRevisionFromSelection(const QModelIndexList & indexes)
-{
- QString dat;
- QTextStream stream(&dat);
-
- stream << "format_version \"1\"\n\n";
- stream << "old_revision [" << oldRevision << "]\n\n";
- stream << "new_manifest [" << QString().fill('0', 40) << "]\n\n";
-
- foreach (QModelIndex index, indexes)
- {
- Change * change = static_cast(index.internalPointer());
- stream << change->getStanzaData() << "\n\n";
- }
-
- return dat;
-}
-
int GetRevision::columnCount(const QModelIndex &parent) const
{
return 2;
@@ -192,15 +184,14 @@ QVariant GetRevision::data(const QModelI
QVariant GetRevision::data(const QModelIndex & index, int role) const
{
- if (!index.isValid())
- {
+ if (!index.isValid())
return QVariant();
- }
+
+ if (!revision.changesAgainstParent.contains(changesAgainstParent))
+ return QVariant();
- int row = index.row();
- if (row >= changelist.size()) return QVariant();
-
- Change change(changelist.at(row));
+ Change change =
+ revision.changesAgainstParent[changesAgainstParent].at(index.row());
if (role == Qt::DisplayRole)
{
@@ -256,18 +247,21 @@ int GetRevision::rowCount(const QModelIn
int GetRevision::rowCount(const QModelIndex & parent) const
{
- return changelist.size();
+ if (!revision.changesAgainstParent.contains(changesAgainstParent))
+ return 0;
+
+ return revision.changesAgainstParent[changesAgainstParent].size();
}
QModelIndex GetRevision::index(int row, int column, const QModelIndex & parent) const
{
- if (!hasIndex(row, column, parent))
- {
+ if (!revision.changesAgainstParent.contains(changesAgainstParent))
return QModelIndex();
- }
- Change * change = new Change(changelist.at(row));
- return createIndex(row, column, change);
+ if (row >= revision.changesAgainstParent[changesAgainstParent].size())
+ return QModelIndex();
+
+ return createIndex(row, column, NULL);
}
QModelIndex GetRevision::parent(const QModelIndex& index) const
@@ -275,3 +269,18 @@ QModelIndex GetRevision::parent(const QM
return QModelIndex();
}
+QStringList GetRevision::getParentRevisions() const
+{
+ return revision.changesAgainstParent.keys();
+}
+
+void GetRevision::showChangesAgainstParent(const QString & parent)
+{
+ QStringList parents = getParentRevisions();
+
+ if (!parents.contains(parent)) return;
+
+ changesAgainstParent = parent;
+ reset();
+}
+
============================================================
--- guitone/src/model/GetRevision.h 6d277716bb8d73b698e0106d281a1cf626cf01bb
+++ guitone/src/model/GetRevision.h e6d1d83047029447b8e9d5fb338cf72877458c46
@@ -134,8 +134,17 @@ struct Change {
}
};
-typedef QList ChangeList;
+struct Revision
+{
+ QString new_manifest;
+ QMap > changesAgainstParent;
+ inline void clear()
+ {
+ new_manifest = QString();
+ changesAgainstParent.clear();
+ }
+};
class GetRevision : public QAbstractItemModel, public AutomateCommand
{
@@ -143,9 +152,8 @@ public:
public:
GetRevision(QObject *);
virtual ~GetRevision();
+ QStringList getParentRevisions() const;
- QString getRevisionFromSelection(const QModelIndexList &);
-
// needed Qt Model methods
QVariant data(const QModelIndex &, int) const;
Qt::ItemFlags flags(const QModelIndex &) const;
@@ -157,7 +165,8 @@ public slots:
public slots:
bool readRevision(const QString &);
-
+ void showChangesAgainstParent(const QString &);
+
signals:
void revisionRead();
@@ -165,8 +174,8 @@ private:
void parseOutput();
MonotoneDelegate * mtnDelegate;
- ChangeList changelist;
- QString oldRevision;
+ Revision revision;
+ QString changesAgainstParent;
};
#endif
============================================================
--- guitone/src/monotone/Monotone.cpp b3a10f1cb905f11321c0ef7abcdab6eefcb659f3
+++ guitone/src/monotone/Monotone.cpp c022744d0e1f616a544f8702e9bb4ff2b72a4dc6
@@ -101,6 +101,12 @@ Monotone::Monotone(QObject * parent) : Q
commandCounter = -1;
// true if the process is destroyed in the destructor
isCleanExit = false;
+ // set to true to abort any running requests
+ // FIXME: we certainly need a better way to abort requested data than
+ // setting some flag which gets eventually evaluated or not
+ doAbortRequests = false;
+ // exec timeout waiter
+ timeout = false;
// inialize the process var
process = 0;
// path to the monotone binary
@@ -162,10 +168,11 @@ void Monotone::shutdownCurrentProcess()
void Monotone::shutdownCurrentProcess()
{
- // if a previous process is running, exit it cleanly
+ // if a previous process is running, exit it cleanly
if (process)
{
isCleanExit = true;
+ doAbortRequests = true;
completedCommands.clear();
commandCounter = -1;
@@ -202,13 +209,16 @@ void Monotone::shutdownCurrentProcess()
}
}
-void Monotone::setupNewProcess()
+bool Monotone::setupNewProcess()
{
Q_ASSERT(mtnBinaryPath.size() > 0);
shutdownCurrentProcess();
isCleanExit = false;
+ doAbortRequests = false;
+ timeout = false;
+
process = new QProcess(this);
// monitor if the process is exited unexpectedly
@@ -252,16 +262,36 @@ void Monotone::setupNewProcess()
D(QString("starting %1 %2").arg(mtnBinaryPath).arg(args.join(" ")));
process->start(mtnBinaryPath, args);
+
+ if (!process->waitForStarted(WaitForMonotoneStart))
+ {
+ C("Timed out waiting for monotone start");
+ return false;
+ }
+
+ timer = startTimer(1000);
+
+ while (!timeout && !doAbortRequests)
+ QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
+
+ if (!timeout) killTimer(timer);
+
+ return !doAbortRequests;
}
+void Monotone::timerEvent(QTimerEvent * event)
+{
+ killTimer(timer);
+ timeout = true;
+}
+
bool Monotone::loadWorkspace(QString workspace)
{
// try to find the _MTN directory in the given path and chdir to the root
if (!normalizeWorkspacePath(workspace)) return false;
workDir = workspace;
mode = Workspace;
- setupNewProcess();
- return true;
+ return setupNewProcess();
}
bool Monotone::loadDatabase(QString db)
@@ -270,8 +300,7 @@ bool Monotone::loadDatabase(QString db)
// escalate later on if something goes wrong, e.g. file is not writable...?
databaseFile = db;
mode = Database;
- setupNewProcess();
- return true;
+ return setupNewProcess();
}
void Monotone::processError(QProcess::ProcessError error)
@@ -316,18 +345,15 @@ void Monotone::processFinished(int code,
{
// this was a normal exit
if (code == 0 || isCleanExit) return;
-
- QString msg(process->readAllStandardError());
- emit criticalError(tr(
- "The monotone process exited unexpectedly (return code %1). Please "
- "reconfigure the path to the monotone binary in the Preferences dialog "
- "or check if the version of the database you try to load matches the "
- "monotone version you are using.\n\n"
- "monotone returned:\n%2"
- ).arg(code).arg(stripMtnPrefix(msg))
- );
+ doAbortRequests = true;
}
+QString Monotone::getStderr()
+{
+ QString output(process->readAllStandardError());
+ return stripMtnPrefix(output);
+}
+
bool Monotone::executeCommand(const QStringList & command, int & commandNumber)
{
QStringList opts;
@@ -336,8 +362,7 @@ bool Monotone::executeCommand(const QStr
bool Monotone::executeCommand(const QStringList & command, const QStringList & options, int & commandNumber)
{
- if (process->state() != QProcess::Running &&
- !process->waitForStarted(WaitForMonotoneStart))
+ if (doAbortRequests || process->state() != QProcess::Running)
{
D("monotone is not running");
return false;
@@ -348,11 +373,11 @@ bool Monotone::executeCommand(const QStr
do
{
- waiter.wait(500);
+ waiter.wait(100);
}
- while (!isCommandFinished(commandNumber));
+ while (!doAbortRequests && !isCommandFinished(commandNumber));
- return true;
+ return !doAbortRequests;
}
bool Monotone::triggerCommand(const QStringList & command, int & commandNumber)
@@ -362,8 +387,7 @@ bool Monotone::triggerCommand(const QStr
bool Monotone::triggerCommand(const QStringList & command, const QStringList & options, int & commandNumber)
{
- if (process->state() != QProcess::Running &&
- !process->waitForStarted(WaitForMonotoneStart))
+ if (doAbortRequests || process->state() != QProcess::Running)
{
D("monotone is not running");
return false;
@@ -626,7 +650,7 @@ QString Monotone::stripMtnPrefix(const Q
// FIXME: we should actually use basename(mtnBinaryPath) in case
// the binary is renamed, but I'm too lazy for this right now...
// and this would also require to make this method non-static
- QRegExp rx = QRegExp("^(?:mtn\\:)?[^:]+\\:[ ]*(.+)");
+ QRegExp rx = QRegExp("^(?:mtn\\:[ ]+)?[^:]+\\:[ ]*(.+)");
for (int i=0, j=list.size(); i output;
QMap completedCommands;
int commandCounter;
bool isCleanExit;
+ bool doAbortRequests;
QProcess * process;
QString workDir;
QString databaseFile;
QString mtnBinaryPath;
QMutex lock;
+
+ int timer;
+ bool timeout;
private slots:
void readAndParseStdout();
@@ -87,7 +93,6 @@ class Monotone : public QObject
signals:
void commandFinished();
- void criticalError(const QString &);
};
#endif
============================================================
--- guitone/src/monotone/MonotoneDelegate.cpp 0986e7b2551f4ccf87bcecc7da446cb417514d84
+++ guitone/src/monotone/MonotoneDelegate.cpp aff2e9c2aa1b91433f4d50d29c58b48ed4a45844
@@ -50,6 +50,8 @@ bool MonotoneDelegate::triggerCommand(co
return mtn->triggerCommand(cmd, opts, commandNumber);
}
+// FIXME: if a request is aborted, commandFinished is never signalled,
+// do we need to take care of that here?
void MonotoneDelegate::commandFinished()
{
QObject * obj = dynamic_cast(cmdModel);
============================================================
--- guitone/src/view/MainWindow.cpp fbf63888c531297f7941918ebeb4ee6de9f1ed5c
+++ guitone/src/view/MainWindow.cpp 3d713da4f0ef02fb7a34fd7839cfc67d7b4a1876
@@ -158,17 +158,6 @@ MainWindow::~MainWindow()
delete proxyModelFileList;
}
-void MainWindow::criticalMtnError(const QString & msg)
-{
- // restore the normal cursor
- APP->restoreOverrideCursor();
-
- QMessageBox::critical(this, tr("Critical Monotone Error"),
- msg, QMessageBox::Ok, 0, 0);
-
- close();
-}
-
// try to load the most recent workspace or database, if there are any
// if everything fails, load nothing and hide the appropriate menus
void MainWindow::loadRecent()
@@ -210,8 +199,9 @@ bool MainWindow::doLoadWorkspace(QString
{
QMessageBox::critical(
this,
- tr("Invalid workspace"),
- tr("The chosen directory is no monotone workspace!"),
+ tr("Failed to load workspace"),
+ tr("The workspace could not be loaded.\n"
+ "The last output was:\n\n%1").arg(mtn->getStderr()),
QMessageBox::Ok
);
@@ -273,12 +263,17 @@ bool MainWindow::doLoadDatabase(QString
bool MainWindow::doLoadDatabase(QString fn)
{
- // FIXME: currently a database is always loaded, but not checked
- // so this condition can actually never be false
- if (!MTN(this)->loadDatabase(fn))
+ Monotone * mtn = MTN(this);
+ if (!mtn->loadDatabase(fn))
{
- qDebug("Could not load database.");
- // remove the workspace if it was recorded as recent workspace
+ QMessageBox::critical(
+ this,
+ tr("Failed to load database"),
+ tr("The database could not be loaded.\n"
+ "The last output was:\n\n%1").arg(mtn->getStderr()),
+ QMessageBox::Ok
+ );
+
Settings::removeItemFromList("RecentDatabaseList", fn);
emit updatePreviousDatabasesMenu();
============================================================
--- guitone/src/view/MainWindow.h a6eec6cd24f15814a4f00dc46cb458432930a2f1
+++ guitone/src/view/MainWindow.h 1d9646474da2a667ec9b56ce3f30a8fc933b6969
@@ -48,7 +48,6 @@ public slots:
public slots:
void doUpdatePreviousWorkspacesMenu();
void doUpdatePreviousDatabasesMenu();
- void criticalMtnError(const QString &);
signals:
void modeChanged(Mode);
============================================================
--- guitone/src/view/dialogs/CommitRevision.cpp b9af9c76a9a56da8ec92fa06fe3a10b2a495046c
+++ guitone/src/view/dialogs/CommitRevision.cpp e796042390241526ff2848e24f0bebd8b432dc9c
@@ -53,7 +53,7 @@ CommitRevision::CommitRevision(QWidget*
connect(
revModel, SIGNAL(revisionRead()),
- this, SLOT(checkForChanges())
+ this, SLOT(revisionRead())
);
connect(
@@ -66,6 +66,11 @@ CommitRevision::CommitRevision(QWidget*
this, SLOT(setChangelogEntryFromList(int))
);
+ connect(
+ changesAgainstParent, SIGNAL(currentIndexChanged(const QString &)),
+ revModel, SLOT(showChangesAgainstParent(const QString &))
+ );
+
// initialize the text view with the most recent entry
setChangelogEntryFromList(0);
}
@@ -84,12 +89,7 @@ void CommitRevision::accept()
void CommitRevision::accept()
{
- QString newRev = revModel->getRevisionFromSelection(
- changeView->selectionModel()->selectedRows(1)
- );
-
- D(QString("CommitRevision::accept: new revision to commit:\n%1").arg(newRev));
-
+ qDebug("CommitRevision::accept: do actual commit");
Settings::addItemToList("ChangelogEntries", changelogEntry->toPlainText(), 10);
done(0);
}
@@ -110,7 +110,7 @@ void CommitRevision::invertChangesetSele
selectionModel->select(selection, QItemSelectionModel::Toggle);
}
-void CommitRevision::checkForChanges()
+void CommitRevision::revisionRead()
{
if (revModel->rowCount(QModelIndex()) == 0)
{
@@ -122,5 +122,7 @@ void CommitRevision::checkForChanges()
);
reject();
}
+
+ changesAgainstParent->addItems(revModel->getParentRevisions());
}
============================================================
--- guitone/src/view/dialogs/CommitRevision.h 9dfc94422ee757d0387ad5c82421dc3584bad2bc
+++ guitone/src/view/dialogs/CommitRevision.h 7d02ef0a24613fc88485823db77d5a9cfdbc6b35
@@ -39,7 +39,7 @@ private slots:
private slots:
void invertChangesetSelection();
void setChangelogEntryFromList(int);
- void checkForChanges();
+ void revisionRead();
void accept();
};