From 47f10a2105b9b0519dbbf1fba70089403e934c2a Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Tue, 2 Nov 2021 09:29:35 +0800 Subject: [PATCH] - enhancement: Problem Set Support - enhancement: Competitive Companion Support --- NEWS.md | 2 + RedPandaIDE/RedPandaIDE.pro | 2 +- RedPandaIDE/compiler/ojproblemcasesrunner.cpp | 3 +- RedPandaIDE/mainwindow.cpp | 69 +++++++++++++++++-- RedPandaIDE/mainwindow.h | 3 + RedPandaIDE/mainwindow.ui | 3 + RedPandaIDE/problems/ojproblemset.h | 3 +- RedPandaIDE/systemconsts.h | 2 +- RedPandaIDE/utils.cpp | 8 +++ RedPandaIDE/utils.h | 1 + RedPandaIDE/widgets/aboutdialog.ui | 3 + RedPandaIDE/widgets/ojproblemsetmodel.cpp | 22 +++++- RedPandaIDE/widgets/ojproblemsetmodel.h | 1 + 13 files changed, 112 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index 65caeec6..cc186b5d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,8 @@ Version 0.7.7 - fix: can't parse old c-style enum variable definition like "enum Test test;" - fix: remove the file change monitor if it's remove from the disk - fix: don't test if a file is writable before save to it (because qt can't do that test reliably). + - enhancement: Problem Set + - enhancement: Competitive Companion Support Version 0.7.6 - change: don't auto insert a new line when input an enter between '(' and ')' or between '[' and ']' (indent instead) diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 4edce9a7..a2c900e0 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -1,4 +1,4 @@ -QT += core gui printsupport +QT += core gui printsupport network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets diff --git a/RedPandaIDE/compiler/ojproblemcasesrunner.cpp b/RedPandaIDE/compiler/ojproblemcasesrunner.cpp index e1def83b..1b8bf943 100644 --- a/RedPandaIDE/compiler/ojproblemcasesrunner.cpp +++ b/RedPandaIDE/compiler/ojproblemcasesrunner.cpp @@ -66,7 +66,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase) if (process.state()!=QProcess::Running) { break; } - if (mStop) { + if (mStop) { process.closeReadChannel(QProcess::StandardOutput); process.closeReadChannel(QProcess::StandardError); process.closeWriteChannel(); @@ -77,6 +77,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase) if (errorOccurred) break; } + readed += process.readAll(); if (errorOccurred) { //qDebug()<<"process error:"< #include #include +#include +#include +#include #include #include #include #include +#include #include #include "settingsdialog/settingsdialog.h" @@ -209,6 +213,7 @@ MainWindow::MainWindow(QWidget *parent) ui->btnRemoveProblem->setEnabled(false); ui->btnRemoveProblemCase->setEnabled(false); + //problem set mOJProblemSetNameCounter=1; mOJProblemSetModel.rename(tr("Problem Set %1").arg(mOJProblemSetNameCounter)); ui->lstProblemSet->setModel(&mOJProblemSetModel); @@ -222,6 +227,8 @@ MainWindow::MainWindow(QWidget *parent) connect(&mOJProblemSetModel, &OJProblemSetModel::problemNameChanged, this , &MainWindow::onProblemNameChanged); ui->pbProblemCases->setVisible(false); + connect(&mTcpServer,&QTcpServer::newConnection, + this, &MainWindow::onNewProblemConnection); //files view ui->treeFiles->setModel(&mFileSystemModel); @@ -528,6 +535,12 @@ void MainWindow::applySettings() font.setStyleStrategy(QFont::PreferAntialias); qApp->setFont(font); this->setFont(font); + + if (!mTcpServer.listen(QHostAddress::LocalHost,10045)) { + QMessageBox::critical(nullptr, + tr("Listen failed"), + tr("Can't listen to port %1").arg(10045)); + } updateDebuggerSettings(); } @@ -2535,11 +2548,12 @@ void MainWindow::onProblemSetIndexChanged(const QModelIndex ¤t, const QMod ui->txtProblemCaseInput->clear(); ui->txtProblemCaseOutput->clear(); ui->tabProblem->setEnabled(false); + ui->lblProblem->clear(); } else { ui->btnRemoveProblem->setEnabled(true); POJProblem problem = mOJProblemSetModel.problem(idx.row()); mOJProblemModel.setProblem(problem); - ui->lblProblem->setText(problem->name); + ui->lblProblem->setText(mOJProblemModel.getTitle()); ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(0,0)); openCloseBottomPanel(true); ui->tabMessages->setCurrentWidget(ui->tabProblem); @@ -2582,10 +2596,53 @@ void MainWindow::onProblemNameChanged(int index) QModelIndex idx = ui->lstProblemSet->currentIndex(); if (idx.isValid() && index == idx.row()) { POJProblem problem = mOJProblemSetModel.problem(idx.row()); - ui->lblProblem->setText(problem->name); + ui->lblProblem->setText(mOJProblemModel.getTitle()); } } +void MainWindow::onNewProblemConnection() +{ + QTcpSocket* clientConnection = mTcpServer.nextPendingConnection(); + mTcpServer.connect(clientConnection, &QAbstractSocket::disconnected, + clientConnection, &QObject::deleteLater); + QByteArray content; + while (clientConnection->state() == QTcpSocket::ConnectedState) { + clientConnection->waitForReadyRead(); + content += clientConnection->readAll(); + } + content += clientConnection->readAll(); + content = getHTTPBody(content); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(content,&error); + if (error.error!=QJsonParseError::NoError) { + qDebug()<<"Read http content failed!"; + qDebug()<(); + problem->name = name; + problem->url = obj["url"].toString(); + QJsonArray caseArray = obj["tests"].toArray(); + foreach ( const QJsonValue& val, caseArray) { + QJsonObject caseObj = val.toObject(); + POJProblemCase problemCase = std::make_shared(); + problemCase->testState = ProblemCaseTestState::NotTested; + problemCase->name = tr("Problem Case %1").arg(problem->cases.count()+1); + problemCase->input = caseObj["input"].toString(); + problemCase->expected = caseObj["output"].toString(); + problem->cases.append(problemCase); + } + mOJProblemSetModel.addProblem(problem); + if (!ui->lstProblemSet->currentIndex().isValid()) { + ui->lstProblemSet->setCurrentIndex(mOJProblemSetModel.index(0,0)); + } + } + clientConnection->disconnectFromHost(); +} + void MainWindow::onShowInsertCodeSnippetMenu() { mMenuInsertCodeSnippet->clear(); @@ -3386,6 +3443,7 @@ void MainWindow::onOJProblemCaseFinished(const QString &id, int current, int tot } ui->pbProblemCases->setMaximum(total); ui->pbProblemCases->setValue(current); + ui->lblProblem->setText(mOJProblemModel.getTitle()); } void MainWindow::cleanUpCPUDialog() @@ -4973,8 +5031,9 @@ void MainWindow::on_btnNewProblemSet_clicked() tr("The current problem set is not empty.") +"
" +tr("Do you want to save it?"), - QMessageBox::Yes | QMessageBox::No)!=QMessageBox::Yes) - return; + QMessageBox::Yes | QMessageBox::No)==QMessageBox::Yes) { + on_btnSaveProblemSet_clicked(); + } } mOJProblemSetNameCounter++; mOJProblemSetModel.create(tr("Problem Set %1").arg(mOJProblemSetNameCounter)); @@ -5056,7 +5115,7 @@ void MainWindow::on_btnAddProblemCase_clicked() } POJProblemCase problemCase = std::make_shared(); problemCase->name = name; - problemCase->testState = ProblemCaseTestState::NoTested; + problemCase->testState = ProblemCaseTestState::NotTested; mOJProblemModel.addCase(problemCase); ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(mOJProblemModel.count()-1)); } diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 1011a66b..fbd33db9 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "common.h" #include "widgets/searchresultview.h" #include "widgets/classbrowser.h" @@ -227,6 +228,7 @@ private slots: void onProblemSetIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); void onProblemCaseIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); void onProblemNameChanged(int index); + void onNewProblemConnection(); void onShowInsertCodeSnippetMenu(); @@ -524,6 +526,7 @@ private: bool mClosing; bool mSystemTurnedOff; QPoint mEditorContextMenuPos; + QTcpServer mTcpServer; //actions for compile issue table QAction * mTableIssuesCopyAction; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 7081fa95..cd4fc232 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -1129,6 +1129,9 @@ Problem + + true + diff --git a/RedPandaIDE/problems/ojproblemset.h b/RedPandaIDE/problems/ojproblemset.h index e3e1e225..74040b07 100644 --- a/RedPandaIDE/problems/ojproblemset.h +++ b/RedPandaIDE/problems/ojproblemset.h @@ -5,7 +5,7 @@ #include enum class ProblemCaseTestState { - NoTested, + NotTested, Testing, Passed, Failed @@ -30,6 +30,7 @@ using POJProblemCase = std::shared_ptr; struct OJProblem { QString name; + QString url; QVector cases; }; diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 74193188..d448e9e0 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -3,7 +3,7 @@ #include -#define DEVCPP_VERSION "0.7.6" +#define DEVCPP_VERSION "0.7.7" #define APP_SETTSINGS_FILENAME "redpandacpp.ini" #ifdef Q_OS_WIN diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index d245221c..e01413a9 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -844,3 +844,11 @@ QByteArray ReadFileToByteArray(const QString &fileName) } return QByteArray(); } + +QByteArray getHTTPBody(const QByteArray& content) { + int i= content.indexOf("\r\n\r\n"); + if (i>=0) { + return content.mid(i+4); + } + return ""; +} diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index ffef72e9..d6eb0df5 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -166,6 +166,7 @@ QString TrimRight(const QString& s); QString TrimLeft(const QString& s); bool StringIsBlank(const QString& s); int compareFileModifiedTime(const QString& filename1, const QString& filename2); +QByteArray getHTTPBody(const QByteArray& content); //void changeTheme(const QString& themeName); diff --git a/RedPandaIDE/widgets/aboutdialog.ui b/RedPandaIDE/widgets/aboutdialog.ui index 6f097bd5..8722dbbb 100644 --- a/RedPandaIDE/widgets/aboutdialog.ui +++ b/RedPandaIDE/widgets/aboutdialog.ui @@ -35,6 +35,9 @@ <html><head/><body><p>Based on Qt %1 (%2)</p><p>Build time: %3 %4</p><p>Copyright 2020-2021 royqh1979@gmail.com</p><p>Homepage: <a href="https://sourceforge.net/projects/dev-cpp-2020/"><span style=" text-decoration: underline; color:#007af4;">https://sourceforge.net/projects/dev-cpp-2020/</span></a></p></body></html> + + true + diff --git a/RedPandaIDE/widgets/ojproblemsetmodel.cpp b/RedPandaIDE/widgets/ojproblemsetmodel.cpp index b7d9a3ec..32abf18e 100644 --- a/RedPandaIDE/widgets/ojproblemsetmodel.cpp +++ b/RedPandaIDE/widgets/ojproblemsetmodel.cpp @@ -86,6 +86,7 @@ void OJProblemSetModel::saveToFile(const QString &fileName) foreach (const POJProblem& problem, mProblemSet.problems) { QJsonObject problemObj; problemObj["name"]=problem->name; + problemObj["url"]=problem->url; QJsonArray cases; foreach (const POJProblemCase& problemCase, problem->cases) { QJsonObject caseObj; @@ -129,6 +130,7 @@ void OJProblemSetModel::loadFromFile(const QString &fileName) QJsonObject problemObj = problemVal.toObject(); POJProblem problem = std::make_shared(); problem->name = problemObj["name"].toString(); + problem->url = problemObj["url"].toString(); QJsonArray casesArray = problemObj["cases"].toArray(); foreach (const QJsonValue& caseVal, casesArray) { QJsonObject caseObj = caseVal.toObject(); @@ -136,7 +138,7 @@ void OJProblemSetModel::loadFromFile(const QString &fileName) problemCase->name = caseObj["name"].toString(); problemCase->input = caseObj["input"].toString(); problemCase->expected = caseObj["expected"].toString(); - problemCase->testState = ProblemCaseTestState::NoTested; + problemCase->testState = ProblemCaseTestState::NotTested; problem->cases.append(problemCase); } mProblemSet.problems.append(problem); @@ -272,6 +274,24 @@ void OJProblemModel::update(int row) emit dataChanged(index(row,0),index(row,0)); } +QString OJProblemModel::getTitle() +{ + if (!mProblem) + return ""; + int total = mProblem->cases.count(); + int passed = 0; + foreach (const POJProblemCase& problemCase, mProblem->cases) { + if (problemCase->testState == ProblemCaseTestState::Passed) + passed ++ ; + } + QString title = QString("%1 (%2/%3)").arg(mProblem->name) + .arg(passed).arg(total); + if (!mProblem->url.isEmpty()) { + title = QString("%2").arg(mProblem->url,title); + } + return title; +} + int OJProblemModel::rowCount(const QModelIndex &) const { if (mProblem==nullptr) diff --git a/RedPandaIDE/widgets/ojproblemsetmodel.h b/RedPandaIDE/widgets/ojproblemsetmodel.h index d1edf0c7..fd2f7c83 100644 --- a/RedPandaIDE/widgets/ojproblemsetmodel.h +++ b/RedPandaIDE/widgets/ojproblemsetmodel.h @@ -19,6 +19,7 @@ public: void clear(); int count(); void update(int row); + QString getTitle(); private: POJProblem mProblem;