Refactoring and find/replace dialog in the JSON editor.

SQL and JSON text editor classes have been refactored. A new parent class
for both editors have been added for the common logic implementable without
depending on the specific lexer.

The only visible effect of this change should be that the JSON editor
(issue #1173) now has the same find/replace dialog as the SQL editor.

This prepares for the implementation of the XML editor (issue #1253).
This commit is contained in:
mgrojo
2017-12-16 00:09:47 +01:00
parent de260d32c5
commit 8896ecca40
10 changed files with 308 additions and 405 deletions
+2
View File
@@ -121,6 +121,7 @@ set(SQLB_MOC_HDR
src/RemoteModel.h
src/RemotePushDialog.h
src/FindReplaceDialog.h
src/ExtendedScintilla.h
)
set(SQLB_SRC
@@ -161,6 +162,7 @@ set(SQLB_SRC
src/RemoteModel.cpp
src/RemotePushDialog.cpp
src/FindReplaceDialog.cpp
src/ExtendedScintilla.cpp
)
set(SQLB_FORMS
+222
View File
@@ -0,0 +1,222 @@
#include "ExtendedScintilla.h"
#include "FindReplaceDialog.h"
#include "Settings.h"
#include "Qsci/qscilexer.h"
#include <QFile>
#include <QDropEvent>
#include <QUrl>
#include <QMimeData>
#include <QShortcut>
#include <QAction>
#include <QMenu>
#include <cmath>
ExtendedScintilla::ExtendedScintilla(QWidget* parent) :
QsciScintilla(parent),
findReplaceDialog(new FindReplaceDialog(this))
{
// This class does not set any lexer, that must be done in the child classes.
// Enable UTF8
setUtf8(true);
// Enable brace matching
setBraceMatching(QsciScintilla::SloppyBraceMatch);
// Enable auto indentation
setAutoIndent(true);
// Enable folding
setFolding(QsciScintilla::BoxedTreeFoldStyle);
// Create error indicator
errorIndicatorNumber = indicatorDefine(QsciScintilla::SquiggleIndicator);
setIndicatorForegroundColor(Qt::red, errorIndicatorNumber);
// Set a sensible scroll width, so the scroll bar is avoided in
// most cases.
setScrollWidth(80);
// Scroll width is adjusted to ensure that all of the lines
// currently displayed can be completely scrolled. This mode never
// adjusts the scroll width to be narrower.
setScrollWidthTracking(true);
// Connect signals
connect(this, SIGNAL(linesChanged()), this, SLOT(updateLineNumberAreaWidth()));
// The shortcut is constrained to the Widget context so it does not conflict with other SqlTextEdit widgets in the Main Window.
QShortcut* shortcutFindReplace = new QShortcut(QKeySequence(tr("Ctrl+H")), this, nullptr, nullptr, Qt::WidgetShortcut);
connect(shortcutFindReplace, SIGNAL(activated()), this, SLOT(openFindReplaceDialog()));
// Prepare for adding the find/replace option to the QScintilla context menu
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint &)));
}
ExtendedScintilla::~ExtendedScintilla()
{
}
void ExtendedScintilla::updateLineNumberAreaWidth()
{
// Calculate number of digits of the current number of lines
int digits = std::floor(std::log10(lines())) + 1;
// Calculate the width of this number if it was all zeros (this is because a 1 might require less space than a 0 and this could
// cause some flickering depending on the font) and set the new margin width.
QFont font = lexer()->defaultFont();
setMarginWidth(0, QFontMetrics(font).width(QString("0").repeated(digits)) + 5);
}
void ExtendedScintilla::dropEvent(QDropEvent* e)
{
QList<QUrl> urls = e->mimeData()->urls();
if(urls.isEmpty())
return QsciScintilla::dropEvent(e);
QString file = urls.first().toLocalFile();
if(!QFile::exists(file))
return;
QFile f(file);
f.open(QIODevice::ReadOnly);
setText(f.readAll());
f.close();
}
void ExtendedScintilla::setupSyntaxHighlightingFormat(const QString& settings_name, int style)
{
lexer()->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style);
QFont font(Settings::getValue("editor", "font").toString());
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
font.setBold(Settings::getValue("syntaxhighlighter", settings_name + "_bold").toBool());
font.setItalic(Settings::getValue("syntaxhighlighter", settings_name + "_italic").toBool());
font.setUnderline(Settings::getValue("syntaxhighlighter", settings_name + "_underline").toBool());
lexer()->setFont(font, style);
}
void ExtendedScintilla::reloadKeywords()
{
// Set lexer again to reload the updated keywords list
setLexer(lexer());
}
void ExtendedScintilla::reloadSettings()
{
// Enable auto completion if it hasn't been disabled
if(Settings::getValue("editor", "auto_completion").toBool())
{
setAutoCompletionThreshold(3);
setAutoCompletionCaseSensitivity(true);
setAutoCompletionShowSingle(true);
setAutoCompletionSource(QsciScintilla::AcsAPIs);
} else {
setAutoCompletionThreshold(0);
}
// Set syntax highlighting settings
QFont defaultfont(Settings::getValue("editor", "font").toString());
defaultfont.setStyleHint(QFont::TypeWriter);
defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt());
lexer()->setDefaultColor(Qt::black);
lexer()->setFont(defaultfont);
// Set font
QFont font(Settings::getValue("editor", "font").toString());
font.setStyleHint(QFont::TypeWriter);
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
setFont(font);
// Show line numbers
QFont marginsfont(QFont(Settings::getValue("editor", "font").toString()));
marginsfont.setPointSize(font.pointSize());
setMarginsFont(marginsfont);
setMarginLineNumbers(0, true);
setMarginsBackgroundColor(Qt::lightGray);
updateLineNumberAreaWidth();
// Highlight current line
setCaretLineVisible(true);
setCaretLineBackgroundColor(QColor(Settings::getValue("syntaxhighlighter", "currentline_colour").toString()));
// Set tab width
setTabWidth(Settings::getValue("editor", "tabsize").toInt());
lexer()->refreshProperties();
// Check if error indicators are enabled and clear them if they just got disabled
showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool();
if(!showErrorIndicators)
clearErrorIndicators();
}
void ExtendedScintilla::clearErrorIndicators()
{
// Clear any error indicators from position (0,0) to the last column of the last line
clearIndicatorRange(0, 0, lines(), lineLength(lines()), errorIndicatorNumber);
}
void ExtendedScintilla::setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex)
{
// Set error indicator for the specified range but only if they're enabled
if(showErrorIndicators)
fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, errorIndicatorNumber);
}
void ExtendedScintilla::setErrorIndicator(int position)
{
// Set error indicator for the position until end of line, but only if they're enabled
if(showErrorIndicators) {
int column = SendScintilla(QsciScintillaBase::SCI_GETCOLUMN, position);
int line = SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, position);
fillIndicatorRange(line, column, line+1, 0, errorIndicatorNumber);
}
}
bool ExtendedScintilla::findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward) {
// For finding the previous occurrence, we need to skip the current
// selection, otherwise we'd always found the same occurrence.
if (!forward && hasSelectedText()) {
int lineFrom, indexFrom;
int lineTo, indexTo;
getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo);
setCursorPosition(lineFrom, indexFrom);
}
return findFirst(text, regexp, caseSensitive, words, wrap, forward);
}
void ExtendedScintilla::clearSelection()
{
setSelection(-1,-1,-1,-1);
}
void ExtendedScintilla::openFindReplaceDialog()
{
findReplaceDialog->setExtendedScintilla(this);
findReplaceDialog->show();
}
void ExtendedScintilla::showContextMenu(const QPoint &pos)
{
QAction* findReplaceAction = new QAction(QIcon(":/icons/text_replace"), tr("Find and Replace..."), this);
findReplaceAction->setShortcut(QKeySequence(tr("Ctrl+H")));
connect(findReplaceAction, &QAction::triggered, [&]() {
openFindReplaceDialog();
});
// This has to be created here, otherwise the set of enabled options would not update accordingly.
QMenu* editContextMenu = createStandardContextMenu();
editContextMenu->addSeparator();
editContextMenu->addAction(findReplaceAction);
editContextMenu->exec(mapToGlobal(pos));
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef EXTENDEDSCINTILLA_H
#define EXTENDEDSCINTILLA_H
#include "Qsci/qsciscintilla.h"
class FindReplaceDialog;
/**
* @brief The ExtendedScintilla class
* This class extends the QScintilla widget for the application
*/
class ExtendedScintilla : public QsciScintilla
{
Q_OBJECT
public:
explicit ExtendedScintilla(QWidget *parent = nullptr);
virtual ~ExtendedScintilla();
bool findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward);
void clearSelection();
public slots:
void reloadKeywords();
void reloadSettings();
void clearErrorIndicators();
void setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex);
// Set error indicator from position to end of line
void setErrorIndicator(int position);
void openFindReplaceDialog();
protected:
void dropEvent(QDropEvent* e);
void setupSyntaxHighlightingFormat(const QString& settings_name, int style);
int errorIndicatorNumber;
bool showErrorIndicators;
FindReplaceDialog* findReplaceDialog;
private slots:
void updateLineNumberAreaWidth();
void showContextMenu(const QPoint &pos);
};
#endif
+20 -19
View File
@@ -17,28 +17,28 @@ FindReplaceDialog::~FindReplaceDialog()
delete ui;
}
void FindReplaceDialog::setSqlTextEdit(SqlTextEdit* sqlTextEdit)
void FindReplaceDialog::setExtendedScintilla(ExtendedScintilla* scintilla)
{
m_sqlTextEdit = sqlTextEdit;
m_scintilla = scintilla;
// Create indicator for find-all and replace-all occurrences
foundIndicatorNumber = m_sqlTextEdit->indicatorDefine(QsciScintilla::StraightBoxIndicator);
m_sqlTextEdit->setIndicatorForegroundColor(Qt::magenta, foundIndicatorNumber);
m_sqlTextEdit->setIndicatorDrawUnder(true, foundIndicatorNumber);
foundIndicatorNumber = m_scintilla->indicatorDefine(QsciScintilla::StraightBoxIndicator);
m_scintilla->setIndicatorForegroundColor(Qt::magenta, foundIndicatorNumber);
m_scintilla->setIndicatorDrawUnder(true, foundIndicatorNumber);
bool isWriteable = ! m_sqlTextEdit->isReadOnly();
bool isWriteable = ! m_scintilla->isReadOnly();
ui->replaceWithText->setEnabled(isWriteable);
ui->replaceButton->setEnabled(isWriteable);
ui->replaceAllButton->setEnabled(isWriteable);
connect(m_sqlTextEdit, SIGNAL(destroyed()), this, SLOT(hide()));
connect(m_scintilla, SIGNAL(destroyed()), this, SLOT(hide()));
}
bool FindReplaceDialog::findNext()
{
clearIndicators();
bool found = m_sqlTextEdit->findText
bool found = m_scintilla->findText
(ui->findText->text(),
ui->regexpCheckBox->isChecked(),
ui->caseCheckBox->isChecked(),
@@ -61,23 +61,23 @@ void FindReplaceDialog::show()
void FindReplaceDialog::replace()
{
m_sqlTextEdit->replace(ui->replaceWithText->text());
m_scintilla->replace(ui->replaceWithText->text());
findNext();
}
void FindReplaceDialog::indicateSelection()
{
int fromRow, fromIndex, toRow, toIndex;
m_sqlTextEdit->getSelection(&fromRow, &fromIndex, &toRow, &toIndex);
m_sqlTextEdit->fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, foundIndicatorNumber);
m_scintilla->getSelection(&fromRow, &fromIndex, &toRow, &toIndex);
m_scintilla->fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, foundIndicatorNumber);
}
void FindReplaceDialog::findAll()
{
clearIndicators();
int occurrences = 0;
m_sqlTextEdit->setCursorPosition(0, 0);
while (m_sqlTextEdit->findText
m_scintilla->setCursorPosition(0, 0);
while (m_scintilla->findText
(ui->findText->text(),
ui->regexpCheckBox->isChecked(),
ui->caseCheckBox->isChecked(),
@@ -87,7 +87,7 @@ void FindReplaceDialog::findAll()
indicateSelection();
++occurrences;
}
m_sqlTextEdit->clearSelection();
m_scintilla->clearSelection();
QString message;
switch (occurrences) {
@@ -109,19 +109,19 @@ void FindReplaceDialog::replaceAll()
{
clearIndicators();
int occurrences = 0;
m_sqlTextEdit->setCursorPosition(0, 0);
while (m_sqlTextEdit->findText
m_scintilla->setCursorPosition(0, 0);
while (m_scintilla->findText
(ui->findText->text(),
ui->regexpCheckBox->isChecked(),
ui->caseCheckBox->isChecked(),
ui->wholeWordsCheckBox->isChecked(),
false,
true)) {
m_sqlTextEdit->replace(ui->replaceWithText->text());
m_scintilla->replace(ui->replaceWithText->text());
indicateSelection();
++occurrences;
}
m_sqlTextEdit->clearSelection();
m_scintilla->clearSelection();
QString message;
switch (occurrences) {
@@ -147,12 +147,13 @@ void FindReplaceDialog::help()
void FindReplaceDialog::clearIndicators()
{
m_sqlTextEdit->clearIndicatorRange(0, 0, m_sqlTextEdit->lines(), m_sqlTextEdit->lineLength(m_sqlTextEdit->lines()), foundIndicatorNumber);
m_scintilla->clearIndicatorRange(0, 0, m_scintilla->lines(), m_scintilla->lineLength(m_scintilla->lines()), foundIndicatorNumber);
ui->messageLabel->setText("");
}
void FindReplaceDialog::close()
{
m_scintilla->clearSelection();
clearIndicators();
QDialog::close();
}
+3 -3
View File
@@ -1,7 +1,7 @@
#ifndef FindReplaceDialog_H
#define FindReplaceDialog_H
#include <sqltextedit.h>
#include <ExtendedScintilla.h>
#include <QDialog>
#include <QAbstractButton>
@@ -18,7 +18,7 @@ public:
explicit FindReplaceDialog(QWidget* parent = nullptr);
~FindReplaceDialog();
void setSqlTextEdit(SqlTextEdit* sqlTextEdit);
void setExtendedScintilla(ExtendedScintilla* scintilla);
void show();
private slots:
@@ -35,7 +35,7 @@ private:
void indicateSelection();
void clearIndicators();
Ui::FindReplaceDialog* ui;
SqlTextEdit* m_sqlTextEdit;
ExtendedScintilla* m_scintilla;
int foundIndicatorNumber;
};
+3 -149
View File
@@ -1,125 +1,32 @@
#include "jsontextedit.h"
#include "Settings.h"
#include <QFile>
#include <QDropEvent>
#include <QUrl>
#include <QMimeData>
#include <QDebug>
#include <cmath>
QsciLexerJSON* JsonTextEdit::jsonLexer = nullptr;
JsonTextEdit::JsonTextEdit(QWidget* parent) :
QsciScintilla(parent)
ExtendedScintilla(parent)
{
// Create lexer object if not done yet
if(jsonLexer == nullptr)
jsonLexer = new QsciLexerJSON(this);
// Set the lexer
// Set the JSON lexer
setLexer(jsonLexer);
// Enable UTF8
setUtf8(true);
// Enable brace matching
setBraceMatching(QsciScintilla::SloppyBraceMatch);
// Enable auto indentation
setAutoIndent(true);
// Enable folding
setFolding(QsciScintilla::BoxedTreeFoldStyle);
jsonLexer->setFoldCompact(false);
// Create error indicator
errorIndicatorNumber = indicatorDefine(QsciScintilla::SquiggleIndicator);
setIndicatorForegroundColor(Qt::red, errorIndicatorNumber);
// Set a sensible scroll width, so the scroll bar is avoided in
// most cases.
setScrollWidth(80);
// Scroll width is adjusted to ensure that all of the lines
// currently displayed can be completely scrolled. This mode never
// adjusts the scroll width to be narrower.
setScrollWidthTracking(true);
// Do rest of initialisation
reloadSettings();
// Connect signals
connect(this, SIGNAL(linesChanged()), this, SLOT(updateLineNumberAreaWidth()));
}
JsonTextEdit::~JsonTextEdit()
{
}
void JsonTextEdit::updateLineNumberAreaWidth()
{
// Calculate number of digits of the current number of lines
int digits = std::floor(std::log10(lines())) + 1;
// Calculate the width of this number if it was all zeros (this is because a 1 might require less space than a 0 and this could
// cause some flickering depending on the font) and set the new margin width.
QFont font = lexer()->font(QsciLexerJSON::Default);
setMarginWidth(0, QFontMetrics(font).width(QString("0").repeated(digits)) + 5);
}
void JsonTextEdit::dropEvent(QDropEvent* e)
{
QList<QUrl> urls = e->mimeData()->urls();
if(urls.isEmpty())
return QsciScintilla::dropEvent(e);
QString file = urls.first().toLocalFile();
if(!QFile::exists(file))
return;
QFile f(file);
f.open(QIODevice::ReadOnly);
setText(f.readAll());
f.close();
}
void JsonTextEdit::setupSyntaxHighlightingFormat(const QString& settings_name, int style)
{
jsonLexer->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style);
QFont font(Settings::getValue("editor", "font").toString());
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
font.setBold(Settings::getValue("syntaxhighlighter", settings_name + "_bold").toBool());
font.setItalic(Settings::getValue("syntaxhighlighter", settings_name + "_italic").toBool());
font.setUnderline(Settings::getValue("syntaxhighlighter", settings_name + "_underline").toBool());
jsonLexer->setFont(font, style);
}
void JsonTextEdit::reloadKeywords()
{
// Set lexer again to reload the updated keywords list
setLexer(lexer());
}
void JsonTextEdit::reloadSettings()
{
// Enable auto completion if it hasn't been disabled
if(Settings::getValue("editor", "auto_completion").toBool())
{
setAutoCompletionThreshold(3);
setAutoCompletionCaseSensitivity(true);
setAutoCompletionShowSingle(true);
setAutoCompletionSource(QsciScintilla::AcsAPIs);
} else {
setAutoCompletionThreshold(0);
}
ExtendedScintilla::reloadSettings();
// Set syntax highlighting settings
QFont defaultfont(Settings::getValue("editor", "font").toString());
defaultfont.setStyleHint(QFont::TypeWriter);
defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt());
jsonLexer->setFont(defaultfont);
setupSyntaxHighlightingFormat("comment", QsciLexerJSON::CommentLine);
setupSyntaxHighlightingFormat("comment", QsciLexerJSON::CommentBlock);
setupSyntaxHighlightingFormat("keyword", QsciLexerJSON::Keyword);
@@ -144,57 +51,4 @@ void JsonTextEdit::reloadSettings()
jsonLexer->setFont(errorFont, QsciLexerJSON::UnclosedString);
jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error);
jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString);
// Set font
QFont font(Settings::getValue("editor", "font").toString());
font.setStyleHint(QFont::TypeWriter);
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
setFont(font);
// Show line numbers
QFont marginsfont(QFont(Settings::getValue("editor", "font").toString()));
marginsfont.setPointSize(font.pointSize());
setMarginsFont(marginsfont);
setMarginLineNumbers(0, true);
setMarginsBackgroundColor(Qt::lightGray);
updateLineNumberAreaWidth();
// Highlight current line
setCaretLineVisible(true);
setCaretLineBackgroundColor(QColor(Settings::getValue("syntaxhighlighter", "currentline_colour").toString()));
// Set tab width
setTabWidth(Settings::getValue("editor", "tabsize").toInt());
jsonLexer->refreshProperties();
// Check if error indicators are enabled and clear them if they just got disabled
showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool();
if(!showErrorIndicators)
clearErrorIndicators();
}
void JsonTextEdit::clearErrorIndicators()
{
// Clear any error indicators from position (0,0) to the last column of the last line
clearIndicatorRange(0, 0, lines(), lineLength(lines()), errorIndicatorNumber);
}
void JsonTextEdit::setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex)
{
// Set error indicator for the specified range but only if they're enabled
if(showErrorIndicators)
fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, errorIndicatorNumber);
}
void JsonTextEdit::setErrorIndicator(int position)
{
// Set error indicator for the position until end of line, but only if they're enabled
if(showErrorIndicators) {
int column = SendScintilla(QsciScintillaBase::SCI_GETCOLUMN, position);
int line = SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, position);
fillIndicatorRange(line, column, line+1, 0, errorIndicatorNumber);
}
}
+3 -20
View File
@@ -1,14 +1,14 @@
#ifndef JSONTEXTEDIT_H
#define JSONTEXTEDIT_H
#include "Qsci/qsciscintilla.h"
#include "ExtendedScintilla.h"
#include <Qsci/qscilexerjson.h>
/**
* @brief The JsonTextEdit class
* This class is based on the QScintilla widget
* This class is based on our Extended QScintilla widget
*/
class JsonTextEdit : public QsciScintilla
class JsonTextEdit : public ExtendedScintilla
{
Q_OBJECT
@@ -19,24 +19,7 @@ public:
static QsciLexerJSON* jsonLexer;
public slots:
void reloadKeywords();
void reloadSettings();
void clearErrorIndicators();
void setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex);
// Set error indicator from position to end of line
void setErrorIndicator(int position);
protected:
void dropEvent(QDropEvent* e);
private:
void setupSyntaxHighlightingFormat(const QString& settings_name, int style);
int errorIndicatorNumber;
bool showErrorIndicators;
private slots:
void updateLineNumberAreaWidth();
};
#endif
+3 -191
View File
@@ -1,28 +1,17 @@
#include "sqltextedit.h"
#include "Settings.h"
#include "SqlUiLexer.h"
#include "FindReplaceDialog.h"
#include <QFile>
#include <QDropEvent>
#include <QUrl>
#include <QMimeData>
#include <QShortcut>
#include <QAction>
#include <QMenu>
#include <cmath>
SqlUiLexer* SqlTextEdit::sqlLexer = nullptr;
SqlTextEdit::SqlTextEdit(QWidget* parent) :
QsciScintilla(parent),
findReplaceDialog(new FindReplaceDialog(this))
ExtendedScintilla(parent)
{
// Create lexer object if not done yet
if(sqlLexer == nullptr)
sqlLexer = new SqlUiLexer(this);
// Set the lexer
// Set the SQL lexer
setLexer(sqlLexer);
// Set icons for auto completion
@@ -31,114 +20,18 @@ SqlTextEdit::SqlTextEdit(QWidget* parent) :
registerImage(SqlUiLexer::ApiCompleterIconIdTable, QImage(":/icons/table"));
registerImage(SqlUiLexer::ApiCompleterIconIdColumn, QImage(":/icons/field"));
// Enable UTF8
setUtf8(true);
// Enable brace matching
setBraceMatching(QsciScintilla::SloppyBraceMatch);
// Enable auto indentation
setAutoIndent(true);
// Enable folding
setFolding(QsciScintilla::BoxedTreeFoldStyle);
// Create error indicator
errorIndicatorNumber = indicatorDefine(QsciScintilla::SquiggleIndicator);
setIndicatorForegroundColor(Qt::red, errorIndicatorNumber);
// Set a sensible scroll width, so the scroll bar is avoided in
// most cases.
setScrollWidth(80);
// Scroll width is adjusted to ensure that all of the lines
// currently displayed can be completely scrolled. This mode never
// adjusts the scroll width to be narrower.
setScrollWidthTracking(true);
// Do rest of initialisation
reloadSettings();
// Connect signals
connect(this, SIGNAL(linesChanged()), this, SLOT(updateLineNumberAreaWidth()));
// The shortcut is constrained to the Widget context so it does not conflict with other SqlTextEdit widgets in the Main Window.
QShortcut* shortcutFindReplace = new QShortcut(QKeySequence(tr("Ctrl+H")), this, nullptr, nullptr, Qt::WidgetShortcut);
connect(shortcutFindReplace, SIGNAL(activated()), this, SLOT(openFindReplaceDialog()));
// Prepare for adding the find/replace option to the QScintilla context menu
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint &)));
}
SqlTextEdit::~SqlTextEdit()
{
}
void SqlTextEdit::updateLineNumberAreaWidth()
{
// Calculate number of digits of the current number of lines
int digits = std::floor(std::log10(lines())) + 1;
// Calculate the width of this number if it was all zeros (this is because a 1 might require less space than a 0 and this could
// cause some flickering depending on the font) and set the new margin width.
QFont font = lexer()->font(QsciLexerSQL::Default);
setMarginWidth(0, QFontMetrics(font).width(QString("0").repeated(digits)) + 5);
}
void SqlTextEdit::dropEvent(QDropEvent* e)
{
QList<QUrl> urls = e->mimeData()->urls();
if(urls.isEmpty())
return QsciScintilla::dropEvent(e);
QString file = urls.first().toLocalFile();
if(!QFile::exists(file))
return;
QFile f(file);
f.open(QIODevice::ReadOnly);
setText(f.readAll());
f.close();
}
void SqlTextEdit::setupSyntaxHighlightingFormat(const QString& settings_name, int style)
{
sqlLexer->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style);
QFont font(Settings::getValue("editor", "font").toString());
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
font.setBold(Settings::getValue("syntaxhighlighter", settings_name + "_bold").toBool());
font.setItalic(Settings::getValue("syntaxhighlighter", settings_name + "_italic").toBool());
font.setUnderline(Settings::getValue("syntaxhighlighter", settings_name + "_underline").toBool());
sqlLexer->setFont(font, style);
}
void SqlTextEdit::reloadKeywords()
{
// Set lexer again to reload the updated keywords list
setLexer(lexer());
}
void SqlTextEdit::reloadSettings()
{
// Enable auto completion if it hasn't been disabled
if(Settings::getValue("editor", "auto_completion").toBool())
{
setAutoCompletionThreshold(3);
setAutoCompletionCaseSensitivity(false);
setAutoCompletionShowSingle(true);
setAutoCompletionSource(QsciScintilla::AcsAPIs);
} else {
setAutoCompletionThreshold(0);
}
ExtendedScintilla::reloadSettings();
// Set syntax highlighting settings
QFont defaultfont(Settings::getValue("editor", "font").toString());
defaultfont.setStyleHint(QFont::TypeWriter);
defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt());
sqlLexer->setColor(Qt::black, QsciLexerSQL::Default);
sqlLexer->setFont(defaultfont);
setupSyntaxHighlightingFormat("comment", QsciLexerSQL::Comment);
setupSyntaxHighlightingFormat("comment", QsciLexerSQL::CommentLine);
setupSyntaxHighlightingFormat("comment", QsciLexerSQL::CommentDoc);
@@ -149,85 +42,4 @@ void SqlTextEdit::reloadSettings()
setupSyntaxHighlightingFormat("string", QsciLexerSQL::SingleQuotedString);
setupSyntaxHighlightingFormat("identifier", QsciLexerSQL::Identifier);
setupSyntaxHighlightingFormat("identifier", QsciLexerSQL::QuotedIdentifier);
// Set font
QFont font(Settings::getValue("editor", "font").toString());
font.setStyleHint(QFont::TypeWriter);
font.setPointSize(Settings::getValue("editor", "fontsize").toInt());
setFont(font);
// Show line numbers
QFont marginsfont(QFont(Settings::getValue("editor", "font").toString()));
marginsfont.setPointSize(font.pointSize());
setMarginsFont(marginsfont);
setMarginLineNumbers(0, true);
setMarginsBackgroundColor(Qt::lightGray);
updateLineNumberAreaWidth();
// Highlight current line
setCaretLineVisible(true);
setCaretLineBackgroundColor(QColor(Settings::getValue("syntaxhighlighter", "currentline_colour").toString()));
// Set tab width
setTabWidth(Settings::getValue("editor", "tabsize").toInt());
// Check if error indicators are enabled and clear them if they just got disabled
showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool();
if(!showErrorIndicators)
clearErrorIndicators();
}
void SqlTextEdit::clearErrorIndicators()
{
// Clear any error indicators from position (0,0) to the last column of the last line
clearIndicatorRange(0, 0, lines(), lineLength(lines()), errorIndicatorNumber);
}
void SqlTextEdit::setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex)
{
// Set error indicator for the specified range but only if they're enabled
if(showErrorIndicators)
fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, errorIndicatorNumber);
}
bool SqlTextEdit::findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward) {
// For finding the previous occurrence, we need to skip the current
// selection, otherwise we'd always found the same occurrence.
if (!forward && hasSelectedText()) {
int lineFrom, indexFrom;
int lineTo, indexTo;
getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo);
setCursorPosition(lineFrom, indexFrom);
}
return findFirst(text, regexp, caseSensitive, words, wrap, forward);
}
void SqlTextEdit::clearSelection()
{
setSelection(-1,-1,-1,-1);
}
void SqlTextEdit::openFindReplaceDialog()
{
findReplaceDialog->setSqlTextEdit(this);
findReplaceDialog->show();
}
void SqlTextEdit::showContextMenu(const QPoint &pos)
{
QAction* findReplaceAction = new QAction(QIcon(":/icons/text_replace"), tr("Find and Replace..."), this);
findReplaceAction->setShortcut(QKeySequence(tr("Ctrl+H")));
connect(findReplaceAction, &QAction::triggered, [&]() {
openFindReplaceDialog();
});
// This has to be created here, otherwise the set of enabled options would not update accordingly.
QMenu* editContextMenu = createStandardContextMenu();
editContextMenu->addSeparator();
editContextMenu->addAction(findReplaceAction);
editContextMenu->exec(mapToGlobal(pos));
}
+2 -21
View File
@@ -1,7 +1,7 @@
#ifndef SQLTEXTEDIT_H
#define SQLTEXTEDIT_H
#include "Qsci/qsciscintilla.h"
#include "ExtendedScintilla.h"
class FindReplaceDialog;
class SqlUiLexer;
@@ -10,7 +10,7 @@ class SqlUiLexer;
* @brief The SqlTextEdit class
* This class is based on the QScintilla widget
*/
class SqlTextEdit : public QsciScintilla
class SqlTextEdit : public ExtendedScintilla
{
Q_OBJECT
@@ -18,30 +18,11 @@ public:
explicit SqlTextEdit(QWidget *parent = nullptr);
virtual ~SqlTextEdit();
bool findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward);
void clearSelection();
static SqlUiLexer* sqlLexer;
public slots:
void reloadKeywords();
void reloadSettings();
void clearErrorIndicators();
void setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex);
void openFindReplaceDialog();
protected:
void dropEvent(QDropEvent* e);
private:
void setupSyntaxHighlightingFormat(const QString& settings_name, int style);
int errorIndicatorNumber;
bool showErrorIndicators;
FindReplaceDialog* findReplaceDialog;
private slots:
void updateLineNumberAreaWidth();
void showContextMenu(const QPoint &pos);
};
#endif
+4 -2
View File
@@ -60,7 +60,8 @@ HEADERS += \
RemoteModel.h \
RemotePushDialog.h \
jsontextedit.h \
FindReplaceDialog.h
FindReplaceDialog.h \
ExtendedScintilla.h
SOURCES += \
sqlitedb.cpp \
@@ -98,7 +99,8 @@ SOURCES += \
RemoteModel.cpp \
RemotePushDialog.cpp \
jsontextedit.cpp \
FindReplaceDialog.cpp
FindReplaceDialog.cpp \
ExtendedScintilla.cpp
RESOURCES += icons/icons.qrc \
translations/flags/flags.qrc \