X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2FSystemcall.cpp;h=d4f71ffcd9eadd9d95edf2cf004f1e22ee4c059f;hb=4480b72a9dc8a5453a17edf55d4d4a60847a68ae;hp=4273983bd2c458229a529e13424cb86f22bc8e4c;hpb=29627f1680755510f116b36efd951b518234a878;p=lyx.git diff --git a/src/support/Systemcall.cpp b/src/support/Systemcall.cpp index 4273983bd2..d4f71ffcd9 100644 --- a/src/support/Systemcall.cpp +++ b/src/support/Systemcall.cpp @@ -15,6 +15,7 @@ #include "support/debug.h" #include "support/filetools.h" +#include "support/gettext.h" #include "support/lstrings.h" #include "support/qstring_helpers.h" #include "support/Systemcall.h" @@ -22,6 +23,7 @@ #include "support/os.h" #include "support/ProgressInterface.h" +#include "LyX.h" #include "LyXRC.h" #include @@ -38,7 +40,7 @@ struct Sleep : QThread { - static void millisec(unsigned long ms) + static void millisec(unsigned long ms) { QThread::usleep(ms * 1000); } @@ -53,7 +55,7 @@ namespace lyx { namespace support { -class ProgressDummy : public ProgressInterface +class ProgressDummy : public ProgressInterface { public: ProgressDummy() {} @@ -70,12 +72,14 @@ public: void warning(QString const &, QString const &) {} void toggleWarning(QString const &, QString const &, QString const &) {} - void error(QString const &, QString const &) {} + void error(QString const &, QString const &, QString const &) {} void information(QString const &, QString const &) {} + int prompt(docstring const &, docstring const &, int default_but, int, + docstring const &, docstring const &) { return default_but; } }; -static ProgressInterface* progress_instance = 0; +static ProgressInterface * progress_instance = 0; void ProgressInterface::setInstance(ProgressInterface* p) { @@ -83,7 +87,7 @@ void ProgressInterface::setInstance(ProgressInterface* p) } -ProgressInterface* ProgressInterface::instance() +ProgressInterface * ProgressInterface::instance() { if (!progress_instance) { static ProgressDummy dummy; @@ -98,15 +102,12 @@ ProgressInterface* ProgressInterface::instance() // Reuse of instance #ifndef USE_QPROCESS int Systemcall::startscript(Starttype how, string const & what, - std::string const & path, bool /*process_events*/) + string const & path, string const & lpath, + bool /*process_events*/) { - string const python_call = "python -tt"; - string command = to_filesystem8bit(from_utf8(latexEnvCmdPrefix(path))); - - if (prefixIs(what, python_call)) - command += os::python() + what.substr(python_call.length()); - else - command += what; + string command = + to_filesystem8bit(from_utf8(latexEnvCmdPrefix(path, lpath))) + + commandPrep(what); if (how == DontWait) { switch (os::shell()) { @@ -230,37 +231,38 @@ string const parsecmd(string const & incmd, string & infile, string & outfile, return trim(outcmd[0]); } -} // namespace anon - +} // namespace int Systemcall::startscript(Starttype how, string const & what, - string const & path, bool process_events) + string const & path, string const & lpath, + bool process_events) { - lyxerr << "\nRunning: " << what << endl; + string const what_ss = commandPrep(what); + if (verbose) + lyxerr << "\nRunning: " << what_ss << endl; + else + LYXERR(Debug::INFO,"Running: " << what_ss); string infile; string outfile; string errfile; - QString cmd = QString::fromLocal8Bit( - parsecmd(what, infile, outfile, errfile).c_str()); + QString const cmd = QString::fromLocal8Bit( + parsecmd(what_ss, infile, outfile, errfile).c_str()); SystemcallPrivate d(infile, outfile, errfile); + d.startProcess(cmd, path, lpath, how == DontWait); + if (how == DontWait && d.state == SystemcallPrivate::Running) + return 0; - d.startProcess(cmd, path); - if (!d.waitWhile(SystemcallPrivate::Starting, process_events, -1)) { + if (d.state == SystemcallPrivate::Error + || !d.waitWhile(SystemcallPrivate::Starting, process_events, -1)) { LYXERR0("Systemcall: '" << cmd << "' did not start!"); LYXERR0("error " << d.errorMessage()); return 10; } - if (how == DontWait) { - QProcess* released = d.releaseProcess(); - (void) released; // TODO who deletes it? - return 0; - } - if (!d.waitWhile(SystemcallPrivate::Running, process_events, os::timeout_min() * 60 * 1000)) { LYXERR0("Systemcall: '" << cmd << "' did not finish!"); @@ -278,16 +280,10 @@ int Systemcall::startscript(Starttype how, string const & what, } -SystemcallPrivate::SystemcallPrivate(std::string const & sf, - std::string const & of, - std::string const & ef) : - process_(new QProcess), - out_index_(0), - err_index_(0), - in_file_(sf), - out_file_(of), - err_file_(ef), - process_events_(false) +SystemcallPrivate::SystemcallPrivate(std::string const & sf, std::string const & of, + std::string const & ef) + : state(Error), process_(new QProcess), out_index_(0), err_index_(0), + in_file_(sf), out_file_(of), err_file_(ef), process_events_(false) { if (!in_file_.empty()) process_->setStandardInputFile(QString::fromLocal8Bit(in_file_.c_str())); @@ -340,25 +336,47 @@ SystemcallPrivate::SystemcallPrivate(std::string const & sf, connect(process_, SIGNAL(readyReadStandardOutput()), SLOT(stdOut())); connect(process_, SIGNAL(readyReadStandardError()), SLOT(stdErr())); +#if QT_VERSION >= 0x050600 + connect(process_, SIGNAL(errorOccurred(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); +#else connect(process_, SIGNAL(error(QProcess::ProcessError)), SLOT(processError(QProcess::ProcessError))); +#endif connect(process_, SIGNAL(started()), this, SLOT(processStarted())); connect(process_, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus))); } -void SystemcallPrivate::startProcess(QString const & cmd, string const & path) +void SystemcallPrivate::startProcess(QString const & cmd, string const & path, + string const & lpath, bool detached) { cmd_ = cmd; - if (process_) { + if (detached) { + state = SystemcallPrivate::Running; +#ifdef Q_OS_WIN32 + // Avoid opening a console window when a viewer is started + if (in_file_.empty()) + process_->setStandardInputFile(QProcess::nullDevice()); + if (out_file_.empty()) + process_->setStandardOutputFile(QProcess::nullDevice()); + if (err_file_.empty()) + process_->setStandardErrorFile(QProcess::nullDevice()); +#endif + if (!QProcess::startDetached(toqstr(latexEnvCmdPrefix(path, lpath)) + cmd_)) { + state = SystemcallPrivate::Error; + return; + } + QProcess* released = releaseProcess(); + delete released; + } else if (process_) { state = SystemcallPrivate::Starting; - process_->start(toqstr(latexEnvCmdPrefix(path)) + cmd_); + process_->start(toqstr(latexEnvCmdPrefix(path, lpath)) + cmd_); } } void SystemcallPrivate::processEvents() { - if(process_events_) { + if (process_events_) { QCoreApplication::processEvents(/*QEventLoop::ExcludeUserInputEvents*/); } } @@ -371,11 +389,26 @@ void SystemcallPrivate::waitAndProcessEvents() } +namespace { + +bool queryStopCommand(QString const & cmd) +{ + docstring text = bformat(_( + "The command\n%1$s\nhas not yet completed.\n\n" + "Do you want to stop it?"), qstring_to_ucs4(cmd)); + return ProgressInterface::instance()->prompt(_("Stop command?"), text, + 1, 1, _("&Stop it"), _("Let it &run")) == 0; +} + +} // namespace + + bool SystemcallPrivate::waitWhile(State waitwhile, bool process_events, int timeout) { if (!process_) return false; + bool timedout = false; process_events_ = process_events; // Block GUI while waiting, @@ -383,8 +416,24 @@ bool SystemcallPrivate::waitWhile(State waitwhile, bool process_events, int time if (!process_events_) { if (waitwhile == Starting) return process_->waitForStarted(timeout); - if (waitwhile == Running) - return process_->waitForFinished(timeout); + if (waitwhile == Running) { + int bump = 2; + while (!timedout) { + if (process_->waitForFinished(timeout)) + return true; + bool stop = queryStopCommand(cmd_); + // The command may have finished in the meantime + if (process_->state() == QProcess::NotRunning) + return true; + if (stop) { + timedout = true; + process_->kill(); + } else { + timeout *= bump; + bump = 3; + } + } + } return false; } @@ -394,15 +443,26 @@ bool SystemcallPrivate::waitWhile(State waitwhile, bool process_events, int time waitAndProcessEvents(); } return state != Error; - } + } - // process events while waiting whith timeout + // process events while waiting with timeout QTime timer; timer.start(); - while (state == waitwhile && state != Error && timer.elapsed() < timeout) { + while (state == waitwhile && state != Error && !timedout) { waitAndProcessEvents(); + if (timer.elapsed() > timeout) { + bool stop = queryStopCommand(cmd_); + // The command may have finished in the meantime + if (process_->state() == QProcess::NotRunning) + break; + if (stop) { + timedout = true; + process_->kill(); + } else + timeout *= 3; + } } - return (state != Error) && (timer.elapsed() < timeout); + return (state != Error) && !timedout; } @@ -486,7 +546,7 @@ void SystemcallPrivate::processError(QProcess::ProcessError) } -QString SystemcallPrivate::errorMessage() const +QString SystemcallPrivate::errorMessage() const { if (!process_) return "No QProcess available"; @@ -513,7 +573,7 @@ QString SystemcallPrivate::errorMessage() const break; case QProcess::UnknownError: default: - message = "An unknown error occured."; + message = "An unknown error occurred."; break; } return message; @@ -543,7 +603,9 @@ QString SystemcallPrivate::exitStatusMessage() const int SystemcallPrivate::exitCode() { - if (!process_) + // From Qt's documentation, in regards to QProcess::exitCode(), + // "This value is not valid unless exitStatus() returns NormalExit" + if (!process_ || process_->exitStatus() != QProcess::NormalExit) return -1; return process_->exitCode();