- fix: can't stop a freeze program that has stdin redirected.

- enhancement: context menu for problem cases table
This commit is contained in:
Roy Qu 2022-03-30 19:28:46 +08:00
parent 1d845cc843
commit 7bc5a2ee7a
10 changed files with 86 additions and 29 deletions

View File

@ -13,6 +13,8 @@ Red Panda C++ Version 1.0.2
- enhancement: auto position cursor in expected with output's cursor
- enhancement: display line number in problem case's input/output/expected input controls
- enhancement: only tag the first inconstantency when running problem case, to greatly reduce compare & display time
- fix: can't stop a freeze program that has stdin redirected.
- enhancement: context menu for problem cases table
Red Panda C++ Version 1.0.1
- fix: only convert project icon file when it's filename doesn't end with ".ico"

View File

@ -178,18 +178,14 @@ void ExecutableRunner::run()
mProcess->waitForStarted(5000);
if (mProcess->state()==QProcess::Running && redirectInput()) {
mProcess->write(readFileToByteArray(redirectInputFilename()));
mProcess->closeWriteChannel();
}
bool writeChannelClosed = false;
while (true) {
mProcess->waitForFinished(mWaitForFinishTime);
if (mProcess->state()!=QProcess::Running) {
break;
}
if (mStop) {
mProcess->closeReadChannel(QProcess::StandardOutput);
mProcess->closeReadChannel(QProcess::StandardError);
mProcess->closeWriteChannel();
mProcess->terminate();
if (mProcess->waitForFinished(1000)) {
break;
@ -202,6 +198,10 @@ void ExecutableRunner::run()
}
break;
}
if (mProcess->bytesToWrite()==0 && redirectInput() && !writeChannelClosed) {
writeChannelClosed=true;
mProcess->closeWriteChannel();
}
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
if (mStartConsole && !mPausing && pBuf) {
if (strncmp(pBuf,"FINISHED",sizeof("FINISHED"))==0) {

View File

@ -25,8 +25,7 @@
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
const QVector<POJProblemCase>& problemCases, QObject *parent):
Runner(filename,arguments,workDir,parent),
mExecTimeout(-1),
mExecTimeouted(false)
mExecTimeout(-1)
{
mProblemCases = problemCases;
mBufferSize = 8192;
@ -37,8 +36,7 @@ OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QStrin
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
POJProblemCase problemCase, QObject *parent):
Runner(filename,arguments,workDir,parent),
mExecTimeout(-1),
mExecTimeouted(false)
mExecTimeout(-1)
{
mProblemCases.append(problemCase);
mBufferSize = 8192;
@ -59,12 +57,14 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
QByteArray output;
int noOutputTime = 0;
QElapsedTimer elapsedTimer;
bool execTimeouted = false;
process.setProgram(mFilename);
process.setArguments(splitProcessCommand(mArguments));
process.setWorkingDirectory(mWorkDir);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH");
QStringList pathAdded;
bool writeChannelClosed = false;
if (pSettings->compilerSets().defaultSet()) {
foreach(const QString& dir, pSettings->compilerSets().defaultSet()->binDirs()) {
pathAdded.append(dir);
@ -92,33 +92,33 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
process.write(readFileToByteArray(problemCase->inputFileName));
else
process.write(problemCase->input.toUtf8());
process.closeWriteChannel();
}
elapsedTimer.start();
while (true) {
process.waitForFinished(mWaitForFinishTime);
readed = process.read(mBufferSize);
buffer += readed;
if (process.state()!=QProcess::Running) {
break;
}
if (mExecTimeout>0) {
int msec = elapsedTimer.elapsed();
if (msec>mExecTimeout) {
mExecTimeouted=true;
execTimeouted=true;
}
}
if (mStop || mExecTimeouted) {
process.closeReadChannel(QProcess::StandardOutput);
process.closeReadChannel(QProcess::StandardError);
process.closeWriteChannel();
if (mStop || execTimeouted) {
process.terminate();
process.kill();
break;
}
if (errorOccurred)
break;
if (process.bytesToWrite()==0 && !writeChannelClosed) {
writeChannelClosed = true;
process.closeWriteChannel();
}
readed = process.read(mBufferSize);
buffer += readed;
if (buffer.length()>=mBufferSize || noOutputTime > mOutputRefreshTime) {
if (!buffer.isEmpty()) {
emit newOutputGetted(problemCase->getId(),QString::fromLocal8Bit(buffer));
@ -131,7 +131,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
}
}
problemCase->runningTime=elapsedTimer.elapsed();
if (mExecTimeouted) {
if (execTimeouted) {
problemCase->output = tr("Case Timeout");
emit resetOutput(problemCase->getId(), problemCase->output);
} else {
@ -139,6 +139,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
buffer += process.readAll();
emit newOutputGetted(problemCase->getId(),QString::fromLocal8Bit(buffer));
output.append(buffer);
problemCase->output = QString::fromLocal8Bit(output);
if (errorOccurred) {
//qDebug()<<"process error:"<<process.error();
switch (process.error()) {
@ -162,7 +163,6 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
break;
}
}
problemCase->output = QString::fromLocal8Bit(output);
}
}
@ -180,11 +180,6 @@ void OJProblemCasesRunner::run()
}
}
bool OJProblemCasesRunner::execTimeouted() const
{
return mExecTimeouted;
}
int OJProblemCasesRunner::execTimeout() const
{
return mExecTimeout;

View File

@ -43,8 +43,6 @@ public:
int execTimeout() const;
void setExecTimeout(int newExecTimeout);
bool execTimeouted() const;
signals:
void caseStarted(const QString &caseId, int current, int total);
void caseFinished(const QString &caseId, int current, int total);
@ -62,7 +60,6 @@ private:
int mBufferSize;
int mOutputRefreshTime;
int mExecTimeout;
bool mExecTimeouted;
};
#endif // OJPROBLEMCASESRUNNER_H

View File

@ -151,6 +151,8 @@ bool Debugger::start(const QString& inferior)
&WatchModel::addVarChild);
connect(mReader, &DebugReader::varValueUpdated,mWatchModel,
&WatchModel::updateVarValue);
connect(mReader, &DebugReader::varsValueUpdated,mWatchModel,
&WatchModel::updateAllHasMoreVars);
connect(mReader, &DebugReader::inferiorContinued,pMainWindow,
&MainWindow::removeActiveBreakpoints);
connect(mReader, &DebugReader::inferiorStopped,pMainWindow,
@ -1262,6 +1264,8 @@ void DebugReader::handleUpdateVarValue(const QList<GDBMIResultParser::ParseValue
emit varValueUpdated(name,val,inScope,typeChanged,newType,newNumChildren,
hasMore);
}
//todo: -var-list-children will freeze if the var is not correctly initialized
//emit varsValueUpdated();
}
QByteArray DebugReader::removeToken(const QByteArray &line)
@ -2008,6 +2012,16 @@ void WatchModel::updateVarValue(const QString &name, const QString &val, const Q
emit dataChanged(idx,createIndex(idx.row(),2,var.get()));
}
void WatchModel::updateAllHasMoreVars()
{
foreach (const PWatchVar& var, mVarIndex.values()) {
if (var->hasMore) {
QModelIndex idx = index(var);
fetchMore(idx);
}
}
}
void WatchModel::clearAllVarInfos()
{
beginResetModel();

View File

@ -196,6 +196,7 @@ public slots:
const QString& inScope, bool typeChanged,
const QString& newType, int newNumChildren,
bool hasMore);
void updateAllHasMoreVars();
signals:
void fetchChildren(const QString& name);
private:
@ -456,6 +457,7 @@ signals:
const QString& inScope, bool typeChanged,
const QString& newType, int newNumChildren,
bool hasMore);
void varsValueUpdated();
private:
void clearCmdQueue();

View File

@ -2250,6 +2250,23 @@ void MainWindow::buildContextMenus()
connect(mProblem_OpenSource, &QAction::triggered, this,
&MainWindow::onProblemOpenSource);
//context menu signal for the problem list view
ui->tblProblemCases->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tblProblemCases, &QWidget::customContextMenuRequested,
this, &MainWindow::onTableProblemCasesContextMenu);
mProblem_RunAllCases = createActionFor(
tr("Run All Cases"),
ui->tblProblemCases
);
connect(mProblem_RunAllCases, &QAction::triggered, this,
&MainWindow::on_btnRunAllProblemCases_clicked);
mProblem_RunCurrentCase = createActionFor(
tr("Run Current Case"),
ui->tblProblemCases
);
connect(mProblem_RunCurrentCase, &QAction::triggered, this,
&MainWindow::onProblemRunCurrentCase);
//context menu signal for the Problem Set lable
ui->lblProblemSet->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->lblProblemSet, &QWidget::customContextMenuRequested,
@ -3117,6 +3134,17 @@ void MainWindow::onLstProblemSetContextMenu(const QPoint &pos)
menu.exec(ui->lstProblemSet->mapToGlobal(pos));
}
void MainWindow::onTableProblemCasesContextMenu(const QPoint &pos)
{
QMenu menu(this);
QModelIndex idx = ui->tblProblemCases->currentIndex();
menu.addAction(mProblem_RunAllCases);
menu.addAction(mProblem_RunCurrentCase);
mProblem_RunAllCases->setEnabled(mOJProblemModel.count()>0);
mProblem_RunCurrentCase->setEnabled(idx.isValid());
menu.exec(ui->tblProblemCases->mapToGlobal(pos));
}
void MainWindow::onToolsOutputContextMenu(const QPoint &pos)
{
QMenu menu(this);
@ -3216,6 +3244,12 @@ void MainWindow::onProblemNameChanged(int index)
}
}
void MainWindow::onProblemRunCurrentCase()
{
applyCurrentProblemCaseChanges();
runExecutable(RunType::CurrentProblemCase);
}
void MainWindow::onNewProblemConnection()
{
QTcpSocket* clientConnection = mTcpServer.nextPendingConnection();
@ -7403,6 +7437,13 @@ void MainWindow::on_btnProblemCaseInputFileName_clicked()
if (problemCase->inputFileName == fileName)
return;
problemCase->inputFileName = fileName;
if (problemCase->expectedOutputFileName.isEmpty()
&& problemCase->expected.isEmpty()
&& QFileInfo(fileName).suffix()=="in") {
QString expectedFileName = fileName.mid(0,fileName.length()-2)+"out";
if (fileExists(expectedFileName))
problemCase->expectedOutputFileName = expectedFileName;
}
fillProblemCaseInputAndExpected(problemCase);
}
}

View File

@ -276,11 +276,13 @@ private slots:
void onFileEncodingContextMenu(const QPoint& pos);
void onFilesViewContextMenu(const QPoint& pos);
void onLstProblemSetContextMenu(const QPoint& pos);
void onTableProblemCasesContextMenu(const QPoint& pos);
void onToolsOutputContextMenu(const QPoint&pos);
void onProblemSetIndexChanged(const QModelIndex &current, const QModelIndex &previous);
void onProblemCaseIndexChanged(const QModelIndex &current, const QModelIndex &previous);
void onProblemNameChanged(int index);
void onRroblemRunCurrentCase();
void onNewProblemConnection();
void updateProblemTitle();
void onEditorClosed();
@ -784,6 +786,10 @@ private:
QAction * mProblem_OpenSource;
QAction * mProblem_Properties;
//action for problem
QAction * mProblem_RunCurrentCase;
QAction * mProblem_RunAllCases;
//action for tools output
QAction * mToolsOutput_Clear;
QAction * mToolsOutput_SelectAll;

View File

@ -3335,7 +3335,7 @@ void Settings::Executor::doLoad()
#endif
mCaseEditorFontSize = intValue("case_editor_font_size",12);
mCaseEditorFontOnlyMonospaced = boolValue("case_editor_font_only_monospaced",true);
mCaseTimeout = intValue("case_timeout", 3);
mCaseTimeout = intValue("case_timeout", 2);
mEnableCaseTimeout = boolValue("enable_case_timeout", true);
}

View File

@ -54,7 +54,7 @@ void ExecutorProblemSetWidget::doSave()
pSettings->executor().setCaseEditorFontName(ui->cbFont->currentFont().family());
pSettings->executor().setCaseEditorFontOnlyMonospaced(ui->chkOnlyMonospaced->isChecked());
pSettings->executor().setCaseEditorFontSize(ui->spinFontSize->value());
pSettings->executor().setEnableCaseTimeout(ui->grpEnableTimeout->isEnabled());
pSettings->executor().setEnableCaseTimeout(ui->grpEnableTimeout->isChecked());
pSettings->executor().setCaseTimeout(ui->spinCaseTimeout->value());
pSettings->executor().save();
pMainWindow->applySettings();