From 7bc5a2ee7aee8aa85c2d58e687103dc0b07957a6 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Wed, 30 Mar 2022 19:28:46 +0800 Subject: [PATCH] - fix: can't stop a freeze program that has stdin redirected. - enhancement: context menu for problem cases table --- NEWS.md | 2 + RedPandaIDE/compiler/executablerunner.cpp | 10 ++--- RedPandaIDE/compiler/ojproblemcasesrunner.cpp | 33 +++++++-------- RedPandaIDE/compiler/ojproblemcasesrunner.h | 3 -- RedPandaIDE/debugger.cpp | 14 +++++++ RedPandaIDE/debugger.h | 2 + RedPandaIDE/mainwindow.cpp | 41 +++++++++++++++++++ RedPandaIDE/mainwindow.h | 6 +++ RedPandaIDE/settings.cpp | 2 +- .../executorproblemsetwidget.cpp | 2 +- 10 files changed, 86 insertions(+), 29 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2cd017a4..124b8f39 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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" diff --git a/RedPandaIDE/compiler/executablerunner.cpp b/RedPandaIDE/compiler/executablerunner.cpp index 8a48a018..77e2843e 100644 --- a/RedPandaIDE/compiler/executablerunner.cpp +++ b/RedPandaIDE/compiler/executablerunner.cpp @@ -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) { diff --git a/RedPandaIDE/compiler/ojproblemcasesrunner.cpp b/RedPandaIDE/compiler/ojproblemcasesrunner.cpp index ed0f91a9..22618642 100644 --- a/RedPandaIDE/compiler/ojproblemcasesrunner.cpp +++ b/RedPandaIDE/compiler/ojproblemcasesrunner.cpp @@ -25,8 +25,7 @@ OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir, const QVector& 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:"<output = QString::fromLocal8Bit(output); } } @@ -180,11 +180,6 @@ void OJProblemCasesRunner::run() } } -bool OJProblemCasesRunner::execTimeouted() const -{ - return mExecTimeouted; -} - int OJProblemCasesRunner::execTimeout() const { return mExecTimeout; diff --git a/RedPandaIDE/compiler/ojproblemcasesrunner.h b/RedPandaIDE/compiler/ojproblemcasesrunner.h index 5acd4290..e85cdcf8 100644 --- a/RedPandaIDE/compiler/ojproblemcasesrunner.h +++ b/RedPandaIDE/compiler/ojproblemcasesrunner.h @@ -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 diff --git a/RedPandaIDE/debugger.cpp b/RedPandaIDE/debugger.cpp index 791d36e0..f5e367fe 100644 --- a/RedPandaIDE/debugger.cpp +++ b/RedPandaIDE/debugger.cpp @@ -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 QListhasMore) { + QModelIndex idx = index(var); + fetchMore(idx); + } + } +} + void WatchModel::clearAllVarInfos() { beginResetModel(); diff --git a/RedPandaIDE/debugger.h b/RedPandaIDE/debugger.h index 59f38c53..0938f050 100644 --- a/RedPandaIDE/debugger.h +++ b/RedPandaIDE/debugger.h @@ -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(); diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 33aaf8a2..ef9c0cb0 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -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); } } diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 79b49ed3..fe75e0af 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -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 ¤t, const QModelIndex &previous); void onProblemCaseIndexChanged(const QModelIndex ¤t, 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; diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 8ee7cd13..55216b12 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -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); } diff --git a/RedPandaIDE/settingsdialog/executorproblemsetwidget.cpp b/RedPandaIDE/settingsdialog/executorproblemsetwidget.cpp index 7c86cf66..c0182a94 100644 --- a/RedPandaIDE/settingsdialog/executorproblemsetwidget.cpp +++ b/RedPandaIDE/settingsdialog/executorproblemsetwidget.cpp @@ -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();