work save: oj problem cases runner

This commit is contained in:
royqh1979 2021-11-01 09:18:23 +08:00
parent 46b95c03ae
commit 9f4e8344a3
13 changed files with 335 additions and 42 deletions

View File

@ -20,7 +20,9 @@ SOURCES += \
codeformatter.cpp \
codesnippetsmanager.cpp \
colorscheme.cpp \
compiler/ojproblemcasesrunner.cpp \
compiler/projectcompiler.cpp \
compiler/runner.cpp \
platform.cpp \
compiler/compiler.cpp \
compiler/compilermanager.cpp \
@ -140,7 +142,9 @@ HEADERS += \
compiler/compilermanager.h \
compiler/executablerunner.h \
compiler/filecompiler.h \
compiler/ojproblemcasesrunner.h \
compiler/projectcompiler.h \
compiler/runner.h \
compiler/stdincompiler.h \
cpprefacter.h \
parser/cppparser.h \

View File

@ -3,6 +3,7 @@
#include "stdincompiler.h"
#include "../mainwindow.h"
#include "executablerunner.h"
#include "ojproblemcasesrunner.h"
#include "utils.h"
#include "../settings.h"
#include <QMessageBox>
@ -208,6 +209,7 @@ void CompilerManager::run(const QString &filename, const QString &arguments, con
redirectInput =true;
redirectInputFilename = pSettings->executor().inputFilename();
}
ExecutableRunner * execRunner;
if (programHasConsole(filename)) {
int consoleFlag=0;
if (redirectInput)
@ -217,18 +219,49 @@ void CompilerManager::run(const QString &filename, const QString &arguments, con
QString newArguments = QString(" %1 \"%2\" %3")
.arg(consoleFlag)
.arg(toLocalPath(filename)).arg(arguments);
mRunner = new ExecutableRunner(includeTrailingPathDelimiter(pSettings->dirs().app())+"ConsolePauser.exe",newArguments,workDir);
mRunner->setStartConsole(true);
execRunner = new ExecutableRunner(includeTrailingPathDelimiter(pSettings->dirs().app())+"ConsolePauser.exe",newArguments,workDir);
execRunner->setStartConsole(true);
} else {
mRunner = new ExecutableRunner(filename,arguments,workDir);
execRunner = new ExecutableRunner(filename,arguments,workDir);
}
if (redirectInput) {
mRunner->setRedirectInput(true);
mRunner->setRedirectInputFilename(redirectInputFilename);
execRunner->setRedirectInput(true);
execRunner->setRedirectInputFilename(redirectInputFilename);
}
connect(mRunner, &ExecutableRunner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &ExecutableRunner::finished, pMainWindow ,&MainWindow::onRunFinished);
connect(mRunner, &ExecutableRunner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
mRunner = execRunner;
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
mRunner->start();
}
void CompilerManager::runProblem(const QString &filename, const QString &arguments, const QString &workDir, POJProblemCase problemCase)
{
QMutexLocker locker(&mRunnerMutex);
if (mRunner!=nullptr) {
return;
}
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCase);
mRunner = execRunner;
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
// connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted);
mRunner->start();
}
void CompilerManager::runProblem(const QString &filename, const QString &arguments, const QString &workDir, QVector<POJProblemCase> problemCases)
{
QMutexLocker locker(&mRunnerMutex);
if (mRunner!=nullptr) {
return;
}
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCases);
mRunner = execRunner;
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
// connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted);
mRunner->start();
}
@ -268,7 +301,7 @@ void CompilerManager::onCompileFinished()
void CompilerManager::onRunnerTerminated()
{
QMutexLocker locker(&mRunnerMutex);
ExecutableRunner* p=mRunner;
Runner* p=mRunner;
mRunner=nullptr;
p->deleteLater();
}

View File

@ -6,9 +6,11 @@
#include "../utils.h"
#include "../common.h"
class ExecutableRunner;
class Runner;
class Compiler;
class Project;
class OJProblemCase;
using POJProblemCase = std::shared_ptr<OJProblemCase>;
class CompilerManager : public QObject
{
Q_OBJECT
@ -25,6 +27,8 @@ public:
void buildProjectMakefile(std::shared_ptr<Project> project);
void checkSyntax(const QString&filename, const QString& content, bool isAscii, std::shared_ptr<Project> project);
void run(const QString& filename, const QString& arguments, const QString& workDir);
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, POJProblemCase problemCase);
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, QVector<POJProblemCase> problemCases);
void stopRun();
void stopCompile();
void stopCheckSyntax();
@ -51,7 +55,7 @@ private:
int mSyntaxCheckErrorCount;
int mSyntaxCheckIssueCount;
Compiler* mBackgroundSyntaxChecker;
ExecutableRunner* mRunner;
Runner* mRunner;
QRecursiveMutex mCompileMutex;
QRecursiveMutex mBackgroundSyntaxCheckMutex;
QRecursiveMutex mRunnerMutex;

View File

@ -7,23 +7,15 @@
#include "../settings.h"
#include "../systemconsts.h"
ExecutableRunner::ExecutableRunner(const QString &filename, const QString &arguments, const QString &workDir):
QThread(),
mFilename(filename),
mArguments(arguments),
mWorkDir(workDir),
mStop(false),
ExecutableRunner::ExecutableRunner(const QString &filename, const QString &arguments, const QString &workDir
,QObject* parent):
Runner(filename,arguments,workDir,parent),
mRedirectInput(false),
mStartConsole(false)
{
}
void ExecutableRunner::stop()
{
mStop = true;
}
bool ExecutableRunner::startConsole() const
{
return mStartConsole;
@ -57,6 +49,9 @@ void ExecutableRunner::setRedirectInputFilename(const QString &newDataFile)
void ExecutableRunner::run()
{
emit started();
auto action = finally([this]{
emit terminated();
});
QProcess process;
mStop = false;
bool errorOccurred = false;
@ -142,5 +137,4 @@ void ExecutableRunner::run()
break;
}
}
emit terminated();
}

View File

@ -1,13 +1,14 @@
#ifndef EXECUTABLERUNNER_H
#define EXECUTABLERUNNER_H
#include <QThread>
#include "runner.h"
class ExecutableRunner : public QThread
class ExecutableRunner : public Runner
{
Q_OBJECT
public:
ExecutableRunner(const QString& filename, const QString& arguments, const QString& workDir);
ExecutableRunner(const QString& filename, const QString& arguments, const QString& workDir,
QObject* parent = nullptr);
const QString &redirectInputFilename() const;
void setRedirectInputFilename(const QString &newDataFile);
@ -18,19 +19,7 @@ public:
bool startConsole() const;
void setStartConsole(bool newStartConsole);
signals:
void started();
void terminated();
void runErrorOccurred(const QString& reason);
public slots:
void stop();
private:
QString mFilename;
QString mArguments;
QString mWorkDir;
bool mStop;
QString mRedirectInputFilename;
bool mRedirectInput;
bool mStartConsole;

View File

@ -0,0 +1,120 @@
#include "ojproblemcasesrunner.h"
#include "../utils.h"
#include "../settings.h"
#include "../systemconsts.h"
#include "../widgets/ojproblemsetmodel.h"
#include <QProcess>
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
const QVector<POJProblemCase>& problemCases, QObject *parent):
Runner(filename,arguments,workDir,parent)
{
mProblemCases = problemCases;
}
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
POJProblemCase problemCase, QObject *parent):
Runner(filename,arguments,workDir,parent)
{
mProblemCases.append(problemCase);
}
void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
{
emit caseStarted(mProblemCases.count(),index);
auto action = finally([this,&index]{
emit caseStarted(mProblemCases.count(),index);
});
QProcess process;
bool errorOccurred = false;
process.setProgram(mFilename);
process.setArguments(QProcess::splitCommand(mArguments));
process.setWorkingDirectory(mWorkDir);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH");
QStringList pathAdded;
if (pSettings->compilerSets().defaultSet()) {
foreach(const QString& dir, pSettings->compilerSets().defaultSet()->binDirs()) {
pathAdded.append(dir);
}
}
pathAdded.append(pSettings->dirs().app());
if (!path.isEmpty()) {
path+= PATH_SEPARATOR + pathAdded.join(PATH_SEPARATOR);
} else {
path = pathAdded.join(PATH_SEPARATOR);
}
env.insert("PATH",path);
process.setProcessEnvironment(env);
process.setProcessChannelMode(QProcess::MergedChannels);
process.connect(&process, &QProcess::errorOccurred,
[&](){
errorOccurred= true;
});
problemCase->output.clear();
process.start();
process.waitForStarted(5000);
if (process.state()==QProcess::Running) {
process.write(problemCase->input.toUtf8());
process.closeWriteChannel();
}
QByteArray readed;
while (true) {
process.waitForFinished(1000);
if (process.state()!=QProcess::Running) {
break;
}
if (mStop) {
process.closeReadChannel(QProcess::StandardOutput);
process.closeReadChannel(QProcess::StandardError);
process.closeWriteChannel();
process.terminate();
process.kill();
break;
}
readed += process.readAll();
if (errorOccurred)
break;
}
if (errorOccurred) {
//qDebug()<<"process error:"<<process.error();
switch (process.error()) {
case QProcess::FailedToStart:
emit runErrorOccurred(tr("The runner process '%1' failed to start.").arg(mFilename));
break;
// case QProcess::Crashed:
// if (!mStop)
// emit runErrorOccurred(tr("The runner process crashed after starting successfully."));
// break;
case QProcess::Timedout:
emit runErrorOccurred(tr("The last waitFor...() function timed out."));
break;
case QProcess::WriteError:
emit runErrorOccurred(tr("An error occurred when attempting to write to the runner process."));
break;
case QProcess::ReadError:
emit runErrorOccurred(tr("An error occurred when attempting to read from the runner process."));
break;
default:
break;
}
}
problemCase->output = QString::fromUtf8(readed);
}
void OJProblemCasesRunner::run()
{
emit started();
auto action = finally([this]{
emit terminated();
});
for (int i=0;i<mProblemCases.size();i++) {
if (mStop)
break;
POJProblemCase problemCase =mProblemCases[i];
runCase(i,problemCase);
}
}

View File

@ -0,0 +1,31 @@
#ifndef OJPROBLEMCASESRUNNER_H
#define OJPROBLEMCASESRUNNER_H
#include "runner.h"
#include <QVector>
class OJProblemCase;
using POJProblemCase = std::shared_ptr<OJProblemCase>;
class OJProblemCasesRunner : public Runner
{
Q_OBJECT
public:
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
const QVector<POJProblemCase>& problemCases, QObject *parent = nullptr);
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
POJProblemCase problemCase, QObject *parent = nullptr);
signals:
void caseStarted(int total, int current);
void caseFinished(int total, int current);
private:
void runCase(int index, POJProblemCase problemCase);
private:
QVector<POJProblemCase> mProblemCases;
// QThread interface
protected:
void run() override;
};
#endif // OJPROBLEMCASESRUNNER_H

View File

@ -0,0 +1,17 @@
#include "runner.h"
Runner::Runner(const QString &filename, const QString &arguments, const QString &workDir
,QObject *parent) : QThread(parent),
mStop(false),
mFilename(filename),
mArguments(arguments),
mWorkDir(workDir)
{
}
void Runner::stop()
{
mStop = true;
}

View File

