From 432180ec03a066279b3d3d7635c42eb63f3e67a0 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Tue, 7 May 2013 20:16:17 +0200 Subject: [PATCH] SqlTextEdit: Show line numbers Show line numbers in the SqlTextEdit widget. This code is based on the CodeEditor example from the Qt documentation. --- src/sqltextedit.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++--- src/sqltextedit.h | 22 ++++++++++-- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/sqltextedit.cpp b/src/sqltextedit.cpp index 73bea775..80f04e57 100644 --- a/src/sqltextedit.cpp +++ b/src/sqltextedit.cpp @@ -5,10 +5,11 @@ #include #include #include -//#include +#include +#include SqlTextEdit::SqlTextEdit(QWidget* parent) : - QTextEdit(parent), m_Completer(0), m_defaultCompleterModel(0) + QPlainTextEdit(parent), m_Completer(0), m_defaultCompleterModel(0) { // basic auto completer for sqliteedit m_Completer = new QCompleter(this); @@ -17,10 +18,16 @@ SqlTextEdit::SqlTextEdit(QWidget* parent) : m_Completer->setWrapAround(false); m_Completer->setWidget(this); + // Create line number area + lineNumberArea = new LineNumberArea(this); + + connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth())); + connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); connect(m_Completer, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString))); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); highlightCurrentLine(); + updateLineNumberAreaWidth(); } SqlTextEdit::~SqlTextEdit() @@ -111,6 +118,74 @@ void SqlTextEdit::highlightCurrentLine() setExtraSelections(extra_selections); } +int SqlTextEdit::lineNumberAreaWidth() +{ + int digits = 1; + int max = qMax(1, blockCount()); + while(max >= 10) + { + max /= 10; + ++digits; + } + + return 3 + fontMetrics().width(QLatin1Char('9')) * digits; +} + +void SqlTextEdit::updateLineNumberAreaWidth() +{ + setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); +} + +void SqlTextEdit::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(); +} + +void SqlTextEdit::resizeEvent(QResizeEvent* e) +{ + QPlainTextEdit::resizeEvent(e); + + QRect cr = contentsRect(); + lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); +} + +void SqlTextEdit::LineNumberArea::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + painter.fillRect(event->rect(), Qt::lightGray); + + QTextBlock block = parent->firstVisibleBlock(); + int blockNumber = block.blockNumber(); + int top = parent->blockBoundingGeometry(block).translated(parent->contentOffset()).top(); + int bottom = top + parent->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(Qt::black); + painter.drawText(0, top, width(), fontMetrics().height(), Qt::AlignRight, number); + } + + block = block.next(); + top = bottom; + bottom = top + parent->blockBoundingRect(block).height(); + blockNumber++; + } +} + +QSize SqlTextEdit::LineNumberArea::sizeHint() const +{ + return QSize(parent->lineNumberAreaWidth(), 0); +} + namespace { bool isSqliteIdentifierChar(QChar c) { return c.isLetterOrNumber() || c == '.' || c == '_'; @@ -165,7 +240,7 @@ void SqlTextEdit::focusInEvent(QFocusEvent *e) { if (m_Completer) m_Completer->setWidget(this); - QTextEdit::focusInEvent(e); + QPlainTextEdit::focusInEvent(e); } void SqlTextEdit::keyPressEvent(QKeyEvent *e) @@ -187,7 +262,7 @@ void SqlTextEdit::keyPressEvent(QKeyEvent *e) bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space); // CTRL+SPACE if (!m_Completer || !isShortcut) // do not process the shortcut when we have a completer - QTextEdit::keyPressEvent(e); + QPlainTextEdit::keyPressEvent(e); const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier); const bool cursorKey = e->key() == Qt::Key_Left || e->key() == Qt::Key_Up || diff --git a/src/sqltextedit.h b/src/sqltextedit.h index 9d408d72..5daeeabe 100644 --- a/src/sqltextedit.h +++ b/src/sqltextedit.h @@ -1,7 +1,7 @@ #ifndef SQLTEXTEDIT_H #define SQLTEXTEDIT_H -#include +#include class QCompleter; class QAbstractItemModel; @@ -11,7 +11,7 @@ class QAbstractItemModel; * With basic table and fieldname auto completion. * This class is based on the Qt custom completion example. */ -class SqlTextEdit : public QTextEdit +class SqlTextEdit : public QPlainTextEdit { Q_OBJECT public: @@ -31,13 +31,31 @@ public: protected: void keyPressEvent(QKeyEvent *e); void focusInEvent(QFocusEvent *e); + void resizeEvent(QResizeEvent* event); + + void lineNumberAreaPaintEvent(QPaintEvent* event); + int lineNumberAreaWidth(); private: + class LineNumberArea : public QWidget + { + public: + LineNumberArea(SqlTextEdit *editor) : QWidget(editor), parent(editor) {} + QSize sizeHint() const; + + protected: + void paintEvent(QPaintEvent* event); + SqlTextEdit* parent; + }; + + LineNumberArea* lineNumberArea; QString identifierUnderCursor() const; private slots: void insertCompletion(const QString& completion); void highlightCurrentLine(); + void updateLineNumberAreaWidth(); + void updateLineNumberArea(const QRect& rect, int dy); private: QCompleter* m_Completer;