#include //#include #include #include #include #include #include #include #include #include #define STR(expr) #expr #define DBG(expr) STR(expr) << "=" << (expr) class MyWidget : public QWidget { Q_OBJECT public: MyWidget(QWidget *aParent) : QWidget(aParent), mOtherProcess(0), mRedirectedToOtherProcess(false) { // children mProcess = new QProcess(this); mEditor = new QTextEdit(); mEditor->setReadOnly(true); mLineEdit = new QLineEdit(); mStatusLabel = new QLabel(); // connections connect(mProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(process_stateChanged(QProcess::ProcessState))); connect(mProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(process_error(QProcess::ProcessError))); connect(mProcess, SIGNAL(started()), this, SLOT(process_started())); connect(mProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(process_finished(int, QProcess::ExitStatus))); connect(mProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(process_readyReadStandardOutput())); connect(mProcess, SIGNAL(readyReadStandardError()), this, SLOT(process_readyReadStandardError())); connect(mLineEdit, SIGNAL(returnPressed()), this, SLOT(lineEdit_returnPressed())); // layout QVBoxLayout *l1 = new QVBoxLayout(); l1->addWidget(mEditor); l1->addWidget(mLineEdit); l1->addWidget(mStatusLabel); QHBoxLayout *mainLayout = new QHBoxLayout(); mainLayout->addLayout(l1); setLayout(mainLayout); mLineEdit->setFocus(); // initial values mLineEdit->setText("D:\\Coding\\qt\\smplayer_test\\mplayer.ex"); process_stateChanged(mProcess->state()); // other } QProcess *process() const { return mProcess; } void setOtherProcess(QProcess *aOtherProcess) { mOtherProcess = aOtherProcess; } private slots: void lineEdit_returnPressed() { QString text = mLineEdit->text(); if (text.isEmpty()) return; mLineEdit->clear(); text = text.trimmed(); QString cmd; if (text.startsWith('>')) { int ws = text.indexOf(' '); if (ws < 0) ws = text.length(); cmd = text.mid(1, ws - 1); text = text.mid(ws); text = text.trimmed(); } // @todo support for quoted strings QStringList words = text.split(' '); if (cmd.isNull() && mProcess->state() == QProcess::NotRunning) cmd = "s"; if (cmd.isNull()) { Q_ASSERT(mProcess->state() != QProcess::NotRunning); /* send the line to standard input */ QByteArray data = (text + "\n").toLocal8Bit(); mProcess->write(data); } else if (cmd == "s" || cmd == "ss" || cmd == "scd" || cmd == "sscd") { /* start process (..cd changes to its directory) */ if (words.count() < 1) { mEditor->append(tr("> ERROR: '%1' requires one argument").arg(cmd)); return; } if (mProcess->state() != QProcess::NotRunning) { mEditor->append(tr("> ERROR: Process is already running")); return; } QString workDir; if (cmd.endsWith("cd")) { QDir dir = QDir(QFileInfo(words[0]).path()); workDir = dir.absolutePath(); mProcess->setWorkingDirectory(workDir); } else { workDir = QDir::currentPath(); mProcess->setWorkingDirectory(QString()); } mEditor->append(tr("> Working directory: '%1'").arg(workDir)); mEditor->append(tr("> Starting: '%1'").arg(text)); mProcess->start(text); } else if (cmd == "mch" || cmd == "sch") { /* merge/separate stdout & stderr */ if (mProcess->state() != QProcess::NotRunning) { mEditor->append(tr("> ERROR: Process is already running")); return; } mProcess->setProcessChannelMode(cmd == "mch" ? QProcess::MergedChannels : QProcess::SeparateChannels); if (cmd == "mch") mEditor->append(tr("> Merged standard error stream to standard output")); else mEditor->append(tr("> Separated standard error stream from standard output")); } else if (cmd == "rso" || cmd == "rse") { /* redirect stdout & stderr */ if (mProcess->state() != QProcess::NotRunning) { mEditor->append(tr("> ERROR: Process is already running")); return; } bool output = cmd == "rso"; output ? mProcess->setStandardOutputFile(text) : mProcess->setStandardErrorFile(text); if (!text.isEmpty()) mEditor->append(tr("> Redirected standard %1 stream to: '%2'") .arg(output ? "output" : "error").arg(text)); else mEditor->append(tr("> Canceled redirection of standard %1") .arg(output ? "output" : "error")); } else if (cmd == "term") { /* terminate */ if (mProcess->state() == QProcess::NotRunning) { mEditor->append(tr("> ERROR: No process is running")); return; } mEditor->append(tr("> Sent terminate process request")); mProcess->terminate(); } else if (cmd == "kill") { /* kill */ if (mProcess->state() == QProcess::NotRunning) { mEditor->append(tr("> ERROR: No process is running")); return; } mEditor->append(tr("> Sent kill process request")); mProcess->kill(); } else if (cmd == "rtp") { /* redirect stdout to stdin of the other process */ if (mProcess->state() != QProcess::NotRunning) { mEditor->append(tr("> ERROR: Process is already running")); return; } if (!mRedirectedToOtherProcess) { mRedirectedToOtherProcess = true; mProcess->setStandardOutputProcess(mOtherProcess); mEditor->append(tr("> Redirected standard output to standard " "input of another process")); } else { mRedirectedToOtherProcess = false; mProcess->setStandardErrorFile(QString::null); mEditor->append(tr("> Canceled redirection of standard output")); } } else if (cmd == "d" || cmd == "dcd") { QString workDir; if (cmd.endsWith("cd")) { QDir dir = QDir(QFileInfo(words[0]).path()); workDir = dir.absolutePath(); } else { workDir = QDir::currentPath(); } mEditor->append(tr("> Working directory: '%1'").arg(workDir)); mEditor->append(tr("> Detaching: '%1'").arg(text)); QStringList args = words; QString prg = args.takeFirst(); qint64 pid; if (QProcess::startDetached(prg, args, workDir, &pid)) mEditor->append(tr("> Detached successfully (pid '%1')").arg(pid)); else mEditor->append(tr("> Detach failed")); } else { mEditor->append(tr("> ERROR: '%1' command is unknown").arg(cmd)); return; } } void process_stateChanged(QProcess::ProcessState aState) { QString state; switch (aState) { case QProcess::NotRunning: state = tr("NotRunning"); break; case QProcess::Starting: state = tr("Starting"); break; case QProcess::Running: state = tr("Running"); break; } mStatusLabel->setText(tr("%1 (PID: %2)").arg(state).arg((ulong)mProcess->pid())); } void process_error(QProcess::ProcessError aError) { QString error; switch (aError) { case QProcess::FailedToStart: error = tr("FailedToStart"); break; case QProcess::Crashed: error = tr("Crashed"); break; case QProcess::Timedout: error = tr("Timedout"); break; case QProcess::WriteError: error = tr("WriteError"); break; case QProcess::ReadError: error = tr("ReadError"); break; case QProcess::UnknownError: error = tr("UnknownError"); break; } mEditor->append(tr("> ERROR: %1: %2").arg(error).arg(mProcess->errorString())); } void process_started() { mEditor->append(tr("> Started: PID is %1").arg((ulong)mProcess->pid())); } void process_finished(int aExitCode, QProcess::ExitStatus aExitStatus) { QString exitStatus; switch (aExitStatus) { case QProcess::NormalExit: exitStatus = tr("NormalExit"); break; case QProcess::CrashExit: exitStatus = tr("CrashExit"); break; } mEditor->append(tr("> Finished: %1 with code %2").arg(exitStatus).arg(aExitCode)); } void process_readyReadStandardOutput() { QByteArray data = mProcess->readAllStandardOutput(); mEditor->append(QString::fromLocal8Bit(data)); } void process_readyReadStandardError() { QByteArray data = mProcess->readAllStandardError(); mEditor->append(QString::fromLocal8Bit(data)); } private: QProcess *mProcess; QProcess *mOtherProcess; bool mRedirectedToOtherProcess; QTextEdit *mEditor; QLineEdit *mLineEdit; QLabel *mStatusLabel; }; //////////////////////////////////////////////////////////////////////////////// class MyDialog : public QWidget { Q_OBJECT public: MyDialog() : QWidget(0, Qt::Window) { // children QTabWidget *tabs = new QTabWidget(); mWidget1 = new MyWidget(tabs); mWidget2 = new MyWidget(tabs); mWidget1->setOtherProcess(mWidget2->process()); mWidget2->setOtherProcess(mWidget1->process()); tabs->addTab(mWidget1, QLatin1String("Process 1")); tabs->addTab(mWidget2, QLatin1String("Process 2")); // connections // layout QHBoxLayout *mainLayout = new QHBoxLayout(); mainLayout->addWidget(tabs); setLayout(mainLayout); // initial values tabs->currentWidget()->setFocus(); // other } private: MyWidget *mWidget1; MyWidget *mWidget2; }; //////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { #if 1 QApplication app(argc, argv); MyDialog dialog; dialog.resize(800, 400); dialog.show(); return app.exec(); #else qDebug() << "Starting..."; QProcess proc; #if defined(Q_OS_OS2) //proc.start("cmd.exe /c dir >bbb"); //proc.start("cmd /c start /n newview.exe"); proc.start("test"); #elif defined(Q_OS_WIN) proc.start("notepad.exe"); #endif qDebug() << "Waiting for finished..."; proc.waitForFinished(); qDebug() << "DONE"; #endif } #include "process-async.moc"