]> git.lyx.org Git - features.git/commitdiff
Move some code from the process branch into trunk.
authorPeter Kümmel <syntheticpp@gmx.net>
Fri, 4 Dec 2009 09:51:13 +0000 (09:51 +0000)
committerPeter Kümmel <syntheticpp@gmx.net>
Fri, 4 Dec 2009 09:51:13 +0000 (09:51 +0000)
Don't incorporated any progess stuff.
Behavior when starting a process is UNTOUCHED, but could simply changed by setting progessEvents to true.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@32323 a592a061-630c-0410-9148-cb99ea01b6c8

src/support/Systemcall.cpp
src/support/SystemcallPrivate.h

index e51fc169ca16350259b06a9070ec973b94492788..499994b34c57ef4f11c023b9c511b24699f1087e 100644 (file)
@@ -4,9 +4,9 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Asger Alstrup
- *
- * Interface cleaned up by
  * \author Angus Leeming
+ * \author Enrico Forestieri
+ * \author Peter Kuemmel
  *
  * Full author contact details are available in file CREDITS.
  */
 #include "support/SystemcallPrivate.h"
 #include "support/os.h"
 
+
 #include <cstdlib>
 #include <iostream>
 
 #include <QProcess>
+#include <QTime>
+#include <QThread>
+#include <QCoreApplication>
+
 
 #define USE_QPROCESS
 
+
+struct Sleep : QThread
+{
+       static void millisec(unsigned long ms) 
+       {
+               QThread::usleep(ms * 1000);
+       }
+};
+
+
+
 using namespace std;
 
 namespace lyx {
@@ -42,6 +58,9 @@ static void killProcess(QProcess * p)
 }
 
 
+
+
+
 // Reuse of instance
 #ifndef USE_QPROCESS
 int Systemcall::startscript(Starttype how, string const & what)
@@ -90,48 +109,47 @@ string const parsecmd(string const & cmd, string & outfile)
 } // namespace anon
 
 
+
 int Systemcall::startscript(Starttype how, string const & what)
 {
        string outfile;
        QString cmd = toqstr(parsecmd(what, outfile));
        QProcess * process = new QProcess;
-       ConOut console(process);
+       SystemcallPrivate d(process);
        if (!outfile.empty()) {
                // Check whether we have to simply throw away the output.
                if (outfile != os::nulldev())
                        process->setStandardOutputFile(toqstr(outfile));
        } else if (os::is_terminal(os::STDOUT))
-               console.showout();
+               d.showout();
        if (os::is_terminal(os::STDERR))
-               console.showerr();
-
-       process->start(cmd);
-       if (!process->waitForStarted(3000)) {
-               LYXERR0("Qprocess " << cmd << " did not start!");
-               LYXERR0("error " << process->error());
-               LYXERR0("state " << process->state());
-               LYXERR0("status " << process->exitStatus());
+               d.showerr();
+       
+
+       bool processEvents = false;
+       d.startProcess(cmd);
+       if (!d.waitWhile(SystemcallPrivate::Starting, processEvents, 3000)) {
+               LYXERR0("QProcess " << cmd << " did not start!");
+               LYXERR0("error " << d.errorMessage());
                return 10;
        }
+
        if (how == DontWait) {
                // TODO delete process later
                return 0;
        }
 
-       if (!process->waitForFinished(180000)) {
-               LYXERR0("Qprocess " << cmd << " did not finished!");
-               LYXERR0("error " << process->error());
-               LYXERR0("state " << process->state());
-               LYXERR0("status " << process->exitStatus());
+       if (!d.waitWhile(SystemcallPrivate::Running, processEvents, 180000)) {
+               LYXERR0("QProcess " << cmd << " did not finished!");
+               LYXERR0("error " << d.errorMessage());
+               LYXERR0("status " << d.exitStatusMessage());
                return 20;
        }
+
        int const exit_code = process->exitCode();
        if (exit_code) {
-               LYXERR0("Qprocess " << cmd << " finished!");
-               LYXERR0("exitCode " << process->exitCode());
-               LYXERR0("error " << process->error());
-               LYXERR0("state " << process->state());
-               LYXERR0("status " << process->exitStatus());
+               LYXERR0("QProcess " << cmd << " finished!");
+               LYXERR0("error " << exit_code << ": " << d.errorMessage()); 
        }
 
        // If the output has been redirected, we write it all at once.
@@ -145,19 +163,68 @@ int Systemcall::startscript(Starttype how, string const & what)
                            process->readAllStandardError().data()));
 
        killProcess(process);
+
        return exit_code;
 }
 
 
-ConOut::ConOut(QProcess * proc) : proc_(proc), outindex_(0), errindex_(0),
-                                 showout_(false), showerr_(false)
+SystemcallPrivate::SystemcallPrivate(QProcess * proc) : proc_(proc), outindex_(0), 
+                               errindex_(0), showout_(false), showerr_(false)
 {
        connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(stdOut()));
        connect(proc, SIGNAL(readyReadStandardError()), SLOT(stdErr()));
