- 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: display problem case running time
|
||||||
- enhancement: set problem case input/expected output file
|
- enhancement: set problem case input/expected output file
|
||||||
- enhancement: auto position cursor in expected with output's cursor
|
- 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
|
Red Panda C++ Version 1.0.1
|
||||||
- fix: only convert project icon file when it's filename doesn't end with ".ico"
|
- fix: only convert project icon file when it's filename doesn't end with ".ico"
|
||||||
|
|
|
@ -170,6 +170,7 @@ SOURCES += \
|
||||||
widgets/issuestable.cpp \
|
widgets/issuestable.cpp \
|
||||||
widgets/labelwithmenu.cpp \
|
widgets/labelwithmenu.cpp \
|
||||||
widgets/lightfusionstyle.cpp \
|
widgets/lightfusionstyle.cpp \
|
||||||
|
widgets/linenumbertexteditor.cpp \
|
||||||
widgets/macroinfomodel.cpp \
|
widgets/macroinfomodel.cpp \
|
||||||
widgets/newclassdialog.cpp \
|
widgets/newclassdialog.cpp \
|
||||||
widgets/newheaderdialog.cpp \
|
widgets/newheaderdialog.cpp \
|
||||||
|
@ -314,6 +315,7 @@ HEADERS += \
|
||||||
widgets/issuestable.h \
|
widgets/issuestable.h \
|
||||||
widgets/labelwithmenu.h \
|
widgets/labelwithmenu.h \
|
||||||
widgets/lightfusionstyle.h \
|
widgets/lightfusionstyle.h \
|
||||||
|
widgets/linenumbertexteditor.h \
|
||||||
widgets/macroinfomodel.h \
|
widgets/macroinfomodel.h \
|
||||||
widgets/newclassdialog.h \
|
widgets/newclassdialog.h \
|
||||||
widgets/newheaderdialog.h \
|
widgets/newheaderdialog.h \
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -69,6 +69,7 @@
|
||||||
#include <QFileIconProvider>
|
#include <QFileIconProvider>
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QTextDocumentFragment>
|
||||||
|
|
||||||
#include "settingsdialog/settingsdialog.h"
|
#include "settingsdialog/settingsdialog.h"
|
||||||
#include "compiler/compilermanager.h"
|
#include "compiler/compilermanager.h"
|
||||||
|
@ -646,8 +647,11 @@ void MainWindow::applySettings()
|
||||||
caseEditorFont.setPixelSize(pointToPixel(pSettings->executor().caseEditorFontSize()));
|
caseEditorFont.setPixelSize(pointToPixel(pSettings->executor().caseEditorFontSize()));
|
||||||
font.setStyleStrategy(QFont::PreferAntialias);
|
font.setStyleStrategy(QFont::PreferAntialias);
|
||||||
ui->txtProblemCaseInput->setFont(caseEditorFont);
|
ui->txtProblemCaseInput->setFont(caseEditorFont);
|
||||||
|
ui->lblProblemCaseInput->setFont(caseEditorFont);
|
||||||
ui->txtProblemCaseOutput->setFont(caseEditorFont);
|
ui->txtProblemCaseOutput->setFont(caseEditorFont);
|
||||||
|
ui->lblProblemCaseOutput->setFont(caseEditorFont);
|
||||||
ui->txtProblemCaseExpected->setFont(caseEditorFont);
|
ui->txtProblemCaseExpected->setFont(caseEditorFont);
|
||||||
|
ui->lblProblemCaseExpected->setFont(caseEditorFont);
|
||||||
|
|
||||||
mTcpServer.close();
|
mTcpServer.close();
|
||||||
if (pSettings->executor().enableProblemSet()) {
|
if (pSettings->executor().enableProblemSet()) {
|
||||||
|
@ -3170,25 +3174,23 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex ¤t, const QMo
|
||||||
POJProblemCase problemCase = mOJProblemModel.getCase(idx.row());
|
POJProblemCase problemCase = mOJProblemModel.getCase(idx.row());
|
||||||
if (problemCase) {
|
if (problemCase) {
|
||||||
ui->btnProblemCaseInputFileName->setEnabled(false);
|
ui->btnProblemCaseInputFileName->setEnabled(false);
|
||||||
ui->txtProblemCaseInputFileName->setEnabled(false);
|
|
||||||
ui->btnRemoveProblemCase->setEnabled(true);
|
ui->btnRemoveProblemCase->setEnabled(true);
|
||||||
ui->btnProblemCaseInputFileName->setEnabled(true);
|
ui->btnProblemCaseInputFileName->setEnabled(true);
|
||||||
fillProblemCaseInputAndExpected(problemCase);
|
fillProblemCaseInputAndExpected(problemCase);
|
||||||
ui->txtProblemCaseOutput->clear();
|
ui->txtProblemCaseOutput->clear();
|
||||||
ui->txtProblemCaseOutput->setPlainText(problemCase->output);
|
ui->txtProblemCaseOutput->setPlainText(problemCase->output);
|
||||||
updateProblemCaseOutput(problemCase);
|
updateProblemCaseOutput(problemCase);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->btnProblemCaseClearInputFileName->setVisible(false);
|
ui->btnProblemCaseClearInputFileName->setVisible(false);
|
||||||
ui->btnProblemCaseInputFileName->setEnabled(false);
|
ui->btnProblemCaseInputFileName->setEnabled(false);
|
||||||
ui->txtProblemCaseInputFileName->setEnabled(false);
|
|
||||||
ui->txtProblemCaseInputFileName->clear();
|
ui->txtProblemCaseInputFileName->clear();
|
||||||
ui->txtProblemCaseInputFileName->setToolTip("");
|
ui->txtProblemCaseInputFileName->setToolTip("");
|
||||||
|
|
||||||
ui->btnProblemCaseClearExpectedOutputFileName->setVisible(false);
|
ui->btnProblemCaseClearExpectedOutputFileName->setVisible(false);
|
||||||
ui->btnProblemCaseExpectedOutputFileName->setEnabled(false);
|
ui->btnProblemCaseExpectedOutputFileName->setEnabled(false);
|
||||||
ui->txtProblemCaseExpectedOutputFileName->setEnabled(false);
|
|
||||||
ui->txtProblemCaseExpectedOutputFileName->clear();
|
ui->txtProblemCaseExpectedOutputFileName->clear();
|
||||||
ui->txtProblemCaseExpectedOutputFileName->setToolTip("");
|
ui->txtProblemCaseExpectedOutputFileName->setToolTip("");
|
||||||
|
|
||||||
|
@ -3200,6 +3202,10 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex ¤t, const QMo
|
||||||
ui->txtProblemCaseExpected->clear();
|
ui->txtProblemCaseExpected->clear();
|
||||||
ui->txtProblemCaseExpected->setReadOnly(true);
|
ui->txtProblemCaseExpected->setReadOnly(true);
|
||||||
ui->txtProblemCaseOutput->clear();
|
ui->txtProblemCaseOutput->clear();
|
||||||
|
|
||||||
|
ui->lblProblemCaseExpected->clear();
|
||||||
|
ui->lblProblemCaseOutput->clear();
|
||||||
|
ui->lblProblemCaseInput->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onProblemNameChanged(int index)
|
void MainWindow::onProblemNameChanged(int index)
|
||||||
|
@ -6217,31 +6223,33 @@ void MainWindow::doCompileRun(RunType runType)
|
||||||
void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase)
|
void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase)
|
||||||
{
|
{
|
||||||
if (problemCase->testState == ProblemCaseTestState::Failed) {
|
if (problemCase->testState == ProblemCaseTestState::Failed) {
|
||||||
QStringList output = textToLines(problemCase->output);
|
int diffLine;
|
||||||
QStringList expected;
|
if (problemCase->outputLineCounts > problemCase->expectedLineCounts) {
|
||||||
if (fileExists(problemCase->expectedOutputFileName))
|
diffLine = problemCase->expectedLineCounts;
|
||||||
expected = readFileToLines(problemCase->expectedOutputFileName);
|
} else if (problemCase->outputLineCounts < problemCase->expectedLineCounts) {
|
||||||
else
|
diffLine = problemCase->outputLineCounts;
|
||||||
expected = textToLines(problemCase->expected);
|
} else {
|
||||||
for (int i=0;i<output.count();i++) {
|
diffLine = problemCase->firstDiffLine;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (output.count()<expected.count()) {
|
if (diffLine < problemCase->outputLineCounts) {
|
||||||
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(output.count()-1);
|
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(diffLine);
|
||||||
|
if (!block.isValid())
|
||||||
|
return;
|
||||||
QTextCursor cur(block);
|
QTextCursor cur(block);
|
||||||
cur.select(QTextCursor::LineUnderCursor);
|
if (cur.isNull())
|
||||||
|
return;
|
||||||
|
cur = QTextCursor(block);
|
||||||
|
QTextCharFormat oldFormat = cur.charFormat();
|
||||||
QTextCharFormat format = cur.charFormat();
|
QTextCharFormat format = cur.charFormat();
|
||||||
|
cur.select(QTextCursor::LineUnderCursor);
|
||||||
format.setUnderlineColor(mErrorColor);
|
format.setUnderlineColor(mErrorColor);
|
||||||
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||||
cur.setCharFormat(format);
|
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();
|
QTextCursor cursor = ui->txtProblemCaseOutput->textCursor();
|
||||||
int val = ui->txtProblemCaseOutput->verticalScrollBar()->value();
|
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->setTextCursor(cursor);
|
||||||
ui->txtProblemCaseExpected->verticalScrollBar()->setValue(val);
|
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_txtProblemCaseOutput_cursorPositionChanged();
|
||||||
|
|
||||||
|
void on_txtProblemCaseExpected_cursorPositionChanged();
|
||||||
|
|
||||||
|
void on_txtProblemCaseInput_cursorPositionChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
EditorList *mEditorList;
|
EditorList *mEditorList;
|
||||||
|
|
|
@ -1373,7 +1373,7 @@
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QPlainTextEdit" name="txtProblemCaseOutput">
|
<widget class="LineNumberTextEditor" name="txtProblemCaseOutput">
|
||||||
<property name="lineWrapMode">
|
<property name="lineWrapMode">
|
||||||
<enum>QPlainTextEdit::NoWrap</enum>
|
<enum>QPlainTextEdit::NoWrap</enum>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1382,13 +1382,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="0" column="0">
|
||||||
<widget class="QWidget" name="widget_7" native="true">
|
<widget class="QWidget" name="widget_7" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
@ -1406,6 +1399,9 @@
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QLineEdit" name="txtProblemCaseInputFileName">
|
<widget class="QLineEdit" name="txtProblemCaseInputFileName">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1453,13 +1449,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="0" column="2">
|
||||||
<widget class="QWidget" name="widget_8" native="true">
|
<widget class="QWidget" name="widget_8" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
<layout class="QHBoxLayout" name="horizontalLayout_18">
|
||||||
|
@ -1484,6 +1473,9 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="txtProblemCaseExpectedOutputFileName">
|
<widget class="QLineEdit" name="txtProblemCaseExpectedOutputFileName">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1517,6 +1509,41 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -3010,6 +3037,11 @@
|
||||||
<header location="global">widgets/editorstabwidget.h</header>
|
<header location="global">widgets/editorstabwidget.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>LineNumberTextEditor</class>
|
||||||
|
<extends>QPlainTextEdit</extends>
|
||||||
|
<header location="global">widgets/linenumbertexteditor.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="icons.qrc"/>
|
<include location="icons.qrc"/>
|
||||||
|
|
|
@ -36,6 +36,9 @@ struct OJProblemCase {
|
||||||
ProblemCaseTestState testState; // no persistence
|
ProblemCaseTestState testState; // no persistence
|
||||||
QString output; // no persistence
|
QString output; // no persistence
|
||||||
int runningTime;
|
int runningTime;
|
||||||
|
int firstDiffLine;
|
||||||
|
int outputLineCounts;
|
||||||
|
int expectedLineCounts;
|
||||||
OJProblemCase();
|
OJProblemCase();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -27,16 +27,26 @@ bool ProblemCaseValidator::validate(POJProblemCase problemCase, bool ignoreSpace
|
||||||
if (!problemCase)
|
if (!problemCase)
|
||||||
return false;
|
return false;
|
||||||
QStringList output = textToLines(problemCase->output);
|
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())
|
if (output.count()!=expected.count())
|
||||||
return false;
|
return false;
|
||||||
for (int i=0;i<output.count();i++) {
|
for (int i=0;i<output.count();i++) {
|
||||||
if (ignoreSpaces) {
|
if (ignoreSpaces) {
|
||||||
if (!equalIgnoringSpaces(output[i],expected[i]))
|
if (!equalIgnoringSpaces(output[i],expected[i])) {
|
||||||
|
problemCase->firstDiffLine = i;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (output[i]!=expected[i])
|
if (output[i]!=expected[i]) {
|
||||||
|
problemCase->firstDiffLine = i;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
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