- enhancement: Problem Set Support

- enhancement: Competitive Companion Support
This commit is contained in:
royqh1979@gmail.com 2021-11-02 09:29:35 +08:00
parent f28aac649b
commit 47f10a2105
13 changed files with 112 additions and 10 deletions

View File

@ -4,6 +4,8 @@ Version 0.7.7
- fix: can't parse old c-style enum variable definition like "enum Test test;" - 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: 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). - 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 Version 0.7.6
- change: don't auto insert a new line when input an enter between '(' and ')' or between '[' and ']' (indent instead) - change: don't auto insert a new line when input an enter between '(' and ')' or between '[' and ']' (indent instead)

View File

@ -1,4 +1,4 @@
QT += core gui printsupport QT += core gui printsupport network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

View File

@ -77,6 +77,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
if (errorOccurred) if (errorOccurred)
break; break;
} }
readed += process.readAll();
if (errorOccurred) { if (errorOccurred) {
//qDebug()<<"process error:"<<process.error(); //qDebug()<<"process error:"<<process.error();
switch (process.error()) { switch (process.error()) {

View File

@ -26,10 +26,14 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QFileDialog> #include <QFileDialog>
#include <QInputDialog> #include <QInputDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QMessageBox> #include <QMessageBox>
#include <QMimeData> #include <QMimeData>
#include <QTcpSocket>
#include <QTranslator> #include <QTranslator>
#include "settingsdialog/settingsdialog.h" #include "settingsdialog/settingsdialog.h"
@ -209,6 +213,7 @@ MainWindow::MainWindow(QWidget *parent)
ui->btnRemoveProblem->setEnabled(false); ui->btnRemoveProblem->setEnabled(false);
ui->btnRemoveProblemCase->setEnabled(false); ui->btnRemoveProblemCase->setEnabled(false);
//problem set
mOJProblemSetNameCounter=1; mOJProblemSetNameCounter=1;
mOJProblemSetModel.rename(tr("Problem Set %1").arg(mOJProblemSetNameCounter)); mOJProblemSetModel.rename(tr("Problem Set %1").arg(mOJProblemSetNameCounter));
ui->lstProblemSet->setModel(&mOJProblemSetModel); ui->lstProblemSet->setModel(&mOJProblemSetModel);
@ -222,6 +227,8 @@ MainWindow::MainWindow(QWidget *parent)
connect(&mOJProblemSetModel, &OJProblemSetModel::problemNameChanged, connect(&mOJProblemSetModel, &OJProblemSetModel::problemNameChanged,
this , &MainWindow::onProblemNameChanged); this , &MainWindow::onProblemNameChanged);
ui->pbProblemCases->setVisible(false); ui->pbProblemCases->setVisible(false);
connect(&mTcpServer,&QTcpServer::newConnection,
this, &MainWindow::onNewProblemConnection);
//files view //files view
ui->treeFiles->setModel(&mFileSystemModel); ui->treeFiles->setModel(&mFileSystemModel);
@ -528,6 +535,12 @@ void MainWindow::applySettings()
font.setStyleStrategy(QFont::PreferAntialias); font.setStyleStrategy(QFont::PreferAntialias);
qApp->setFont(font); qApp->setFont(font);
this->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(); updateDebuggerSettings();
} }
@ -2535,11 +2548,12 @@ void MainWindow::onProblemSetIndexChanged(const QModelIndex &current, const QMod
ui->txtProblemCaseInput->clear(); ui->txtProblemCaseInput->clear();
ui->txtProblemCaseOutput->clear(); ui->txtProblemCaseOutput->clear();
ui->tabProblem->setEnabled(false); ui->tabProblem->setEnabled(false);
ui->lblProblem->clear();
} else { } else {
ui->btnRemoveProblem->setEnabled(true); ui->btnRemoveProblem->setEnabled(true);
POJProblem problem = mOJProblemSetModel.problem(idx.row()); POJProblem problem = mOJProblemSetModel.problem(idx.row());
mOJProblemModel.setProblem(problem); mOJProblemModel.setProblem(problem);
ui->lblProblem->setText(problem->name); ui->lblProblem->setText(mOJProblemModel.getTitle());
ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(0,0)); ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(0,0));
openCloseBottomPanel(true); openCloseBottomPanel(true);
ui->tabMessages->setCurrentWidget(ui->tabProblem); ui->tabMessages->setCurrentWidget(ui->tabProblem);
@ -2582,10 +2596,53 @@ void MainWindow::onProblemNameChanged(int index)
QModelIndex idx = ui->lstProblemSet->currentIndex(); QModelIndex idx = ui->lstProblemSet->currentIndex();
if (idx.isValid() && index == idx.row()) { if (idx.isValid() && index == idx.row()) {
POJProblem problem = mOJProblemSetModel.problem(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()<<error.errorString();
return;
}
QJsonObject obj=doc.object();
QString name = obj["name"].toString();
if (!mOJProblemSetModel.problemNameUsed(name)) {
POJProblem problem = std::make_shared<OJProblem>();
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<OJProblemCase>();
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() void MainWindow::onShowInsertCodeSnippetMenu()
{ {
mMenuInsertCodeSnippet->clear(); mMenuInsertCodeSnippet->clear();
@ -3386,6 +3443,7 @@ void MainWindow::onOJProblemCaseFinished(const QString &id, int current, int tot
} }
ui->pbProblemCases->setMaximum(total); ui->pbProblemCases->setMaximum(total);
ui->pbProblemCases->setValue(current); ui->pbProblemCases->setValue(current);
ui->lblProblem->setText(mOJProblemModel.getTitle());
} }
void MainWindow::cleanUpCPUDialog() void MainWindow::cleanUpCPUDialog()
@ -4973,8 +5031,9 @@ void MainWindow::on_btnNewProblemSet_clicked()
tr("The current problem set is not empty.") tr("The current problem set is not empty.")
+"<br />" +"<br />"
+tr("Do you want to save it?"), +tr("Do you want to save it?"),
QMessageBox::Yes | QMessageBox::No)!=QMessageBox::Yes) QMessageBox::Yes | QMessageBox::No)==QMessageBox::Yes) {
return; on_btnSaveProblemSet_clicked();
}
} }
mOJProblemSetNameCounter++; mOJProblemSetNameCounter++;
mOJProblemSetModel.create(tr("Problem Set %1").arg(mOJProblemSetNameCounter)); mOJProblemSetModel.create(tr("Problem Set %1").arg(mOJProblemSetNameCounter));
@ -5056,7 +5115,7 @@ void MainWindow::on_btnAddProblemCase_clicked()
} }
POJProblemCase problemCase = std::make_shared<OJProblemCase>(); POJProblemCase problemCase = std::make_shared<OJProblemCase>();
problemCase->name = name; problemCase->name = name;
problemCase->testState = ProblemCaseTestState::NoTested; problemCase->testState = ProblemCaseTestState::NotTested;
mOJProblemModel.addCase(problemCase); mOJProblemModel.addCase(problemCase);
ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(mOJProblemModel.count()-1)); ui->lstProblemCases->setCurrentIndex(mOJProblemModel.index(mOJProblemModel.count()-1));
} }

View File

@ -5,6 +5,7 @@
#include <QMainWindow> #include <QMainWindow>
#include <QTimer> #include <QTimer>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QTcpServer>
#include "common.h" #include "common.h"
#include "widgets/searchresultview.h" #include "widgets/searchresultview.h"
#include "widgets/classbrowser.h" #include "widgets/classbrowser.h"
@ -227,6 +228,7 @@ private slots:
void onProblemSetIndexChanged(const QModelIndex &current, const QModelIndex &previous); void onProblemSetIndexChanged(const QModelIndex &current, const QModelIndex &previous);
void onProblemCaseIndexChanged(const QModelIndex &current, const QModelIndex &previous); void onProblemCaseIndexChanged(const QModelIndex &current, const QModelIndex &previous);
void onProblemNameChanged(int index); void onProblemNameChanged(int index);
void onNewProblemConnection();
void onShowInsertCodeSnippetMenu(); void onShowInsertCodeSnippetMenu();
@ -524,6 +526,7 @@ private:
bool mClosing; bool mClosing;
bool mSystemTurnedOff; bool mSystemTurnedOff;
QPoint mEditorContextMenuPos; QPoint mEditorContextMenuPos;
QTcpServer mTcpServer;
//actions for compile issue table //actions for compile issue table
QAction * mTableIssuesCopyAction; QAction * mTableIssuesCopyAction;

View File

@ -1129,6 +1129,9 @@
<property name="text"> <property name="text">
<string>Problem</string> <string>Problem</string>
</property> </property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -5,7 +5,7 @@
#include <QVector> #include <QVector>
enum class ProblemCaseTestState { enum class ProblemCaseTestState {
NoTested, NotTested,
Testing, Testing,
Passed, Passed,
Failed Failed
@ -30,6 +30,7 @@ using POJProblemCase = std::shared_ptr<OJProblemCase>;
struct OJProblem { struct OJProblem {
QString name; QString name;
QString url;
QVector<POJProblemCase> cases; QVector<POJProblemCase> cases;
}; };

View File

@ -3,7 +3,7 @@
#include <QStringList> #include <QStringList>
#define DEVCPP_VERSION "0.7.6" #define DEVCPP_VERSION "0.7.7"
#define APP_SETTSINGS_FILENAME "redpandacpp.ini" #define APP_SETTSINGS_FILENAME "redpandacpp.ini"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN

View File

@ -844,3 +844,11 @@ QByteArray ReadFileToByteArray(const QString &fileName)
} }
return QByteArray(); return QByteArray();
} }
QByteArray getHTTPBody(const QByteArray& content) {
int i= content.indexOf("\r\n\r\n");
if (i>=0) {
return content.mid(i+4);
}
return "";
}