+       connect(proc, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError)));
+       connect(proc, SIGNAL(started()), this, SLOT(processStarted()));
+       connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
+}
+
+
+
+void SystemcallPrivate::startProcess(const QString& cmd)
+{
+       state = SystemcallPrivate::Starting;
+       proc_->start(cmd);
+}
+
+
+void SystemcallPrivate::waitAndProcessEvents()
+{
+       Sleep::millisec(100);
+       QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+}
+
+
+bool SystemcallPrivate::waitWhile(State waitwhile, bool processEvents, int timeout)
+{
+       // Block GUI while waiting,
+       // relay on QProcess' wait functions
+       if (!processEvents) {
+               if (waitwhile == Starting)
+                       return proc_->waitForStarted(timeout);
+               if (waitwhile == Running)
+                       return proc_->waitForFinished(timeout);
+               return false;
+       }
+
+       // process events while waiting, no timeout
+       if (timeout == -1) {
+               while (state == waitwhile && state != Error) {
+                       waitAndProcessEvents();
+               }
+               return state != Error;
+       } 
+
+       // process events while waiting whith timeout
+       QTime timer;
+       timer.start();
+       while (state == waitwhile && state != Error && timer.elapsed() < timeout) {
+               waitAndProcessEvents();
+       }
+       return (state != Error) && (timer.elapsed() < timeout);
 }
 
 
-ConOut::~ConOut()
+SystemcallPrivate::~SystemcallPrivate()
 {
        if (outindex_) {
                outdata_[outindex_] = '\0';
@@ -174,7 +241,7 @@ ConOut::~ConOut()
 }
 
 
-void ConOut::stdOut()
+void SystemcallPrivate::stdOut()
 {
        if (showout_) {
                char c;
@@ -191,7 +258,7 @@ void ConOut::stdOut()
 }
 
 
-void ConOut::stdErr()
+void SystemcallPrivate::stdErr()
 {
        if (showerr_) {
                char c;
@@ -207,6 +274,76 @@ void ConOut::stdErr()
        }
 }
 
+
+void SystemcallPrivate::processError(QProcess::ProcessError err)
+{
+       state = Error;
+}
+
+
+QString SystemcallPrivate::errorMessage() const 
+{
+       QString message;
+       switch (proc_->error()) {
+               case QProcess::FailedToStart:
+                       message = "The process failed to start. Either the invoked program is missing, "
+                                     "or you may have insufficient permissions to invoke the program.";
+                       break;
+               case QProcess::Crashed:
+                       message = "The process crashed some time after starting successfully.";
+                       break;
+               case QProcess::Timedout:
+                       message = "The process timed out. It might be restarted automatically.";
+                       break;
+               case QProcess::WriteError:
+                       message = "An error occurred when attempting to write to the process-> For example, "
+                                     "the process may not be running, or it may have closed its input channel.";
+                       break;
+               case QProcess::ReadError:
+                       message = "An error occurred when attempting to read from the process-> For example, "
+                                     "the process may not be running.";
+                       break;
+               case QProcess::UnknownError:
+               default:
+                       message = "An unknown error occured.";
+                       break;
+       }
+       return message;
+}
+
+
+void SystemcallPrivate::processStarted()
+{
+       state = Running;
+       // why do we get two started signals?
+       //disconnect(proc_, SIGNAL(started()), this, SLOT(processStarted()));
+}
+
+
+void SystemcallPrivate::processFinished(int, QProcess::ExitStatus status)
+{
+       state = Finished;
+}
+
+
+QString SystemcallPrivate::exitStatusMessage() const
+{
+       QString message;
+       switch (proc_->exitStatus()) {
+               case QProcess::NormalExit:
+                       message = "The process exited normally.";
+                       break;
+               case QProcess::CrashExit:
+                       message = "The process crashed.";
+                       break;
+               default:
+                       message = "Unknown exit state.";
+                       break;
+       }
+       return message;
+}
+
+
 #include "moc_SystemcallPrivate.cpp"
 #endif
 
index 93918ac71213a946e26b6fcd7aea0710380bd7b8..5e00f9846c337d7ebb167be75c4abe3e4fb8917f 100644 (file)
 
 #include <QObject>
 
-class QProcess;
+#include <QProcess>
 
 namespace lyx {
 namespace support {
 
+class Systemcall;
+
 /**
  * Outputs to the console terminal the line buffered standard output and
  * error of a spawned process when there is a controlling terminal and 
  * stdout/stderr have not been redirected.
  */
-class ConOut : public QObject
+class SystemcallPrivate : public QObject
 {
        Q_OBJECT
 public:
-       ConOut(QProcess * proc);
-       ~ConOut();
+       SystemcallPrivate(QProcess * proc);
+       ~SystemcallPrivate();
 
        /// Should the standard output be displayed?
        void showout() { showout_ = true; }
@@ -37,6 +39,22 @@ public:
        /// Should the standard error be displayed?
        void showerr() { showerr_ = true; }
 
+       enum State {
+               Starting,
+               Running,
+               Finished,
+               Error
+       };
+       State state;
+
+       bool waitWhile(State, bool processEvents, int timeout = -1);
+       void startProcess(const QString& cmd);
+       
+       QString errorMessage() const;
+       QString exitStatusMessage() const;
+
+
+
 private:
        /// Pointer to the process to monitor.
        QProcess * proc_;
@@ -55,9 +73,15 @@ private:
        /// 
        bool showerr_;
 
+       void waitAndProcessEvents();
+
 public Q_SLOTS:
        void stdOut();
        void stdErr();
+       void processError(QProcess::ProcessError);
+       void processStarted();
+       void processFinished(int, QProcess::ExitStatus status);
+
 };
 
 } // namespace support