#
#
# add_file "res/forms/dialogs/netsync.ui"
# content [2c01c845bdfe4490cff1659390efe749d72fe544]
#
# add_file "src/view/dialogs/Netsync.cpp"
# content [8782a4afbfaf1af1871e297529c6c47cac028a55]
#
# add_file "src/view/dialogs/Netsync.h"
# content [33cb539497a787d27d32cb594a901ffd8584f4f7]
#
# patch "NEWS"
# from [ea03d1c9b0c26b701b56a1e217213eaadaa7106c]
# to [1c169dfc4599d4ea266a86ffffcec3bb77db7ecd]
#
# patch "src/model/AutomateCommand.cpp"
# from [1c819d32c321a539d0d59e100a632d17fdba16ca]
# to [80b69f1ceaee3c47a08a18914f5cda659bed27d0]
#
# patch "src/model/AutomateCommand.h"
# from [93a7d2bbd7d51d8b0f75ff9d63092ffc69aaa247]
# to [b2e0fd928d2e273b314398bc250066de03ea5348]
#
# patch "src/monotone/MonotoneThread.cpp"
# from [c15b3807460064117d7d5904624decb5f0f52759]
# to [56a8906a9d0f808ea3a08d88920bfffd1afecf69]
#
# patch "src/monotone/MonotoneThread.h"
# from [80bb125d5e5b9d5b51d3bc2eb9701f1080689c7d]
# to [8a6365f540ed8706b8eae206865dfac75fa452a3]
#
# patch "src/util/StdioParser.cpp"
# from [48c78328277cff98a5ba59e95e32c3440637c964]
# to [d4cba87dc4415fc989015ccadcc95ba28b3e50ae]
#
# patch "src/util/StdioParser.h"
# from [5f6b6793087a0d3d884c32f1cfa786632c67c647]
# to [280e28221050eecf94aac14355dc0f80c09f7dd3]
#
# patch "src/view/dialogs/DatabaseDialogManager.cpp"
# from [903fe5513823171829c2d7feaefc5996bcd05a7d]
# to [bf76575815a0ab6bf17bb5c75fe52a1f4c5db4a5]
#
# patch "src/view/dialogs/DatabaseDialogManager.h"
# from [532a5c5e04720356b89b3584d40833c422ed2a26]
# to [1a090d7cc52c821066410946fbcdd592158eddda]
#
# patch "src/view/mainwindows/DatabaseWindow.cpp"
# from [37323d919fecd0fda6c5266a8af16203b88edf04]
# to [32afece8ed33326fca00fe4180fcc440dcf07256]
#
# patch "src/view/widgets/DatabaseMenuBar.cpp"
# from [24128d740e1d3b1b08839bf94d1f348b96bf1fd4]
# to [ce3a7aa362d08e1f816cd9456b8d3fd555a4fadc]
#
# patch "src/view/widgets/DatabaseMenuBar.h"
# from [b100fad7678bb201825278f5d496dc29bd43fe26]
# to [e891dcedbca13fdf865e320f4a6026e1c5eadbb3]
#
# patch "src/vocab.h"
# from [1b2725cb1d597d7dd4035b6763f47bf02eb062cb]
# to [47f7cac5d9cfea1f8308980d3de9268b1e97a674]
#
============================================================
--- res/forms/dialogs/netsync.ui 2c01c845bdfe4490cff1659390efe749d72fe544
+++ res/forms/dialogs/netsync.ui 2c01c845bdfe4490cff1659390efe749d72fe544
@@ -0,0 +1,223 @@
+
+
+ NetsyncDialog
+
+
+
+ 0
+ 0
+ 583
+ 308
+
+
+
+
+ 0
+ 0
+
+
+
+ Synchronize with other nodes
+
+
+
+ 10
+
+
+ QLayout::SetFixedSize
+
+ -
+
+
-
+
+
+ Settings
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
-
+
+
+ Host
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Authentication
+
+
+
+ -
+
+
+ Include-Pattern
+
+
+
+ -
+
+
+ Example: net.venge.monotone*
+
+
+ *
+
+
+
+ -
+
+
+ Exclude-Pattern
+
+
+
+ -
+
+
+ Example: net.venge.monotone{,.guitone}
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+ Action
+
+
+
-
+
+
+ Pull
+
+
+ true
+
+
+
+ -
+
+
+ Push
+
+
+
+ -
+
+
+ Sync
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 300
+ 20
+
+
+
+
+ -
+
+
+ Start
+
+
+
+ -
+
+
+ Close
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
-
+
+
+ 0
+
+
+ -1
+
+
+
+ -
+
+
+
+ 11
+
+
+
+ Progress:
+
+
+ Qt::NoTextInteraction
+
+
+
+
+
+
+
+
+
+ includePattern
+ excludePattern
+
+
+
+
+ closeButton
+ clicked()
+ NetsyncDialog
+ accept()
+
+
+ 484
+ 235
+
+
+ 386
+ 238
+
+
+
+
+
============================================================
--- src/view/dialogs/Netsync.cpp 8782a4afbfaf1af1871e297529c6c47cac028a55
+++ src/view/dialogs/Netsync.cpp 8782a4afbfaf1af1871e297529c6c47cac028a55
@@ -0,0 +1,233 @@
+/***************************************************************************
+ * Copyright (C) 2009 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 3 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, see . *
+ ***************************************************************************/
+
+#include "Netsync.h"
+#include "Settings.h"
+#include "MonotoneUtil.h"
+
+#include
+
+Netsync::Netsync(QWidget * parent, const DatabaseFile & database)
+ : Dialog(parent), db(database), running(false)
+{
+ setupUi(this);
+ Dialog::init();
+
+ connect(
+ startStopButton, SIGNAL(clicked()),
+ this, SLOT(startStopClicked())
+ );
+}
+
+Netsync::~Netsync() {}
+
+void Netsync::init()
+{
+ progressWidget->hide();
+
+ QMap defaults =
+ MonotoneUtil::getDatabaseVariables(db, "database");
+
+ QList knownServers =
+ (MonotoneUtil::getDatabaseVariables(db, "known-servers")).keys();
+
+ includePattern->setText(defaults.contains("default-include-pattern") ?
+ defaults["default-include-pattern"] : "*");
+
+ excludePattern->setText(defaults.contains("default-exclude-pattern") ?
+ defaults["default-exclude-pattern"] : "");
+
+ host->clear();
+ host->addItems(knownServers);
+
+ if (defaults.contains("default-server"))
+ {
+ if (!knownServers.contains(defaults["default-server"]))
+ {
+ host->addItem(defaults["default-server"]);
+ }
+ host->setCurrentIndex(host->findText(defaults["default-server"]));
+ }
+
+ QMap privateKeys =
+ MonotoneUtil::getPrivateKeyList(db);
+
+ keys->clear();
+ keys->addItem(tr(""), QString());
+
+ for (QMap::const_iterator it = privateKeys.constBegin();
+ it != privateKeys.constEnd(); it++)
+ {
+ keys->addItem(it.value(), it.key());
+ }
+}
+
+void Netsync::start(Action act,
+ const QString & host,
+ const QString & key,
+ const QString & include,
+ const QString & exclude)
+{
+ QMap actions;
+ actions[Pull] = "pull";
+ actions[Push] = "push";
+ actions[Sync] = "sync";
+
+ QStringList cmd;
+ cmd << actions[act] << host << include;
+
+ QStringList opts;
+ if (!exclude.isEmpty())
+ {
+ opts << "exclude" << exclude;
+ }
+
+ if (!key.isEmpty())
+ {
+ opts << "key" << key;
+ }
+
+ MonotoneTask task(cmd, opts);
+ AutomateCommand::enqueueDatabaseTask(db, task);
+
+ progressText->setText(tr("Connecting to %1...").arg(host));
+ startStopButton->setText(tr("Stop"));
+ settingsGroup->setEnabled(false);
+ actionsGroup->setEnabled(false);
+ overallProgress->setMaximum(0);
+ progressWidget->show();
+ running = true;
+}
+
+void Netsync::stop()
+{
+ stopAllTasks();
+ progressWidget->hide();
+ startStopButton->setText(tr("Start"));
+ settingsGroup->setEnabled(true);
+ actionsGroup->setEnabled(true);
+ running = false;
+}
+
+void Netsync::startStopClicked()
+{
+ if (running)
+ {
+ stop();
+ return;
+ }
+
+ Action act;
+ QStringList cmd;
+ if (actionPull->isChecked())
+ act = Pull;
+ else if (actionPush->isChecked())
+ act = Push;
+ else if (actionSync->isChecked())
+ act = Sync;
+ else
+ I(false);
+
+ QString include("*");
+ if (!includePattern->text().isEmpty())
+ {
+ include = includePattern->text();
+ }
+
+ QString exclude;
+ if (!excludePattern->text().isEmpty())
+ {
+ exclude = excludePattern->text();
+ }
+
+ QString key = keys->itemData(keys->currentIndex()).toString();
+
+ start(act, host->currentText(), key, include, exclude);
+}
+
+void Netsync::processTaskResult(const MonotoneTask & task)
+{
+ running = false;
+ startStopButton->setText(tr("Start"));
+ settingsGroup->setEnabled(true);
+ actionsGroup->setEnabled(true);
+
+ overallProgress->setMaximum(1);
+ overallProgress->setValue(1);
+
+ if (task.getReturnCode() != 0)
+ {
+ progressText->setText(tr("Connection failed: %1")
+ .arg(task.getDecodedOutput()));
+ return;
+ }
+
+ progressText->setText(tr("Successful exchange with %1")
+ .arg(QString(task.getArguments().at(1))));
+}
+
+void Netsync::tickerUpdate(const TickerMap & tickers)
+{
+ // we "compress" the values of all found tickers into one progress bar
+ // this also means that we cannot display an actual progress unless
+ // we know the total values of all tickers
+ bool knowTotalValue = true;
+ int progress = 0, total = 0;
+ QStringList progressTexts;
+ foreach (char ident, tickers.keys())
+ {
+ if (tickers[ident].complete)
+ continue;
+
+ // we never get total values for the transferred bytes, so ignore
+ // these completly for the progress bar calculation
+ if (ident == '<' || ident == '>')
+ {
+ progressTexts.push_back(tickers[ident].toString(true));
+ }
+ else
+ {
+ if (tickers[ident].total == 0)
+ knowTotalValue = false;
+
+ progress += tickers[ident].progress;
+ total += tickers[ident].total;
+ progressTexts.push_back(tickers[ident].toString(false));
+ }
+ }
+
+ if (knowTotalValue)
+ overallProgress->setMaximum(total);
+ else
+ overallProgress->setMaximum(0);
+
+ overallProgress->setValue(progress);
+ progressText->setText(progressTexts.join(", "));
+
+ progressWidget->show();
+}
+
+void Netsync::accept()
+{
+ if (running)
+ stop();
+
+ progressWidget->hide();
+ done(QDialog::Accepted);
+}
+
============================================================
--- src/view/dialogs/Netsync.h 33cb539497a787d27d32cb594a901ffd8584f4f7
+++ src/view/dialogs/Netsync.h 33cb539497a787d27d32cb594a901ffd8584f4f7
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2008 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 3 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, see . *
+ ***************************************************************************/
+
+#ifndef NETSYNC_H
+#define NETSYNC_H
+
+#include "vocab.h"
+#include "Dialog.h"
+#include "AutomateCommand.h"
+#include "ui_netsync.h"
+
+class Netsync : public Dialog, public AutomateCommand, private Ui::NetsyncDialog
+{
+ Q_OBJECT
+public:
+ enum Action { Push, Pull, Sync };
+
+ Netsync(QWidget *, const DatabaseFile &);
+ ~Netsync();
+ void init();
+
+public slots:
+ void start(Action,
+ const QString &,
+ const QString &,
+ const QString &,
+ const QString &);
+ void stop();
+
+protected:
+ void accept();
+ void processTaskResult(const MonotoneTask &);
+ virtual void tickerUpdate(const TickerMap &);
+
+protected slots:
+ void startStopClicked();
+
+private:
+ DatabaseFile db;
+ bool running;
+};
+
+#endif
============================================================
--- NEWS ea03d1c9b0c26b701b56a1e217213eaadaa7106c
+++ NEWS 1c169dfc4599d4ea266a86ffffcec3bb77db7ecd
@@ -1,6 +1,10 @@
????-??-?? (0.10)
- new: create / initialize new monotone databases
+ - new: synchronize with other monotone databases via netsync
- new: directly select the key to sign a revision with in the commit dialog
+ - bugfix: no longer load the user's default hooks under ~/.monotone/monotonerc
+ or _MTN/monotonerc whose out-of-band output would interfer with our stdio
+ interface.
- bugfix: no longer crash the changeset browser when a database contains no
revisions and the user clicks on "more/all changes"
============================================================
--- src/model/AutomateCommand.cpp 1c819d32c321a539d0d59e100a632d17fdba16ca
+++ src/model/AutomateCommand.cpp 80b69f1ceaee3c47a08a18914f5cda659bed27d0
@@ -36,7 +36,10 @@ AutomateCommand::~AutomateCommand()
AutomateCommand::~AutomateCommand()
{
- if (cmdHelperCreated) delete cmdHelper;
+ if (cmdHelperCreated)
+ {
+ delete cmdHelper;
+ }
}
void AutomateCommand::enqueueTask(MonotoneThread * thread, const MonotoneTask & task)
@@ -57,6 +60,11 @@ void AutomateCommand::enqueueTask(Monoto
cmdHelper, SLOT(taskFinished(const MonotoneTask &))
);
+ QObject::connect(
+ thread, SIGNAL(tickersChanged(const TickerMap &)),
+ cmdHelper, SLOT(tickersChanged(const TickerMap &))
+ );
+
connectedThreads.append(threadNumber);
}
@@ -97,6 +105,11 @@ void AutomateCommand::stopAllTasks()
}
}
+void AutomateCommand::tickerUpdate(const TickerMap & tickers)
+{
+ Q_UNUSED(tickers);
+}
+
AutomateCommandHelper::AutomateCommandHelper(AutomateCommand * cmd)
: command(cmd)
{}
@@ -132,3 +145,8 @@ void AutomateCommandHelper::taskFinished
command->processTaskResult(task);
}
+void AutomateCommandHelper::tickersChanged(const TickerMap & tickers)
+{
+ command->tickerUpdate(tickers);
+}
+
============================================================
--- src/model/AutomateCommand.h 93a7d2bbd7d51d8b0f75ff9d63092ffc69aaa247
+++ src/model/AutomateCommand.h b2e0fd928d2e273b314398bc250066de03ea5348
@@ -36,6 +36,7 @@ protected:
protected:
virtual void processTaskResult(const MonotoneTask &) = 0;
+ virtual void tickerUpdate(const TickerMap &);
void enqueueWorkspaceTask(const WorkspacePath &, const MonotoneTask &);
void enqueueDatabaseTask(const DatabaseFile &, const MonotoneTask &);
void stopAllTasks();
@@ -60,8 +61,8 @@ protected slots:
protected slots:
virtual void taskAborted(const MonotoneTask &);
-
void taskFinished(const MonotoneTask &);
+ void tickersChanged(const TickerMap &);
private:
AutomateCommand * command;
============================================================
--- src/monotone/MonotoneThread.cpp c15b3807460064117d7d5904624decb5f0f52759
+++ src/monotone/MonotoneThread.cpp 56a8906a9d0f808ea3a08d88920bfffd1afecf69
@@ -70,13 +70,6 @@ void MonotoneTask::init(const ByteArrayL
finished = false;
abortTask = false;
outputEncoding = "UTF-8";
-
- static bool initialized = false;
- if (!initialized)
- {
- qRegisterMetaType("MonotoneTask");
- initialized = true;
- }
}
ByteArrayList MonotoneTask::stringToByteArrayList(const QStringList & list)
@@ -148,12 +141,7 @@ MonotoneThread::MonotoneThread(
int thread, const QString & m, const QString & d, const QString & w
) : QThread(), doAbort(false), commandNumber(0), threadNumber(thread),
mtnBinary(m), databasePath(d), workspacePath(w)
-{
- connect(
- this, SIGNAL(aborted(int, QProcess::ProcessError, const QString &)),
- this, SLOT(cleanup())
- );
-}
+{}
MonotoneThread::~MonotoneThread() {}
@@ -199,6 +187,7 @@ void MonotoneThread::run()
args << "stdio";
args << QString("--automate-stdio-size=%1").arg(StdioBufferSize);
args << "--db" << databasePath;
+ args << "--norc";
// check whether we need to work on a specific workspace directory or not
if (!workspacePath.isEmpty())
@@ -218,6 +207,7 @@ void MonotoneThread::run()
"workspace, which may lead to serious path resolution "
"errors on execution. Its recommended you remove "
"this workspace before you retry this again!").arg(tmpPath));
+ cleanup(process);
return;
}
process->setWorkingDirectory(tmpPath);
@@ -239,6 +229,7 @@ void MonotoneThread::run()
emit aborted(threadNumber, process->error(),
QString::fromUtf8(process->readAllStandardError())
);
+ cleanup(process);
return;
}
@@ -255,6 +246,7 @@ void MonotoneThread::run()
QString err = QString::fromUtf8(process->readAllStandardError());
emit aborted(threadNumber, process->error(), err);
+ cleanup(process);
return;
}
process->setReadChannel(QProcess::StandardOutput);
@@ -285,6 +277,7 @@ void MonotoneThread::run()
emit aborted(threadNumber, process->error(),
QString::fromUtf8(process->readAllStandardError())
);
+ cleanup(process);
return;
}
@@ -323,6 +316,7 @@ void MonotoneThread::run()
buffer.clear();
output.clear();
+ tickers.clear();
processingTask = true;
D(QString("thread %1: task %2 (%3) started").arg(threadNumber)
@@ -335,55 +329,74 @@ void MonotoneThread::run()
emit aborted(threadNumber, process->error(),
QString::fromUtf8(process->readAllStandardError())
);
+ cleanup(process);
return;
}
- // we can't assume that all stderr output from stdio is evil
- // just because there are some automate commands which are
- // programmed badly (f.e. genkey, which outputs status messages
- // on stderr)
QByteArray err = process->readAllStandardError();
if (err.size() != 0)
{
- // FIXME: expand this list further or wait for nvm.automate_out_of_band to land
- QStringList cmdsWithSpuriousOutput =
- QStringList() << "genkey" << "select" << "inventory";
- QString cmd = task.getArguments().at(0);
+ task.setOutput(err);
+ task.setReturnCode(-1);
- if (!cmdsWithSpuriousOutput.contains(cmd))
+ processingTask = false;
+ buffer.clear();
+ output.clear();
+ queue.dequeue();
+
+ emit taskAborted(task);
+ continue;
+ }
+
+ buffer.append(process->readAllStandardOutput());
+
+ int returnCode = -1;
+ while (!buffer.isEmpty())
+ {
+ StdioParser parser(buffer);
+
+ // if the chunk is not yet complete, try again later
+ if (!parser.parse())
{
- task.setOutput(err);
- task.setReturnCode(-1);
+ D("cannot parse - continueing");
+ break;
+ }
- processingTask = false;
- buffer.clear();
- output.clear();
- queue.dequeue();
+ TickerMap tickerUpdates = parser.getTickers();
+ if (tickerUpdates.size() > 0)
+ {
+ if (tickers.size() == 0)
+ {
+ tickers = tickerUpdates;
+ }
+ else
+ {
+ // update previous ticker values
+ foreach (char ident, tickerUpdates.keys())
+ {
+ if (tickers.contains(ident))
+ tickers[ident].update(tickerUpdates[ident]);
+ else
+ tickers[ident] = tickerUpdates[ident];
+ }
+ }
- emit taskAborted(task);
- continue;
+ emit tickersChanged(tickers);
}
- }
- buffer.append(process->readAllStandardOutput());
- StdioParser parser(buffer);
+ buffer = parser.getLeftBytes();
+ output.append(parser.getPayload());
- // if the chunk is not yet complete, try again later
- if (!parser.parse())
- {
- D("cannot parse - continueing");
- continue;
+ if (parser.getChunkType() == 'l')
+ {
+ returnCode = parser.getErrorCode();
+ I(buffer.isEmpty());
+ break;
+ }
}
- buffer = parser.getLeftBytes();
- output.append(parser.getPayload());
- int returnCode = parser.getErrorCode();
-
- // TODO: support for other chunk types here?
- if (parser.getChunkType() == 'm')
- {
+ if (returnCode < 0)
continue;
- }
task.setOutput(output);
task.setReturnCode(returnCode);
============================================================
--- src/monotone/MonotoneThread.h 80bb125d5e5b9d5b51d3bc2eb9701f1080689c7d
+++ src/monotone/MonotoneThread.h 8a6365f540ed8706b8eae206865dfac75fa452a3
@@ -157,6 +157,9 @@ signals:
//! signaled if the interal mtn process was aborted (i.e. crashed)
void aborted(int, QProcess::ProcessError, const QString &);
+ //! signals newly setup / changed tickers
+ void tickersChanged(const TickerMap &);
+
private slots:
void cleanup(QProcess *);
@@ -172,6 +175,7 @@ private:
QQueue queue;
QMutex lock;
QWaitCondition waitForTasks;
+ TickerMap tickers;
};
#endif
============================================================
--- src/util/StdioParser.cpp 48c78328277cff98a5ba59e95e32c3440637c964
+++ src/util/StdioParser.cpp d4cba87dc4415fc989015ccadcc95ba28b3e50ae
@@ -31,7 +31,6 @@ bool StdioParser::parse()
errorCode = getNumber();
I(getNext() == ':');
chunkType = getNext();
- I(chunkType == 'm' || chunkType == 'l');
I(getNext() == ':');
chunkSize = getNumber();
I(getNext() == ':');
@@ -42,7 +41,20 @@ bool StdioParser::parse()
return false;
}
- payload = getNext(chunkSize);
+ if (chunkType == 'm' || chunkType == 'l')
+ {
+ payload = getNext(chunkSize);
+ }
+ else
+ if (chunkType == 't')
+ {
+ parseTicks(getNext(chunkSize));
+ }
+ else
+ {
+ oobMessages.push_back(qMakePair(chunkType, getNext(chunkSize)));
+ }
+
return true;
}
@@ -69,3 +81,56 @@ int StdioParser::getNumber()
return number;
}
+void StdioParser::parseTicks(const QByteArray & ticks)
+{
+ I(ticks.endsWith(';'));
+
+ QList tickerList = ticks.left(ticks.size() - 1).split(';');
+ I(tickerList.size() > 0);
+
+ foreach (QByteArray tick, tickerList)
+ {
+ I(tick.size() > 0);
+ char ident = tick.at(0);
+ tick.remove(0, 1);
+
+ if (!tickers.contains(ident))
+ {
+ tickers[ident] = Ticker();
+ }
+
+ if (tick.size() == 0)
+ {
+ tickers[ident].complete = true;
+ continue;
+ }
+
+ if (tick.at(0) == ':')
+ {
+ tick.remove(0, 1);
+ tickers[ident] = Ticker(tick);
+ continue;
+ }
+
+ if (tick.at(0) == '=')
+ {
+ tick.remove(0, 1);
+ bool ok;
+ tickers[ident].total = tick.toUInt(&ok);
+ I(ok);
+ continue;
+ }
+
+ if (tick.at(0) == '#')
+ {
+ tick.remove(0, 1);
+ bool ok;
+ tickers[ident].progress = tick.toUInt(&ok);
+ I(ok);
+ continue;
+ }
+
+ I(false);
+ }
+}
+
============================================================
--- src/util/StdioParser.h 5f6b6793087a0d3d884c32f1cfa786632c67c647
+++ src/util/StdioParser.h 280e28221050eecf94aac14355dc0f80c09f7dd3
@@ -19,6 +19,7 @@
#ifndef STDIO_PARSER_H
#define STDIO_PARSER_H
+#include "vocab.h"
#include "AbstractParser.h"
class StdioParser : public AbstractParser
@@ -32,15 +33,19 @@ public:
inline char getChunkType() const { return chunkType; }
inline int getChunkSize() const { return chunkSize; }
inline QByteArray getPayload() const { return payload; }
+ inline TickerMap getTickers() const { return tickers; }
private:
int getNumber();
+ void parseTicks(const QByteArray &);
int commandNumber;
int errorCode;
char chunkType;
int chunkSize;
QByteArray payload;
+ TickerMap tickers;
+ QList > oobMessages;
};
#endif
============================================================
--- src/view/dialogs/DatabaseDialogManager.cpp 903fe5513823171829c2d7feaefc5996bcd05a7d
+++ src/view/dialogs/DatabaseDialogManager.cpp bf76575815a0ab6bf17bb5c75fe52a1f4c5db4a5
@@ -22,7 +22,8 @@ DatabaseDialogManager::DatabaseDialogMan
DatabaseDialogManager::DatabaseDialogManager(QWidget * parent)
: DialogManager(parent), changesetBrowser(0),
checkoutRevision(0), fileDiff(0), fileHistory(0), generateKeypair(0),
- keyManagement(0), revisionDiff(0), revisionManifest(0), selectRevision(0)
+ netsync(0), keyManagement(0), revisionDiff(0),
+ revisionManifest(0), selectRevision(0)
{}
DatabaseDialogManager::~DatabaseDialogManager()
@@ -37,6 +38,7 @@ void DatabaseDialogManager::cleanup()
if (fileDiff) { delete fileDiff; fileDiff = 0; }
if (fileHistory) { delete fileHistory; fileHistory = 0; }
if (generateKeypair) { delete generateKeypair; generateKeypair = 0; }
+ if (netsync) { delete netsync; netsync = 0; }
if (keyManagement) { delete keyManagement; keyManagement = 0; }
if (revisionDiff) { delete revisionDiff; revisionDiff = 0; }
if (revisionManifest) { delete revisionManifest; revisionManifest = 0; }
@@ -50,6 +52,7 @@ void DatabaseDialogManager::closeAllDial
if (fileDiff) fileDiff->close();
if (fileHistory) fileHistory->close();
if (generateKeypair) generateKeypair->close();
+ if (netsync) netsync->close();
if (keyManagement) keyManagement->close();
if (revisionDiff) revisionDiff->close();
if (revisionManifest) revisionManifest->close();
@@ -150,6 +153,17 @@ void DatabaseDialogManager::showGenerate
showDialog(generateKeypair);
}
+void DatabaseDialogManager::showNetsync()
+{
+ if (!netsync)
+ {
+ netsync = new Netsync(parentWidget(), databaseFile);
+ }
+
+ netsync->init();
+ showDialog(netsync);
+}
+
void DatabaseDialogManager::showKeyManagement()
{
if (!keyManagement)
============================================================
--- src/view/dialogs/DatabaseDialogManager.h 532a5c5e04720356b89b3584d40833c422ed2a26
+++ src/view/dialogs/DatabaseDialogManager.h 1a090d7cc52c821066410946fbcdd592158eddda
@@ -25,6 +25,7 @@
#include "FileDiff.h"
#include "FileHistory.h"
#include "GenerateKeypair.h"
+#include "Netsync.h"
#include "KeyManagement.h"
#include "RevisionDiff.h"
#include "RevisionManifest.h"
@@ -50,6 +51,7 @@ public slots:
virtual void showFileDiff(const QString & file, const QString & base, const QString & target);
void showFileHistory(const QString & file, const QString & startRevision);
void showGenerateKeypair();
+ void showNetsync();
void showKeyManagement();
virtual void showRevisionDiff(const QString & path, const QString & base, const QString & target);
void showRevisionManifest(const QString & revision);
@@ -61,6 +63,7 @@ protected:
FileDiff * fileDiff;
FileHistory * fileHistory;
GenerateKeypair * generateKeypair;
+ Netsync * netsync;
KeyManagement * keyManagement;
RevisionDiff * revisionDiff;
RevisionManifest * revisionManifest;
============================================================
--- src/view/mainwindows/DatabaseWindow.cpp 37323d919fecd0fda6c5266a8af16203b88edf04
+++ src/view/mainwindows/DatabaseWindow.cpp 32afece8ed33326fca00fe4180fcc440dcf07256
@@ -63,6 +63,11 @@ void DatabaseWindow::init()
);
connect(
+ menuBar, SIGNAL(showNetsync()),
+ dialogManager, SLOT(showNetsync())
+ );
+
+ connect(
menuBar, SIGNAL(showChangesetBrowser()),
dialogManager, SLOT(showChangesetBrowser())
);
@@ -148,7 +153,7 @@ void DatabaseWindow::load(const QString
Settings::addItemToList("RecentDatabaseList", path, 5);
- reinterpret_cast(dialogManager)->init(databaseFile);
- databaseVariables->setDatabaseFile(databaseFile);
+ reinterpret_cast(dialogManager)->init(databaseFile);
+ databaseVariables->setDatabaseFile(databaseFile);
}
============================================================
--- src/view/widgets/DatabaseMenuBar.cpp 24128d740e1d3b1b08839bf94d1f348b96bf1fd4
+++ src/view/widgets/DatabaseMenuBar.cpp ce3a7aa362d08e1f816cd9456b8d3fd555a4fadc
@@ -23,6 +23,8 @@ DatabaseMenuBar::DatabaseMenuBar(QWidget
//
// The Database menu
//
+ actionNetsync = new QAction(tr("Network synchronisation"), this);
+ actionNetsync->setShortcut(tr("F5"));
actionChangeset_browser = new QAction(tr("Changeset browser"), this);
actionChangeset_browser->setShortcut(tr("Ctrl+B"));
actionKey_management = new QAction(tr("Key management"), this);
@@ -32,6 +34,8 @@ DatabaseMenuBar::DatabaseMenuBar(QWidget
menuDatabase = new QMenu(tr("Database"), this);
+ menuDatabase->addAction(actionNetsync);
+ menuDatabase->addSeparator();
menuDatabase->addAction(actionChangeset_browser);
menuDatabase->addAction(actionKey_management);
menuDatabase->addSeparator();
@@ -41,6 +45,11 @@ DatabaseMenuBar::DatabaseMenuBar(QWidget
insertMenu(menuWindow->menuAction(), menuDatabase);
connect(
+ actionNetsync, SIGNAL(triggered()),
+ this, SIGNAL(showNetsync())
+ );
+
+ connect(
actionChangeset_browser, SIGNAL(triggered()),
this, SIGNAL(showChangesetBrowser())
);
============================================================
--- src/view/widgets/DatabaseMenuBar.h b100fad7678bb201825278f5d496dc29bd43fe26
+++ src/view/widgets/DatabaseMenuBar.h e891dcedbca13fdf865e320f4a6026e1c5eadbb3
@@ -31,11 +31,13 @@ signals:
void addDockWidgetAction(QAction * action);
signals:
+ void showNetsync();
void showCheckoutRevision();
void showChangesetBrowser();
void showKeyManagement();
protected:
+ QAction * actionNetsync;
QAction * actionKey_management;
QAction * actionChangeset_browser;
QAction * actionCheckout_revision;
============================================================
--- src/vocab.h 1b2725cb1d597d7dd4035b6763f47bf02eb062cb
+++ src/vocab.h 47f7cac5d9cfea1f8308980d3de9268b1e97a674
@@ -96,6 +96,61 @@ typedef QList StanzaList;
typedef QList Stanza;
typedef QList StanzaList;
+struct Ticker
+{
+ QByteArray name;
+ int total;
+ int progress;
+ bool complete;
+
+ Ticker(const QByteArray & n = QByteArray())
+ : name(n), total(0), progress(0), complete(false) {}
+
+ /**
+ * Updates this ticker's values with the values from another one
+ * (of the same type)
+ */
+ void update(const Ticker & other)
+ {
+ if (name.isEmpty()) name = other.name;
+ if (total < other.total) total = other.total;
+ if (progress < other.progress) progress = other.progress;
+ if (!complete && other.complete) complete = true;
+ }
+
+ QString toString(bool shortened = true) const
+ {
+ if (complete)
+ return QObject::tr("%1: completed")
+ .arg(QString(name));
+
+ QString prog;
+ if (shortened && progress > (1024 * 1024))
+ prog = QString("%1M").arg((double)progress / (1024 * 1024), 0, 'f', 1);
+ else if (shortened && progress > 1024)
+ prog = QString("%1K").arg((double)progress / 1024, 0, 'f', 1);
+ else
+ prog = QString::number(progress);
+
+ if (total == 0)
+ return QObject::tr("%1: %2")
+ .arg(QString(name)).arg(prog);
+
+ QString tot;
+ if (shortened && total > (1024 * 1024))
+ tot = QString("%1M").arg((double)total / (1024 * 1024), 0, 'f', 1);
+ else if (shortened && total > 1024)
+ tot = QString("%1K").arg((double)total / 1024, 0, 'f', 1);
+ else
+ tot = QString::number(total);
+
+ return QObject::tr("%1: %2 / %3")
+ .arg(QString(name)).arg(prog).arg(tot);
+ }
+};
+
+typedef QMap TickerMap;
+
// FIXME: just a few stupid typedefs which should be expanded later on
// to more "intelligent" objects
typedef QString GuitoneException;