- enhancement: only tag the first inconstantency when running problem case, to greatly reduce compare & display time
This commit is contained in:
parent
a1614cef68
commit
6754c014c9
1
NEWS.md
1
NEWS.md
|
@ -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"
|
||||
|
|
|
@ -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
|
@ -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 ¤t, 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 ¤t, 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);
|
||||
int diffLine;
|
||||
if (problemCase->outputLineCounts > problemCase->expectedLineCounts) {
|
||||
diffLine = problemCase->expectedLineCounts;
|
||||
} else if (problemCase->outputLineCounts < problemCase->expectedLineCounts) {
|
||||
diffLine = problemCase->outputLineCounts;
|
||||
} else {
|
||||
diffLine = problemCase->firstDiffLine;
|
||||
}
|
||||
if (diffLine < problemCase->outputLineCounts) {
|
||||
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(diffLine);
|
||||
if (!block.isValid())
|
||||
return;
|
||||
QTextCursor cur(block);
|
||||
cur.select(QTextCursor::LineUnderCursor);
|
||||
QTextCharFormat format = cur.charFormat();
|
||||
format.setUnderlineColor(mErrorColor);
|
||||
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||
cur.setCharFormat(format);
|
||||
}
|
||||
}
|
||||
if (output.count()<expected.count()) {
|
||||
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(output.count()-1);
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -657,6 +657,10 @@ private slots:
|
|||
|
||||
void on_txtProblemCaseOutput_cursorPositionChanged();
|
||||
|
||||
void on_txtProblemCaseExpected_cursorPositionChanged();
|
||||
|
||||
void on_txtProblemCaseInput_cursorPositionChanged();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
EditorList *mEditorList;
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -36,6 +36,9 @@ struct OJProblemCase {
|
|||
ProblemCaseTestState testState; // no persistence
|
||||
QString output; // no persistence
|
||||
int runningTime;
|
||||
int firstDiffLine;
|
||||
int outputLineCounts;
|
||||
int expectedLineCounts;
|
||||
OJProblemCase();
|
||||
|
||||
public:
|
||||
|
|
|
@ -27,18 +27,28 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue