- fix: can't stop a freeze program that has stdin redirected.
- enhancement: context menu for problem cases table
This commit is contained in:
parent
1d845cc843
commit
7bc5a2ee7a
2
NEWS.md
2
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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue