- enhancement: only tag the first inconstantency when running problem case, to greatly reduce compare & display time

This commit is contained in:
Roy Qu 2022-03-29 21:41:02 +08:00
parent a1614cef68
commit 6754c014c9
10 changed files with 495 additions and 260 deletions

View File

@ -11,6 +11,7 @@ Red Panda C++ Version 1.0.2
- enhancement: display problem case running time
- enhancement: set problem case input/expected output file
- enhancement: auto position cursor in expected with output's cursor
- enhancement: only tag the first inconstantency when running problem case, to greatly reduce compare & display time
Red Panda C++ Version 1.0.1
- fix: only convert project icon file when it's filename doesn't end with ".ico"

View File

@ -170,6 +170,7 @@ SOURCES += \
widgets/issuestable.cpp \
widgets/labelwithmenu.cpp \
widgets/lightfusionstyle.cpp \
widgets/linenumbertexteditor.cpp \
widgets/macroinfomodel.cpp \
widgets/newclassdialog.cpp \
widgets/newheaderdialog.cpp \
@ -314,6 +315,7 @@ HEADERS += \
widgets/issuestable.h \
widgets/labelwithmenu.h \
widgets/lightfusionstyle.h \
widgets/linenumbertexteditor.h \
widgets/macroinfomodel.h \
widgets/newclassdialog.h \
widgets/newheaderdialog.h \

File diff suppressed because it is too large Load Diff

View File

