- enhancement: Problem Set Support
- enhancement: Competitive Companion Support
This commit is contained in:
parent
f28aac649b
commit
47f10a2105
2
NEWS.md
2
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: 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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
|
||||||
if (process.state()!=QProcess::Running) {
|
if (process.state()!=QProcess::Running) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (mStop) {
|
if (mStop) {
|
||||||
process.closeReadChannel(QProcess::StandardOutput);
|
process.closeReadChannel(QProcess::StandardOutput);
|
||||||
process.closeReadChannel(QProcess::StandardError);
|
process.closeReadChannel(QProcess::StandardError);
|
||||||
process.closeWriteChannel();
|
process.closeWriteChannel();
|
||||||
|
@ -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()) {
|
||||||
|
|
|
@ -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 ¤t, 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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 ¤t, const QModelIndex &previous);
|
void onProblemSetIndexChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||||
void onProblemCaseIndexChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
void onProblemCaseIndexChanged(const QModelIndex ¤t, 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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 "";
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><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></string>
|
<string><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></string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue