# # # add_file "guitone/src/util/SignalWaiter.cpp" # content [be5421eb7c7ffb705b73ed2fbe4743e2faa41eca] # # add_file "guitone/src/util/SignalWaiter.h" # content [dddf95284e9e1e44a6f4b0732ecabfa49edb06ff] # # patch "guitone/guitone.pro" # from [5274e64c3710f6e145a7f2d6a474bc04ff2fd637] # to [cc1f5ee6f8271627eb8f0a81c1451a454dc71c2b] # # patch "guitone/src/monotone/Monotone.cpp" # from [1aae8564f8b72f74e8e1585ad7eb0769eb24bd4c] # to [65fe8b35f52f9f0bc163b1ee611f774d1f62c091] # # patch "guitone/src/view/InventoryView.cpp" # from [db0489f039bc8df019e4870e8832889806746773] # to [892a8828e88a65b49cb2c280abe87c28eed70531] # # patch "guitone/src/view/dialogs/FileDiff.cpp" # from [95ae7962a58d4777ca532b469600df7e20a2bb28] # to [8c2934c953f61f1fa958a9c83858a6bfed339651] # # patch "guitone/src/view/dialogs/FileDiff.h" # from [7852d0b3128d22c478938f84e419683b46801eee] # to [99ff9d52eae341041edad007cd2f529658d1a122] # ============================================================ --- guitone/src/util/SignalWaiter.cpp be5421eb7c7ffb705b73ed2fbe4743e2faa41eca +++ guitone/src/util/SignalWaiter.cpp be5421eb7c7ffb705b73ed2fbe4743e2faa41eca @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2006 by Adam Higerd * + * address@hidden * + * * + * taken from http://qtnode.net/wiki/SignalWaiter * + * * + * 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 "SignalWaiter.h" +#include +#include +#include + +SignalWaiter::SignalWaiter(const QObject* sender, const char* signal) : QObject(0) { + obj = sender; + sig = signal; +} + +// Returns true if the signal was caught, returns false if the wait timed out +bool SignalWaiter::wait(int msec, const QObject* sender, const char* signal) { + if(sender!=0 && signal!=0) connect(sender, signal, this, SLOT(signalCaught())); + else if(obj!=0 && sig!=0) connect(obj, sig, this, SLOT(signalCaught())); + else if(msec == -1) return false; + // There would be an else clause here, except you can use this to idle for a specified amount of time + + if(msec!=-1) QTimer::singleShot(msec, this, SLOT(timedOut())); + ready = timeout = false; + while(!ready && !timeout) QCoreApplication::processEvents(); + return ready || !timeout; +} + +void SignalWaiter::signalCaught() { + ready = true; +} + +void SignalWaiter::timedOut() { + timeout = true; +} + ============================================================ --- guitone/src/util/SignalWaiter.h dddf95284e9e1e44a6f4b0732ecabfa49edb06ff +++ guitone/src/util/SignalWaiter.h dddf95284e9e1e44a6f4b0732ecabfa49edb06ff @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2006 by Adam Higerd * + * address@hidden * + * * + * taken from http://qtnode.net/wiki/QSignalWaiter * + * * + * 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 QSIGNALWAITER_H +#define QSIGNALWAITER_H + +#include + +class SignalWaiter : public QObject { +Q_OBJECT +public: + SignalWaiter(const QObject* sender = 0, const char* signal = 0); + bool wait(int msec = -1, const QObject* sender = 0, const char* signal = 0); +private slots: + void signalCaught(); + void timedOut(); +private: + const QObject* obj; + const char* sig; + bool ready, timeout; +}; + +#endif ============================================================ --- guitone/guitone.pro 5274e64c3710f6e145a7f2d6a474bc04ff2fd637 +++ guitone/guitone.pro cc1f5ee6f8271627eb8f0a81c1451a454dc71c2b @@ -1,10 +1,10 @@ TARGET = guitone # # Common configuration # TEMPLATE = app TARGET = guitone -CONFIG += qt debug precompile_header +CONFIG += qt debug # precompile_header HEADERS += src/view/Guitone.h \ src/view/TreeView.h \ src/view/Splitter.h \ @@ -30,7 +30,8 @@ HEADERS += src/view/Guitone.h \ src/util/IconProvider.h \ src/util/StanzaParser.h \ src/util/Settings.h \ - src/util/DiffParser.h + src/util/DiffParser.h \ + src/util/SignalWaiter.h SOURCES += src/view/Guitone.cpp \ src/view/TreeView.cpp \ src/view/Splitter.cpp \ @@ -57,6 +58,7 @@ SOURCES += src/view/Guitone.cpp \ src/util/StanzaParser.cpp \ src/util/Settings.cpp \ src/util/DiffParser.cpp \ + src/util/SignalWaiter.cpp \ src/main.cpp FORMS += res/dialogs/switch_workspace.ui \ res/dialogs/preferences.ui \ ============================================================ --- guitone/src/monotone/Monotone.cpp 1aae8564f8b72f74e8e1585ad7eb0769eb24bd4c +++ guitone/src/monotone/Monotone.cpp 65fe8b35f52f9f0bc163b1ee611f774d1f62c091 @@ -21,8 +21,10 @@ #include "Monotone.h" #include "../model/AutomateCommand.h" #include "../util/Settings.h" +#include "../util/SignalWaiter.h" #include +#include Monotone* Monotone::instance = 0; @@ -36,6 +38,8 @@ Monotone::Monotone(QObject * parent) : Q isProcessingData = false; // true if the process is destroyed in the destructor isCleanExit = false; + // inialize the process var + process = 0; } void Monotone::setup(QDir *workingDirectory) @@ -55,12 +59,6 @@ void Monotone::setup(QDir *workingDirect process = new QProcess(this); - // read & parse mtn's output as soon as it gets available - connect( - process, SIGNAL(readyReadStandardOutput()), - this, SLOT(readStdout()) - ); - // monitor if the process is exited unexpectedly connect( process, SIGNAL(finished(int, QProcess::ExitStatus)), @@ -117,39 +115,40 @@ bool Monotone::executeCommand(const QStr bool Monotone::executeCommand(const QStringList & command) { - return executeCommand(command, QStringList()); + QStringList opts; + return executeCommand(command, opts); } bool Monotone::executeCommand(const QStringList & command, const QStringList & options) { + SignalWaiter waiter(process, SIGNAL(readyReadStandardOutput())); + if (!writeStdin(command, options)) { + qDebug("Monotone::executeCommand: could not write command to stdin"); return false; } - while (true) + while (waiter.wait(1000)) { - if (!process->waitForReadyRead(-1)) - { - qDebug("A error occured while waiting for incoming data."); - return false; - } + input.append(process->readAllStandardOutput()); - // read all data from stdout of the process and - // append it to previous output which couldn't be processed yet - input.append(process->readAllStandardOutput()); - int retCode = 0; // check if we already could parse the complete stdio output if (!parseStdio(retCode)) { - qWarning("Monotone::readStdout: Contents incomplete/invalid."); + qWarning("Monotone::executeCommand: Contents incomplete/invalid."); continue; } + // parsing successful + isProcessingData = false; return true; } + + qWarning("Monotone::executeCommand: Timed out waiting for output."); + return false; } bool Monotone::triggerCommand(AutomateCommand * caller, const QStringList & command) @@ -159,6 +158,12 @@ bool Monotone::triggerCommand(AutomateCo bool Monotone::triggerCommand(AutomateCommand * caller, const QStringList & command, const QStringList & options) { + // read & parse mtn's output as soon as it gets available + connect( + process, SIGNAL(readyReadStandardOutput()), + this, SLOT(readStdout()) + ); + // connect the caller with us so he knows when the command is finished connect( this, SIGNAL(commandFinished(AutomateCommand*)), @@ -180,17 +185,17 @@ bool Monotone::writeStdin(const QStringL // the error handler is called and the program is terminated! if (process->state() != QProcess::Running && !process->waitForStarted(15000)) { - qDebug("QProcess is not running."); - return false; + qDebug("Monotone::writeStdin: Process is not running"); + return false; } - + // check if we're already processing a command if (isProcessingData) { - qDebug("Process is already busy."); + qDebug("Monotone::writeStdin: Not finished processing data"); return false; } - + isProcessingData = true; input.clear(); output.clear(); @@ -223,7 +228,7 @@ bool Monotone::writeStdin(const QStringL } commandLine += "e\n"; - qDebug("Final command: %s", qPrintable(commandLine)); + qDebug("Writing command %s", qPrintable(commandLine)); // QProcess in QT4 doesn't have a writeToStdin(). // So we need the following QTextStream @@ -264,9 +269,16 @@ void Monotone::readStdout() isCleanExit = true; process->close(); - // disconnect the event sink from any further signals - disconnect(lastCaller); + disconnect( + process, SIGNAL(readyReadStandardOutput()), + this, SLOT(readStdout()) + ); + disconnect( + this, SIGNAL(commandFinished(AutomateCommand*)), + lastCaller, SLOT(parseOutput(AutomateCommand*)) + ); + // emit a critical error which closes the app later emit criticalError( tr("Unable to process command '%1': %2") @@ -278,8 +290,15 @@ void Monotone::readStdout() emit commandFinished(lastCaller); - // disconnect the event sink from any further signals - disconnect(lastCaller); + disconnect( + process, SIGNAL(readyReadStandardOutput()), + this, SLOT(readStdout()) + ); + + disconnect( + this, SIGNAL(commandFinished(AutomateCommand*)), + lastCaller, SLOT(parseOutput(AutomateCommand*)) + ); } bool Monotone::parseStdio(int & retCode) ============================================================ --- guitone/src/view/InventoryView.cpp db0489f039bc8df019e4870e8832889806746773 +++ guitone/src/view/InventoryView.cpp 892a8828e88a65b49cb2c280abe87c28eed70531 @@ -21,7 +21,7 @@ #include "InventoryView.h" #include "../util/Settings.h" #include "../model/InventoryItem.h" -// #include "dialogs/FileDiff.h" +#include "dialogs/FileDiff.h" #include #include @@ -274,10 +274,10 @@ void InventoryView::slotDiff(void) QModelIndex sourceIndex = static_cast(indexList[0].model())->mapToSource(indexList[0]); InventoryItem * item = static_cast(sourceIndex.internalPointer()); - + FileDiff dlg(this, item->getPath()); dlg.exec(); - + clearSelection(); } ============================================================ --- guitone/src/view/dialogs/FileDiff.cpp 95ae7962a58d4777ca532b469600df7e20a2bb28 +++ guitone/src/view/dialogs/FileDiff.cpp 8c2934c953f61f1fa958a9c83858a6bfed339651 @@ -20,6 +20,7 @@ #include "FileDiff.h" #include "../../monotone/Monotone.h" +#include "../../util/SignalWaiter.h" FileDiff::FileDiff(QWidget* parent) : QDialog(parent) @@ -36,43 +37,34 @@ void FileDiff::init(QString fileName) void FileDiff::init(QString fileName) { - file = fileName; - fileModel = new GetFile(this); fileModel->readFileByName(fileName); diffView->setModel(fileModel); - connect( - fileModel, SIGNAL(fileRead()), - this, SLOT(dataRead()) - ); + SignalWaiter fileWaiter(fileModel, SIGNAL(fileRead())); - diffModel = new ContentDiff(this); - diffModel->readDiff(fileName); - - connect( - diffModel, SIGNAL(diffRead()), - this, SLOT(dataRead()) - ); -} - -FileDiff::~FileDiff() {} - -void FileDiff::dataRead() -{ - // we don't care about the actual order in which the data - // are signaled to be read, we just assume that we're notified two - // times and in the second round we have all data available we need - static bool dataRead = false; - - if (!dataRead) + if (fileWaiter.wait()) { - dataRead = true; - return; + diffModel = new ContentDiff(this); + diffModel->readDiff(fileName); + + SignalWaiter diffWaiter(diffModel, SIGNAL(diffRead())); + + if (diffWaiter.wait()) + { + fileModel->applyDiff(diffModel->getDiff(fileName), GetFile::Both); + } + else + { + qDebug("diffWaiter timed out"); + } } - - // file seems to be read, now apply the diff - fileModel->applyDiff(diffModel->getDiff(file), GetFile::Both); + else + { + qDebug("fileWaiter timed out"); + } } +FileDiff::~FileDiff() {} + ============================================================ --- guitone/src/view/dialogs/FileDiff.h 7852d0b3128d22c478938f84e419683b46801eee +++ guitone/src/view/dialogs/FileDiff.h 99ff9d52eae341041edad007cd2f529658d1a122 @@ -35,14 +35,10 @@ public: void init(QString); ~FileDiff(); - -private slots: - void dataRead(); - + private: ContentDiff * diffModel; GetFile * fileModel; - QString file; }; #endif