@ -69,6 +69,7 @@
#include <QFileIconProvider>
#include "MainWindow.h"
#include <QScrollBar>
#include <QTextDocumentFragment>
#include "settingsdialog/settingsdialog.h"
#include "compiler/compilermanager.h"
@ -646,8 +647,11 @@ void MainWindow::applySettings()
caseEditorFont.setPixelSize(pointToPixel(pSettings->executor().caseEditorFontSize()));
font.setStyleStrategy(QFont::PreferAntialias);
ui->txtProblemCaseInput->setFont(caseEditorFont);
ui->lblProblemCaseInput->setFont(caseEditorFont);
ui->txtProblemCaseOutput->setFont(caseEditorFont);
ui->lblProblemCaseOutput->setFont(caseEditorFont);
ui->txtProblemCaseExpected->setFont(caseEditorFont);
ui->lblProblemCaseExpected->setFont(caseEditorFont);
mTcpServer.close();
if (pSettings->executor().enableProblemSet()) {
@ -3170,25 +3174,23 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex &current, const QMo
POJProblemCase problemCase = mOJProblemModel.getCase(idx.row());
if (problemCase) {
ui->btnProblemCaseInputFileName->setEnabled(false);
ui->txtProblemCaseInputFileName->setEnabled(false);
ui->btnRemoveProblemCase->setEnabled(true);
ui->btnProblemCaseInputFileName->setEnabled(true);
fillProblemCaseInputAndExpected(problemCase);
ui->txtProblemCaseOutput->clear();
ui->txtProblemCaseOutput->setPlainText(problemCase->output);
updateProblemCaseOutput(problemCase);
return;
}
}
ui->btnProblemCaseClearInputFileName->setVisible(false);
ui->btnProblemCaseInputFileName->setEnabled(false);
ui->txtProblemCaseInputFileName->setEnabled(false);
ui->txtProblemCaseInputFileName->clear();
ui->txtProblemCaseInputFileName->setToolTip("");
ui->btnProblemCaseClearExpectedOutputFileName->setVisible(false);
ui->btnProblemCaseExpectedOutputFileName->setEnabled(false);
ui->txtProblemCaseExpectedOutputFileName->setEnabled(false);
ui->txtProblemCaseExpectedOutputFileName->clear();
ui->txtProblemCaseExpectedOutputFileName->setToolTip("");
@ -3200,6 +3202,10 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex &current, const QMo
ui->txtProblemCaseExpected->clear();
ui->txtProblemCaseExpected->setReadOnly(true);
ui->txtProblemCaseOutput->clear();
ui->lblProblemCaseExpected->clear();
ui->lblProblemCaseOutput->clear();
ui->lblProblemCaseInput->clear();
}
void MainWindow::onProblemNameChanged(int index)
@ -6217,31 +6223,33 @@ void MainWindow::doCompileRun(RunType runType)
void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase)
{
if (problemCase->testState == ProblemCaseTestState::Failed) {
QStringList output = textToLines(problemCase->output);
QStringList expected;
if (fileExists(problemCase->expectedOutputFileName))
expected = readFileToLines(problemCase->expectedOutputFileName);
else
expected = textToLines(problemCase->expected);
for (int i=0;i<output.count();i++) {
if (i>=expected.count() || output[i]!=expected[i]) {
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(i);
QTextCursor cur(block);
cur.select(QTextCursor::LineUnderCursor);
QTextCharFormat format = cur.charFormat();
format.setUnderlineColor(mErrorColor);
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
cur.setCharFormat(format);
}
int diffLine;
if (problemCase->outputLineCounts > problemCase->expectedLineCounts) {
diffLine = problemCase->expectedLineCounts;
} else if (problemCase->outputLineCounts < problemCase->expectedLineCounts) {
diffLine = problemCase->outputLineCounts;
} else {
diffLine = problemCase->firstDiffLine;
}
if (output.count()<expected.count()) {
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(output.count()-1);
if (diffLine < problemCase->outputLineCounts) {
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(diffLine);
if (!block.isValid())
return;
QTextCursor cur(block);
cur.select(QTextCursor::LineUnderCursor);
if (cur.isNull())
return;
cur = QTextCursor(block);
QTextCharFormat oldFormat = cur.charFormat();
QTextCharFormat format = cur.charFormat();
cur.select(QTextCursor::LineUnderCursor);
format.setUnderlineColor(mErrorColor);
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
cur.setCharFormat(format);
cur.clearSelection();
cur.setCharFormat(oldFormat);
ui->txtProblemCaseOutput->setTextCursor(cur);
} else if (diffLine < problemCase->expectedLineCounts) {
ui->txtProblemCaseOutput->moveCursor(QTextCursor::MoveOperation::End);
}
}
}
@ -7446,7 +7454,28 @@ void MainWindow::on_txtProblemCaseOutput_cursorPositionChanged()
{
QTextCursor cursor = ui->txtProblemCaseOutput->textCursor();
int val = ui->txtProblemCaseOutput->verticalScrollBar()->value();
int line = cursor.block().firstLineNumber();
ui->lblProblemCaseOutput->setText(tr("Line %1").arg(cursor.block().firstLineNumber()+1));
QTextBlock block = ui->txtProblemCaseExpected->document()->findBlockByLineNumber(line);
if (!block.isValid())
return;
cursor = QTextCursor(block);
ui->txtProblemCaseExpected->setTextCursor(cursor);
ui->txtProblemCaseExpected->verticalScrollBar()->setValue(val);
}
void MainWindow::on_txtProblemCaseExpected_cursorPositionChanged()
{
QTextCursor cursor = ui->txtProblemCaseExpected->textCursor();
ui->lblProblemCaseExpected->setText(tr("Line %1").arg(cursor.block().firstLineNumber()+1));
}
void MainWindow::on_txtProblemCaseInput_cursorPositionChanged()
{
QTextCursor cursor = ui->txtProblemCaseInput->textCursor();
ui->lblProblemCaseInput->setText(tr("Line %1").arg(cursor.block().firstLineNumber()+1));
}

View File

@ -657,6 +657,10 @@ private slots:
void on_txtProblemCaseOutput_cursorPositionChanged();
void on_txtProblemCaseExpected_cursorPositionChanged();
void on_txtProblemCaseInput_cursorPositionChanged();
private:
Ui::MainWindow *ui;
EditorList *mEditorList;

View File

@ -1373,7 +1373,7 @@
<number>0</number>
</property>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="txtProblemCaseOutput">
<widget class="LineNumberTextEditor" name="txtProblemCaseOutput">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
@ -1382,13 +1382,6 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPlainTextEdit" name="txtProblemCaseExpected">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QWidget" name="widget_7" native="true">
<layout class="QGridLayout" name="gridLayout_4">
@ -1406,6 +1399,9 @@
</property>
<item row="0" column="1">
<widget class="QLineEdit" name="txtProblemCaseInputFileName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -1453,13 +1449,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPlainTextEdit" name="txtProblemCaseInput">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QWidget" name="widget_8" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_18">
@ -1484,6 +1473,9 @@
</item>
<item>
<widget class="QLineEdit" name="txtProblemCaseExpectedOutputFileName">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@ -1517,6 +1509,41 @@
</layout>
</widget>
</item>
<item row="2" column="2">
<widget class="LineNumberTextEditor" name="txtProblemCaseExpected">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="LineNumberTextEditor" name="txtProblemCaseInput">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="lblProblemCaseExpected">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblProblemCaseOutput">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblProblemCaseInput">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -3010,6 +3037,11 @@
<header location="global">widgets/editorstabwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LineNumberTextEditor</class>
<extends>QPlainTextEdit</extends>
<header location="global">widgets/linenumbertexteditor.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="icons.qrc"/>

View File

@ -36,6 +36,9 @@ struct OJProblemCase {
ProblemCaseTestState testState; // no persistence
QString output; // no persistence
int runningTime;
int firstDiffLine;
int outputLineCounts;
int expectedLineCounts;
OJProblemCase();
public:

View File

@ -27,16 +27,26 @@ bool ProblemCaseValidator::validate(POJProblemCase problemCase, bool ignoreSpace
if (!problemCase)
return false;
QStringList output = textToLines(problemCase->output);
QStringList expected = textToLines(problemCase->expected);
QStringList expected;
if (fileExists(problemCase->expectedOutputFileName))
expected = readFileToLines(problemCase->expectedOutputFileName);
else
expected = textToLines(problemCase->expected);
problemCase->outputLineCounts = output.count();
problemCase->expectedLineCounts = expected.count();
if (output.count()!=expected.count())
return false;
for (int i=0;i<output.count();i++) {
if (ignoreSpaces) {
if (!equalIgnoringSpaces(output[i],expected[i]))
if (!equalIgnoringSpaces(output[i],expected[i])) {
problemCase->firstDiffLine = i;
return false;
}
} else {
if (output[i]!=expected[i])
if (output[i]!=expected[i]) {
problemCase->firstDiffLine = i;
return false;
}
}
}
return true;

View File

@ -0,0 +1,97 @@
#include "linenumbertexteditor.h"
#include <QPainter>
#include <QTextBlock>
LineNumberTextEditor::LineNumberTextEditor(QWidget *parent)
{
lineNumberArea = new LineNumberArea(this);
connect(this, &LineNumberTextEditor::blockCountChanged, this, &LineNumberTextEditor::updateLineNumberAreaWidth);
connect(this, &LineNumberTextEditor::updateRequest, this, &LineNumberTextEditor::updateLineNumberArea);
//connect(this, &LineNumberTextEditor::cursorPositionChanged, this, &LineNumberTextEditor::highlightCurrentLine);
updateLineNumberAreaWidth(0);
//highlightCurrentLine();
}
int LineNumberTextEditor::lineNumberAreaWidth()
{
int digits = 1;
int max = qMax(1, blockCount());
while (max >= 10) {
max /= 10;
++digits;
}
int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits;
return space;
}
void LineNumberTextEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void LineNumberTextEditor::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
lineNumberArea->scroll(0, dy);
else
lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
if (rect.contains(viewport()->rect()))
updateLineNumberAreaWidth(0);
}
void LineNumberTextEditor::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
QRect cr = contentsRect();
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
void LineNumberTextEditor::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
if (!isReadOnly()) {
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(Qt::yellow).lighter(160);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
void LineNumberTextEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(lineNumberArea);
painter.setFont(font());
painter.fillRect(event->rect(), palette().color(QPalette::Button));
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top());
int bottom = top + qRound(blockBoundingRect(block).height());
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1);
painter.setPen(palette().color(QPalette::ButtonText));
painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + qRound(blockBoundingRect(block).height());
++blockNumber;
}
}

View File

@ -0,0 +1,50 @@
#ifndef LINENUMBERTEXTEDITOR_H
#define LINENUMBERTEXTEDITOR_H
#include <QPlainTextEdit>
class LineNumberTextEditor : public QPlainTextEdit
{
Q_OBJECT
public:
LineNumberTextEditor(QWidget *parent = nullptr);
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberAreaWidth();
protected:
void resizeEvent(QResizeEvent *event) override;
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void highlightCurrentLine();
void updateLineNumberArea(const QRect &rect, int dy);
private:
QWidget *lineNumberArea;
};
class LineNumberArea : public QWidget
{
public:
LineNumberArea(LineNumberTextEditor *editor) : QWidget(editor), mParentEditor(editor)
{}
QSize sizeHint() const override
{
return QSize(mParentEditor->lineNumberAreaWidth(), 0);
}
protected:
void paintEvent(QPaintEvent *event) override
{
mParentEditor->lineNumberAreaPaintEvent(event);
}
private:
LineNumberTextEditor *mParentEditor;
};
#endif // LINENUMBERTEXTEDITOR_H