# # # add_file "src/Tools.h" # content [64b35558c8b25748b9ddead9cee3aa44bff168a4] # # patch "guitone.pro" # from [ecc11c01d4ab8740e2abb65aff67e3a53a85e499] # to [e837191122075b7f915e6a1553480449110b81b1] # # patch "i18n/guitone_de.ts" # from [4272a84f0f1b90fc20472744289cf675471f427c] # to [314d8e73eb4391e445bdfec5a0c301557a7b8c1a] # # patch "src/model/Monotone.cpp" # from [dac206dbc0aded24a1a04fedb5ab6dc9e9cd79a7] # to [f772e5831bb50cb359e81e963351044477dbcb32] # # patch "src/model/Monotone.h" # from [484f8250c03ae129dea32955b892ced42a0e25ce] # to [7afc04bc452e6c37fbb8588ce5f9f3ee9a8e11ba] # # patch "src/model/Workspace.cpp" # from [ab2c1a2fa0e7dfc65a310c8379100b5a18326554] # to [c4614529bfd35c10621950a90016393d867353b6] # ============================================================ --- src/Tools.h 64b35558c8b25748b9ddead9cee3aa44bff168a4 +++ src/Tools.h 64b35558c8b25748b9ddead9cee3aa44bff168a4 @@ -0,0 +1,22 @@ +#ifndef TOOLS_H_ +#define TOOLS_H_ + +#include + +class Tools +{ + public: + // TODO: haven't tested this on windows... only guessed... + inline static void sleep(int millisecs) + { +#ifdef Q_WS_WIN + sleep(millisecs); +#else + // unix usleep(1) interpretes the argument as microseconds + // sleep() is useless since it only takes full seconds as argument + usleep(millisecs * 1000); +#endif + } +}; + +#endif /*TOOLS_H_*/ ============================================================ --- guitone.pro ecc11c01d4ab8740e2abb65aff67e3a53a85e499 +++ guitone.pro e837191122075b7f915e6a1553480449110b81b1 @@ -1,5 +1,6 @@ CONFIG += qt debug -HEADERS += src/view/XPM.h \ +HEADERS += src/Tools.h \ + src/view/XPM.h \ src/view/Guitone.h \ src/view/WorkspaceView.h \ src/model/Monotone.h \ ============================================================ --- i18n/guitone_de.ts 4272a84f0f1b90fc20472744289cf675471f427c +++ i18n/guitone_de.ts 314d8e73eb4391e445bdfec5a0c301557a7b8c1a @@ -68,11 +68,11 @@ Monotone Monotone not found - Monotone nicht gefunden + Monotone nicht gefunden Couldn't connect to monotone. Have you installed it properly? - Konnte Verbindung zu Monotone-Prozess nicht herstellen. Ist das Programm korrekt installiert? + Konnte Verbindung zu Monotone-Prozess nicht herstellen. Ist das Programm korrekt installiert? Process exited @@ -82,6 +82,14 @@ The internal connection to the monotone process was terminated (code %1, status %2) Die interne Verbindung zum Monotone-Prozess wurde beendet (Code %1, Status %2) + + Monotone startup error + Fehler beim Starten von Monotone + + + Couldn't startup the monotone process (ProcessError %1). Have you installed it properly? + Konnte den monotone-Prozess nicht starten (ProcessError %1). Ist das Programm korrekt installiert? + SandboxItem ============================================================ --- src/model/Monotone.cpp dac206dbc0aded24a1a04fedb5ab6dc9e9cd79a7 +++ src/model/Monotone.cpp f772e5831bb50cb359e81e963351044477dbcb32 @@ -5,75 +5,80 @@ #include #include #include +#include "../Tools.h" Monotone* Monotone::instance = 0; -Monotone::Monotone() : QProcess() +Monotone::Monotone(QDir *workingDirectory) : QProcess() { - isRunning = false; + isProcessingData = false; output = new QStringList(); + + // read & parse mtn's output as soon as it gets available + connect( + this, SIGNAL(readyReadStandardOutput()), + this, SLOT(parseLineFromStdout()) + ); + + // monitor if the process is exited unexpectedly + connect( + this, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(processTerminated(int, QProcess::ExitStatus)) + ); + + // check if there occurs an startup error + connect( + this, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(startupError(QProcess::ProcessError)) + ); + + setWorkingDirectory(workingDirectory->absolutePath()); + + QStringList args; + args << "automate"; + args << "stdio"; + + // Start up monotone's executable 'mtn' + start("mtn", args); } Monotone::~Monotone() { - // kill the running process - kill(); + // terminate any running process + terminate(); } -Monotone* Monotone::singleton(QDir *workingDirectory = 0) +Monotone* Monotone::singleton(QDir *workingDirectory = NULL) { - if (instance == 0) + // if we have no instance created yet we need a workspace directory + Q_ASSERT( !(workingDirectory == NULL && instance == 0) ); + + // create a new instance if there is either no instance + // or a new working directory has been explicitely given + if (instance == 0 || workingDirectory != NULL) { - instance = new Monotone(); - if (!instance->openConnection(workingDirectory)) - { - QMessageBox::critical( - NULL, - tr("Monotone not found"), - tr("Couldn't connect to monotone. Have you installed it properly?"), - QMessageBox::Ok, 0, 0 - ); - qApp->exit(1); - } + instance = new Monotone(workingDirectory); } return instance; } -bool Monotone::openConnection(QDir *workingDirectory) +void Monotone::startupError(QProcess::ProcessError error) { - // versions before 0.26pre3 are not supported. - // In that version monotone changed its binary and - // workspace folder names to mtn and _MTN - - setWorkingDirectory(workingDirectory->absolutePath()); - - connect( - this, SIGNAL(readyReadStandardOutput()), - this, SLOT(parseLineFromStdout()) + QMessageBox::critical( + NULL, + tr("Monotone startup error"), + tr("Couldn't startup the monotone process (ProcessError %1). Have you installed it properly?") + .arg(error), + QMessageBox::Ok, 0, 0 ); - - connect( - this, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(processTerminated(int, QProcess::ExitStatus)) - ); - - QStringList args; - args << "automate"; - args << "stdio"; - - // Start up monotone's executable 'mtn' - start("mtn", args); - - // Is montone started up inside 15 seconds? - if (!waitForStarted(15000)) - { - return false; - } - return true; + qApp->exit(1); } void Monotone::processTerminated(int code, QProcess::ExitStatus status) { + // this was a normal exit + if (code == 0) return; + // TODO: log the error output somewhere or at least output it on guitone's STDERR // QProcess' buffers are still intact at this point QMessageBox::critical( @@ -89,12 +94,21 @@ bool Monotone::triggerCommand(QString cmd) { - if (isRunning) + // wait until the process has been started up if it is not already + // running. Notice that if waitForStartup times out after 15 seconds + // the error handler is called and the program is terminated! + if (state() != QProcess::Running && !waitForStarted(15000)) + { + return false; + } + + // check if we're already processing a command + if (isProcessingData) { return false; } - isRunning = true; + isProcessingData = true; output->clear(); QString finalCmd; @@ -156,7 +170,7 @@ // and no additional information if (list[3].compare("l") == 0) { - isRunning = false; + isProcessingData = false; emit commandFinished(list[2].toInt()); break; } ============================================================ --- src/model/Monotone.h 484f8250c03ae129dea32955b892ced42a0e25ce +++ src/model/Monotone.h 7afc04bc452e6c37fbb8588ce5f9f3ee9a8e11ba @@ -20,23 +20,24 @@ Q_OBJECT public: - static Monotone* singleton(QDir*); + static Monotone* singleton(QDir*); + void init(QDir*); ~Monotone(); bool triggerCommand(QString cmd); QStringList* getOutput(); protected: - Monotone(); + Monotone(QDir*); private: - bool openConnection(QDir*); QStringList *output; - bool isRunning; + bool isProcessingData; static Monotone* instance; private slots: void parseLineFromStdout(); void processTerminated(int, QProcess::ExitStatus); + void startupError(QProcess::ProcessError); signals: void commandFinished(int returnCode); ============================================================ --- src/model/Workspace.cpp ab2c1a2fa0e7dfc65a310c8379100b5a18326554 +++ src/model/Workspace.cpp c4614529bfd35c10621950a90016393d867353b6 @@ -21,6 +21,7 @@ #include "Workspace.h" #include +#include #include Workspace::Workspace() @@ -61,8 +62,11 @@ bool Workspace::readInventory() { + // enable the wait cursor + qApp->setOverrideCursor(Qt::WaitCursor); + monotone = Monotone::singleton(workspaceDir); - + connect( monotone, SIGNAL(commandFinished(int)), this, SLOT(parseInventory(int)) @@ -199,6 +203,9 @@ // reset the model to repaint the view completly // (all QModelIndexes are discarded through that, e.g. selections!) this->reset(); + + // restore the normal cursor + qApp->restoreOverrideCursor(); } QList Workspace::buildTreeRecursive(QList items, WorkspaceItem* parentItem)