View File

@ -166,6 +166,7 @@ QString TrimRight(const QString& s);
QString TrimLeft(const QString& s); QString TrimLeft(const QString& s);
bool StringIsBlank(const QString& s); bool StringIsBlank(const QString& s);
int compareFileModifiedTime(const QString& filename1, const QString& filename2); int compareFileModifiedTime(const QString& filename1, const QString& filename2);
QByteArray getHTTPBody(const QByteArray& content);
//void changeTheme(const QString& themeName); //void changeTheme(const QString& themeName);

View File

@ -35,6 +35,9 @@
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Based on Qt %1 (%2)&lt;/p&gt;&lt;p&gt;Build time: %3 %4&lt;/p&gt;&lt;p&gt;Copyright 2020-2021 royqh1979@gmail.com&lt;/p&gt;&lt;p&gt;Homepage: &lt;a href=&quot;https://sourceforge.net/projects/dev-cpp-2020/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;https://sourceforge.net/projects/dev-cpp-2020/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Based on Qt %1 (%2)&lt;/p&gt;&lt;p&gt;Build time: %3 %4&lt;/p&gt;&lt;p&gt;Copyright 2020-2021 royqh1979@gmail.com&lt;/p&gt;&lt;p&gt;Homepage: &lt;a href=&quot;https://sourceforge.net/projects/dev-cpp-2020/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;https://sourceforge.net/projects/dev-cpp-2020/&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -86,6 +86,7 @@ void OJProblemSetModel::saveToFile(const QString &fileName)
foreach (const POJProblem& problem, mProblemSet.problems) { foreach (const POJProblem& problem, mProblemSet.problems) {
QJsonObject problemObj; QJsonObject problemObj;
problemObj["name"]=problem->name; problemObj["name"]=problem->name;
problemObj["url"]=problem->url;
QJsonArray cases; QJsonArray cases;
foreach (const POJProblemCase& problemCase, problem->cases) { foreach (const POJProblemCase& problemCase, problem->cases) {
QJsonObject caseObj; QJsonObject caseObj;
@ -129,6 +130,7 @@ void OJProblemSetModel::loadFromFile(const QString &fileName)
QJsonObject problemObj = problemVal.toObject(); QJsonObject problemObj = problemVal.toObject();
POJProblem problem = std::make_shared<OJProblem>(); POJProblem problem = std::make_shared<OJProblem>();
problem->name = problemObj["name"].toString(); problem->name = problemObj["name"].toString();
problem->url = problemObj["url"].toString();
QJsonArray casesArray = problemObj["cases"].toArray(); QJsonArray casesArray = problemObj["cases"].toArray();
foreach (const QJsonValue& caseVal, casesArray) { foreach (const QJsonValue& caseVal, casesArray) {
QJsonObject caseObj = caseVal.toObject(); QJsonObject caseObj = caseVal.toObject();
@ -136,7 +138,7 @@ void OJProblemSetModel::loadFromFile(const QString &fileName)
problemCase->name = caseObj["name"].toString(); problemCase->name = caseObj["name"].toString();
problemCase->input = caseObj["input"].toString(); problemCase->input = caseObj["input"].toString();
problemCase->expected = caseObj["expected"].toString(); problemCase->expected = caseObj["expected"].toString();
problemCase->testState = ProblemCaseTestState::NoTested; problemCase->testState = ProblemCaseTestState::NotTested;
problem->cases.append(problemCase); problem->cases.append(problemCase);
} }
mProblemSet.problems.append(problem); mProblemSet.problems.append(problem);
@ -272,6 +274,24 @@ void OJProblemModel::update(int row)
emit dataChanged(index(row,0),index(row,0)); 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("<a href=\"%1\">%2</a>").arg(mProblem->url,title);
}
return title;
}
int OJProblemModel::rowCount(const QModelIndex &) const int OJProblemModel::rowCount(const QModelIndex &) const
{ {
if (mProblem==nullptr) if (mProblem==nullptr)

View File

@ -19,6 +19,7 @@ public:
void clear(); void clear();
int count(); int count();
void update(int row); void update(int row);
QString getTitle();
private: private:
POJProblem mProblem; POJProblem mProblem;