@ -0,0 +1,27 @@
#ifndef RUNNER_H
#define RUNNER_H
#include <QThread>
class Runner : public QThread
{
Q_OBJECT
public:
explicit Runner(const QString& filename, const QString& arguments, const QString& workDir, QObject *parent = nullptr);
signals:
void started();
void terminated();
void runErrorOccurred(const QString& reason);
public slots:
void stop();
protected:
bool mStop;
QString mFilename;
QString mArguments;
QString mWorkDir;
};
#endif // RUNNER_H

View File

@ -3314,6 +3314,7 @@ void MainWindow::onCompileErrorOccured(const QString &reason)
void MainWindow::onRunErrorOccured(const QString &reason)
{
mCompilerManager->stopRun();
QMessageBox::critical(this,tr("Run Failed"),reason);
}
@ -4891,8 +4892,18 @@ void MainWindow::on_actionRun_Parameters_triggered()
void MainWindow::on_btnNewProblemSet_clicked()
{
if (mOJProblemSetModel.count()>0) {
if (QMessageBox::warning(this,
tr("New Problem Set"),
tr("The current problem set is not empty.")
+"<br />"
+tr("Do you want to save it?"),
QMessageBox::Yes | QMessageBox::No)!=QMessageBox::Yes)
return;
}
mOJProblemSetNameCounter++;
mOJProblemSetModel.create(tr("Problem Set %1").arg(mOJProblemSetNameCounter));
ui->lblProblemSet->setText(mOJProblemSetModel.name());
}
@ -4954,6 +4965,7 @@ void MainWindow::on_btnLoadProblemSet_clicked()
error.reason());
}
}
ui->lblProblemSet->setText(mOJProblemSetModel.name());
}

View File

@ -263,6 +263,10 @@
</layout>
</widget>
<widget class="QWidget" name="tabProblemSet">
<attribute name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/images/newlook24/014-compopt.png</normaloff>:/icons/images/newlook24/014-compopt.png</iconset>
</attribute>
<attribute name="title">
<string>Problem Set</string>
</attribute>
@ -391,7 +395,14 @@
</widget>
</item>
<item>
<widget class="QListView" name="lstProblemSet"/>
<widget class="QListView" name="lstProblemSet">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
</layout>
</widget>
@ -1222,6 +1233,16 @@
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="pbProblemCases">
<property name="value">
<number>24</number>
</property>
<property name="format">
<string>%v/%m</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
@ -1239,7 +1260,14 @@
</widget>
</item>
<item>
<widget class="QListView" name="lstProblemCases"/>
<widget class="QListView" name="lstProblemCases">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
</layout>
</widget>

View File

@ -153,12 +153,31 @@ QVariant OJProblemSetModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole) {
if (role == Qt::DisplayRole || role == Qt::EditRole) {
return mProblemSet.problems[index.row()]->name;
}
return QVariant();
}
bool OJProblemSetModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
if (role == Qt::EditRole) {
QString s = value.toString();
if (!s.isEmpty()) {
mProblemSet.problems[index.row()]->name = s;
return true;
}
}
return false;
}
Qt::ItemFlags OJProblemSetModel::flags(const QModelIndex &) const
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
OJProblemModel::OJProblemModel(QObject *parent): QAbstractListModel(parent)
{
@ -233,8 +252,19 @@ QVariant OJProblemModel::data(const QModelIndex &index, int role) const
return QVariant();
if (mProblem==nullptr)
return QVariant();
if (role == Qt::DisplayRole) {
if (role == Qt::DisplayRole || role == Qt::EditRole) {
return mProblem->cases[index.row()]->name;
}
return QVariant();
}
bool OJProblemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid())
return false;
}
Qt::ItemFlags OJProblemModel::flags(const QModelIndex &) const
{
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
}

View File

@ -52,6 +52,8 @@ private:
public:
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
};
class OJProblemSetModel : public QAbstractListModel
@ -78,6 +80,8 @@ private:
public:
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
};
#endif // OJPROBLEMSETMODEL_H