work save: oj problem cases runner
This commit is contained in:
parent
46b95c03ae
commit
9f4e8344a3
|
@ -20,7 +20,9 @@ SOURCES += \
|
|||
codeformatter.cpp \
|
||||
codesnippetsmanager.cpp \
|
||||
colorscheme.cpp \
|
||||
compiler/ojproblemcasesrunner.cpp \
|
||||
compiler/projectcompiler.cpp \
|
||||
compiler/runner.cpp \
|
||||
platform.cpp \
|
||||
compiler/compiler.cpp \
|
||||
compiler/compilermanager.cpp \
|
||||
|
@ -140,7 +142,9 @@ HEADERS += \
|
|||
compiler/compilermanager.h \
|
||||
compiler/executablerunner.h \
|
||||
compiler/filecompiler.h \
|
||||
compiler/ojproblemcasesrunner.h \
|
||||
compiler/projectcompiler.h \
|
||||
compiler/runner.h \
|
||||
compiler/stdincompiler.h \
|
||||
cpprefacter.h \
|
||||
parser/cppparser.h \
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "stdincompiler.h"
|
||||
#include "../mainwindow.h"
|
||||
#include "executablerunner.h"
|
||||
#include "ojproblemcasesrunner.h"
|
||||
#include "utils.h"
|
||||
#include "../settings.h"
|
||||
#include <QMessageBox>
|
||||
|
@ -208,6 +209,7 @@ void CompilerManager::run(const QString &filename, const QString &arguments, con
|
|||
redirectInput =true;
|
||||
redirectInputFilename = pSettings->executor().inputFilename();
|
||||
}
|
||||
ExecutableRunner * execRunner;
|
||||
if (programHasConsole(filename)) {
|
||||
int consoleFlag=0;
|
||||
if (redirectInput)
|
||||
|
@ -217,18 +219,49 @@ void CompilerManager::run(const QString &filename, const QString &arguments, con
|
|||
QString newArguments = QString(" %1 \"%2\" %3")
|
||||
.arg(consoleFlag)
|
||||
.arg(toLocalPath(filename)).arg(arguments);
|
||||
mRunner = new ExecutableRunner(includeTrailingPathDelimiter(pSettings->dirs().app())+"ConsolePauser.exe",newArguments,workDir);
|
||||
mRunner->setStartConsole(true);
|
||||
execRunner = new ExecutableRunner(includeTrailingPathDelimiter(pSettings->dirs().app())+"ConsolePauser.exe",newArguments,workDir);
|
||||
execRunner->setStartConsole(true);
|
||||
} else {
|
||||
mRunner = new ExecutableRunner(filename,arguments,workDir);
|
||||
execRunner = new ExecutableRunner(filename,arguments,workDir);
|
||||
}
|
||||
if (redirectInput) {
|
||||
mRunner->setRedirectInput(true);
|
||||
mRunner->setRedirectInputFilename(redirectInputFilename);
|
||||
execRunner->setRedirectInput(true);
|
||||
execRunner->setRedirectInputFilename(redirectInputFilename);
|
||||
}
|
||||
connect(mRunner, &ExecutableRunner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
connect(mRunner, &ExecutableRunner::finished, pMainWindow ,&MainWindow::onRunFinished);
|
||||
connect(mRunner, &ExecutableRunner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
|
||||
mRunner = execRunner;
|
||||
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
|
||||
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
|
||||
mRunner->start();
|
||||
}
|
||||
|
||||
void CompilerManager::runProblem(const QString &filename, const QString &arguments, const QString &workDir, POJProblemCase problemCase)
|
||||
{
|
||||
QMutexLocker locker(&mRunnerMutex);
|
||||
if (mRunner!=nullptr) {
|
||||
return;
|
||||
}
|
||||
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCase);
|
||||
mRunner = execRunner;
|
||||
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
|
||||
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
|
||||
// connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted);
|
||||
mRunner->start();
|
||||
}
|
||||
|
||||
void CompilerManager::runProblem(const QString &filename, const QString &arguments, const QString &workDir, QVector<POJProblemCase> problemCases)
|
||||
{
|
||||
QMutexLocker locker(&mRunnerMutex);
|
||||
if (mRunner!=nullptr) {
|
||||
return;
|
||||
}
|
||||
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCases);
|
||||
mRunner = execRunner;
|
||||
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
|
||||
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
|
||||
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
|
||||
// connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted);
|
||||
mRunner->start();
|
||||
}
|
||||
|
||||
|
@ -268,7 +301,7 @@ void CompilerManager::onCompileFinished()
|
|||
void CompilerManager::onRunnerTerminated()
|
||||
{
|
||||
QMutexLocker locker(&mRunnerMutex);
|
||||
ExecutableRunner* p=mRunner;
|
||||
Runner* p=mRunner;
|
||||
mRunner=nullptr;
|
||||
p->deleteLater();
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
#include "../utils.h"
|
||||
#include "../common.h"
|
||||
|
||||
class ExecutableRunner;
|
||||
class Runner;
|
||||
class Compiler;
|
||||
class Project;
|
||||
class OJProblemCase;
|
||||
using POJProblemCase = std::shared_ptr<OJProblemCase>;
|
||||
class CompilerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -25,6 +27,8 @@ public:
|
|||
void buildProjectMakefile(std::shared_ptr<Project> project);
|
||||
void checkSyntax(const QString&filename, const QString& content, bool isAscii, std::shared_ptr<Project> project);
|
||||
void run(const QString& filename, const QString& arguments, const QString& workDir);
|
||||
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, POJProblemCase problemCase);
|
||||
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, QVector<POJProblemCase> problemCases);
|
||||
void stopRun();
|
||||
void stopCompile();
|
||||
void stopCheckSyntax();
|
||||
|
@ -51,7 +55,7 @@ private:
|
|||
int mSyntaxCheckErrorCount;
|
||||
int mSyntaxCheckIssueCount;
|
||||
Compiler* mBackgroundSyntaxChecker;
|
||||
ExecutableRunner* mRunner;
|
||||
Runner* mRunner;
|
||||
QRecursiveMutex mCompileMutex;
|
||||
QRecursiveMutex mBackgroundSyntaxCheckMutex;
|
||||
QRecursiveMutex mRunnerMutex;
|
||||
|
|
|
@ -7,23 +7,15 @@
|
|||
#include "../settings.h"
|
||||
#include "../systemconsts.h"
|
||||
|
||||
ExecutableRunner::ExecutableRunner(const QString &filename, const QString &arguments, const QString &workDir):
|
||||
QThread(),
|
||||
mFilename(filename),
|
||||
mArguments(arguments),
|
||||
mWorkDir(workDir),
|
||||
mStop(false),
|
||||
ExecutableRunner::ExecutableRunner(const QString &filename, const QString &arguments, const QString &workDir
|
||||
,QObject* parent):
|
||||
Runner(filename,arguments,workDir,parent),
|
||||
mRedirectInput(false),
|
||||
mStartConsole(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ExecutableRunner::stop()
|
||||
{
|
||||
mStop = true;
|
||||
}
|
||||
|
||||
bool ExecutableRunner::startConsole() const
|
||||
{
|
||||
return mStartConsole;
|
||||
|
@ -57,6 +49,9 @@ void ExecutableRunner::setRedirectInputFilename(const QString &newDataFile)
|
|||
void ExecutableRunner::run()
|
||||
{
|
||||
emit started();
|
||||
auto action = finally([this]{
|
||||
emit terminated();
|
||||
});
|
||||
QProcess process;
|
||||
mStop = false;
|
||||
bool errorOccurred = false;
|
||||
|
@ -142,5 +137,4 @@ void ExecutableRunner::run()
|
|||
break;
|
||||
}
|
||||
}
|
||||
emit terminated();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#ifndef EXECUTABLERUNNER_H
|
||||
#define EXECUTABLERUNNER_H
|
||||
|
||||
#include <QThread>
|
||||
#include "runner.h"
|
||||
|
||||
class ExecutableRunner : public QThread
|
||||
class ExecutableRunner : public Runner
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ExecutableRunner(const QString& filename, const QString& arguments, const QString& workDir);
|
||||
ExecutableRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
const QString &redirectInputFilename() const;
|
||||
void setRedirectInputFilename(const QString &newDataFile);
|
||||
|
@ -18,19 +19,7 @@ public:
|
|||
bool startConsole() const;
|
||||
void setStartConsole(bool newStartConsole);
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void terminated();
|
||||
void runErrorOccurred(const QString& reason);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
private:
|
||||
QString mFilename;
|
||||
QString mArguments;
|
||||
QString mWorkDir;
|
||||
bool mStop;
|
||||
QString mRedirectInputFilename;
|
||||
bool mRedirectInput;
|
||||
bool mStartConsole;
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
#include "ojproblemcasesrunner.h"
|
||||
#include "../utils.h"
|
||||
#include "../settings.h"
|
||||
#include "../systemconsts.h"
|
||||
#include "../widgets/ojproblemsetmodel.h"
|
||||
#include <QProcess>
|
||||
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
const QVector<POJProblemCase>& problemCases, QObject *parent):
|
||||
Runner(filename,arguments,workDir,parent)
|
||||
{
|
||||
mProblemCases = problemCases;
|
||||
}
|
||||
|
||||
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
POJProblemCase problemCase, QObject *parent):
|
||||
Runner(filename,arguments,workDir,parent)
|
||||
{
|
||||
mProblemCases.append(problemCase);
|
||||
}
|
||||
|
||||
void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
|
||||
{
|
||||
emit caseStarted(mProblemCases.count(),index);
|
||||
auto action = finally([this,&index]{
|
||||
emit caseStarted(mProblemCases.count(),index);
|
||||
});
|
||||
QProcess process;
|
||||
bool errorOccurred = false;
|
||||
|
||||
process.setProgram(mFilename);
|
||||
process.setArguments(QProcess::splitCommand(mArguments));
|
||||
process.setWorkingDirectory(mWorkDir);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
QString path = env.value("PATH");
|
||||
QStringList pathAdded;
|
||||
if (pSettings->compilerSets().defaultSet()) {
|
||||
foreach(const QString& dir, pSettings->compilerSets().defaultSet()->binDirs()) {
|
||||
pathAdded.append(dir);
|
||||
}
|
||||
}
|
||||
pathAdded.append(pSettings->dirs().app());
|
||||
if (!path.isEmpty()) {
|
||||
path+= PATH_SEPARATOR + pathAdded.join(PATH_SEPARATOR);
|
||||
} else {
|
||||
path = pathAdded.join(PATH_SEPARATOR);
|
||||
}
|
||||
env.insert("PATH",path);
|
||||
process.setProcessEnvironment(env);
|
||||
process.setProcessChannelMode(QProcess::MergedChannels);
|
||||
process.connect(&process, &QProcess::errorOccurred,
|
||||
[&](){
|
||||
errorOccurred= true;
|
||||
});
|
||||
problemCase->output.clear();
|
||||
process.start();
|
||||
process.waitForStarted(5000);
|
||||
if (process.state()==QProcess::Running) {
|
||||
process.write(problemCase->input.toUtf8());
|
||||
process.closeWriteChannel();
|
||||
}
|
||||
QByteArray readed;
|
||||
while (true) {
|
||||
process.waitForFinished(1000);
|
||||
if (process.state()!=QProcess::Running) {
|
||||
break;
|
||||
}
|
||||
if (mStop) {
|
||||
process.closeReadChannel(QProcess::StandardOutput);
|
||||
process.closeReadChannel(QProcess::StandardError);
|
||||
process.closeWriteChannel();
|
||||
process.terminate();
|
||||
process.kill();
|
||||
break;
|
||||
}
|
||||
readed += process.readAll();
|
||||
if (errorOccurred)
|
||||
break;
|
||||
}
|
||||
if (errorOccurred) {
|
||||
//qDebug()<<"process error:"<<process.error();
|
||||
switch (process.error()) {
|
||||
case QProcess::FailedToStart:
|
||||
emit runErrorOccurred(tr("The runner process '%1' failed to start.").arg(mFilename));
|
||||
break;
|
||||
// case QProcess::Crashed:
|
||||
// if (!mStop)
|
||||
// emit runErrorOccurred(tr("The runner process crashed after starting successfully."));
|
||||
// break;
|
||||
case QProcess::Timedout:
|
||||
emit runErrorOccurred(tr("The last waitFor...() function timed out."));
|
||||
break;
|
||||
case QProcess::WriteError:
|
||||
emit runErrorOccurred(tr("An error occurred when attempting to write to the runner process."));
|
||||
break;
|
||||
case QProcess::ReadError:
|
||||
emit runErrorOccurred(tr("An error occurred when attempting to read from the runner process."));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
problemCase->output = QString::fromUtf8(readed);
|
||||
}
|
||||
|
||||
void OJProblemCasesRunner::run()
|
||||
{
|
||||
emit started();
|
||||
auto action = finally([this]{
|
||||
emit terminated();
|
||||
});
|
||||
for (int i=0;i<mProblemCases.size();i++) {
|
||||
if (mStop)
|
||||
break;
|
||||
POJProblemCase problemCase =mProblemCases[i];
|
||||
runCase(i,problemCase);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef OJPROBLEMCASESRUNNER_H
|
||||
#define OJPROBLEMCASESRUNNER_H
|
||||
|
||||
#include "runner.h"
|
||||
#include <QVector>
|
||||
|
||||
class OJProblemCase;
|
||||
using POJProblemCase = std::shared_ptr<OJProblemCase>;
|
||||
|
||||
class OJProblemCasesRunner : public Runner
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
const QVector<POJProblemCase>& problemCases, QObject *parent = nullptr);
|
||||
explicit OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
|
||||
POJProblemCase problemCase, QObject *parent = nullptr);
|
||||
signals:
|
||||
void caseStarted(int total, int current);
|
||||
void caseFinished(int total, int current);
|
||||
private:
|
||||
void runCase(int index, POJProblemCase problemCase);
|
||||
private:
|
||||
QVector<POJProblemCase> mProblemCases;
|
||||
|
||||
// QThread interface
|
||||
protected:
|
||||
void run() override;
|
||||
};
|
||||
|
||||
#endif // OJPROBLEMCASESRUNNER_H
|
|
@ -0,0 +1,17 @@
|
|||
#include "runner.h"
|
||||
|
||||
Runner::Runner(const QString &filename, const QString &arguments, const QString &workDir
|
||||
,QObject *parent) : QThread(parent),
|
||||
mStop(false),
|
||||
mFilename(filename),
|
||||
mArguments(arguments),
|
||||
mWorkDir(workDir)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Runner::stop()
|
||||
{
|
||||
mStop = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef RUNNER_H
|
||||
#define RUNNER_H
|
||||
|
||||
#include <QThread>
|
||||
|
||||
class Runner : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Runner(const QString& filename, const QString& arguments, const QString& workDir, QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void terminated();
|
||||
void runErrorOccurred(const QString& reason);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
bool mStop;
|
||||
QString mFilename;
|
||||
QString mArguments;
|
||||
QString mWorkDir;
|
||||
};
|
||||
|
||||
#endif // RUNNER_H
|
|
@ -3314,6 +3314,7 @@ void MainWindow::onCompileErrorOccured(const QString &reason)
|
|||
|
||||
void MainWindow::onRunErrorOccured(const QString &reason)
|
||||
{
|
||||
mCompilerManager->stopRun();
|
||||
QMessageBox::critical(this,tr("Run Failed"),reason);
|
||||
}
|
||||
|
||||
|
@ -4891,8 +4892,18 @@ void MainWindow::on_actionRun_Parameters_triggered()
|
|||
|
||||
void MainWindow::on_btnNewProblemSet_clicked()
|
||||
{
|
||||
if (mOJProblemSetModel.count()>0) {
|
||||
if (QMessageBox::warning(this,
|
||||
tr("New Problem Set"),
|
||||
tr("The current problem set is not empty.")
|
||||
+"<br />"
|
||||
+tr("Do you want to save it?"),
|
||||
QMessageBox::Yes | QMessageBox::No)!=QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
mOJProblemSetNameCounter++;
|
||||
mOJProblemSetModel.create(tr("Problem Set %1").arg(mOJProblemSetNameCounter));
|
||||
ui->lblProblemSet->setText(mOJProblemSetModel.name());
|
||||
}
|
||||
|
||||
|
||||
|
@ -4954,6 +4965,7 @@ void MainWindow::on_btnLoadProblemSet_clicked()
|
|||
error.reason());
|
||||
}
|
||||
}
|
||||
ui->lblProblemSet->setText(mOJProblemSetModel.name());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -263,6 +263,10 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabProblemSet">
|
||||
<attribute name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/icons/images/newlook24/014-compopt.png</normaloff>:/icons/images/newlook24/014-compopt.png</iconset>
|
||||
</attribute>
|
||||
<attribute name="title">
|
||||
<string>Problem Set</string>
|
||||
</attribute>
|
||||
|
@ -391,7 +395,14 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="lstProblemSet"/>
|
||||
<widget class="QListView" name="lstProblemSet">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -1222,6 +1233,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="pbProblemCases">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="format">
|
||||
<string>%v/%m</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
@ -1239,7 +1260,14 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="lstProblemCases"/>
|
||||
<widget class="QListView" name="lstProblemCases">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -153,12 +153,31 @@ QVariant OJProblemSetModel::data(const QModelIndex &index, int role) const
|
|||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
||||
return mProblemSet.problems[index.row()]->name;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool OJProblemSetModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
if (role == Qt::EditRole) {
|
||||
QString s = value.toString();
|
||||
if (!s.isEmpty()) {
|
||||
mProblemSet.problems[index.row()]->name = s;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags OJProblemSetModel::flags(const QModelIndex &) const
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
OJProblemModel::OJProblemModel(QObject *parent): QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
|
@ -233,8 +252,19 @@ QVariant OJProblemModel::data(const QModelIndex &index, int role) const
|
|||
return QVariant();
|
||||
if (mProblem==nullptr)
|
||||
return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
||||
return mProblem->cases[index.row()]->name;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool OJProblemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags OJProblemModel::flags(const QModelIndex &) const
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ private:
|
|||
public:
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
class OJProblemSetModel : public QAbstractListModel
|
||||
|
@ -78,6 +80,8 @@ private:
|
|||
public:
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
#endif // OJPROBLEMSETMODEL_H
|
||||
|
|
Loading…
Reference in New Issue