JSON mode for cell editor

Support for JSON in the Database Cell editor using the QScintilla library.

The lexJSON has been added to the compilation.

See issue #1173
This commit is contained in:
mgrojo
2017-11-18 14:57:36 +01:00
parent 1d701adec7
commit c832d8a58c
7 changed files with 165 additions and 23 deletions

View File

@@ -105,6 +105,7 @@ set(SQLB_MOC_HDR
src/VacuumDialog.h
src/sqlitetablemodel.h
src/sqltextedit.h
src/jsontextedit.h
src/DbStructureModel.h
src/Application.h
src/CipherDialog.h
@@ -139,6 +140,7 @@ set(SQLB_SRC
src/sqlitetablemodel.cpp
src/sqlitetypes.cpp
src/sqltextedit.cpp
src/jsontextedit.cpp
src/csvparser.cpp
src/DbStructureModel.cpp
src/grammar/Sqlite3Lexer.cpp

View File

@@ -22,6 +22,7 @@ set(QSCINTILLA_SRC
qscilexer.cpp
qscilexercustom.cpp
qscilexersql.cpp
qscilexerjson.cpp
qscimacro.cpp
qsciprinter.cpp
qscistyle.cpp
@@ -33,6 +34,7 @@ set(QSCINTILLA_SRC
PlatQt.cpp
ScintillaQt.cpp
../lexers/LexSQL.cpp
../lexers/LexJSON.cpp
../lexlib/Accessor.cpp
../lexlib/CharacterCategory.cpp
../lexlib/CharacterSet.cpp
@@ -143,6 +145,7 @@ set(QSCINTILLA_MOC_HDR
./Qsci/qscilexer.h
./Qsci/qscilexercustom.h
./Qsci/qscilexersql.h
./Qsci/qscilexerjson.h
./Qsci/qscimacro.h
SciClasses.h
ScintillaQt.h

View File

@@ -86,6 +86,7 @@ HEADERS = \
./Qsci/qscilexer.h \
./Qsci/qscilexercustom.h \
./Qsci/qscilexersql.h \
./Qsci/qscilexerjson.h \
./Qsci/qscimacro.h \
./Qsci/qsciprinter.h \
./Qsci/qscistyle.h \
@@ -158,6 +159,7 @@ SOURCES = \
qscilexer.cpp \
qscilexercustom.cpp \
qscilexersql.cpp \
qscilexerjson.cpp \
qscimacro.cpp \
qsciprinter.cpp \
qscistyle.cpp \
@@ -169,6 +171,7 @@ SOURCES = \
PlatQt.cpp \
ScintillaQt.cpp \
../lexers/LexSQL.cpp \
../lexers/LexJSON.cpp \
../lexlib/Accessor.cpp \
../lexlib/CharacterCategory.cpp \
../lexlib/CharacterSet.cpp \

View File

@@ -78,6 +78,7 @@ int Scintilla_LinkLexers() {
//++Autogenerated -- run scripts/LexGen.py to regenerate
//**\(\tLINK_LEXER(\*);\n\)
LINK_LEXER(lmSQL);
LINK_LEXER(lmJSON);
//--Autogenerated -- end of automatically generated section

View File

@@ -31,11 +31,17 @@ EditDialog::EditDialog(QWidget* parent)
hexLayout->addWidget(hexEdit);
hexEdit->setOverwriteMode(false);
QHBoxLayout* jsonLayout = new QHBoxLayout(ui->editorJSON);
jsonEdit = new JsonTextEdit(this);
jsonLayout->addWidget(jsonEdit);
QShortcut* ins = new QShortcut(QKeySequence(Qt::Key_Insert), this);
connect(ins, SIGNAL(activated()), this, SLOT(toggleOverwriteMode()));
connect(ui->editorText, SIGNAL(textChanged()), this, SLOT(updateApplyButton()));
connect(hexEdit, SIGNAL(dataChanged()), this, SLOT(updateApplyButton()));
connect(jsonEdit, SIGNAL(textChanged()), this, SLOT(updateApplyButton()));
connect(jsonEdit, SIGNAL(textChanged()), this, SLOT(editTextChanged()));
reloadSettings();
}
@@ -89,6 +95,9 @@ void EditDialog::loadData(const QByteArray& data)
// Data type specific handling
switch (dataType) {
case Null:
// Set enabled any of the text widgets
ui->editorText->setEnabled(true);
jsonEdit->setEnabled(true);
switch (editMode) {
case TextEditor:
// The text widget buffer is now the main data source
@@ -96,10 +105,19 @@ void EditDialog::loadData(const QByteArray& data)
// Empty the text editor contents, then enable text editing
ui->editorText->clear();
ui->editorText->setEnabled(true);
break;
case JsonEditor:
// The JSON widget buffer is now the main data source
dataSource = JsonBuffer;
// Empty the text editor contents, then enable text editing
jsonEdit->clear();
break;
case HexEditor:
// The hex widget buffer is now the main data source
dataSource = HexBuffer;
@@ -124,6 +142,10 @@ void EditDialog::loadData(const QByteArray& data)
break;
case Text:
// Set enabled any of the text widgets
ui->editorText->setEnabled(true);
jsonEdit->setEnabled(true);
switch (editMode) {
case TextEditor:
// The text widget buffer is now the main data source
@@ -133,14 +155,24 @@ void EditDialog::loadData(const QByteArray& data)
textData = QString::fromUtf8(data.constData(), data.size());
ui->editorText->setPlainText(textData);
// Enable text editing
ui->editorText->setEnabled(true);
// Select all of the text by default
ui->editorText->selectAll();
break;
case JsonEditor:
// The JSON widget buffer is now the main data source
dataSource = JsonBuffer;
// Load the text into the text editor
textData = QString::fromUtf8(data.constData(), data.size());
jsonEdit->setText(textData);
// Select all of the text by default
jsonEdit->selectAll();
break;
case HexEditor:
// The hex widget buffer is now the main data source
dataSource = HexBuffer;
@@ -191,6 +223,12 @@ void EditDialog::loadData(const QByteArray& data)
ui->editorText->setEnabled(false);
break;
case JsonEditor:
// Disable text editing, and use a warning message as the contents
jsonEdit->setText(tr("Image data can't be viewed with the JSON editor"));
jsonEdit->setEnabled(false);
break;
case ImageViewer:
// Load the image into the image viewing widget
if (img.loadFromData(data)) {
@@ -219,6 +257,12 @@ void EditDialog::loadData(const QByteArray& data)
ui->editorText->setEnabled(false);
break;
case JsonEditor:
// Disable text editing, and use a warning message as the contents
jsonEdit->setText(QString(tr("Binary data can't be viewed with the JSON editor")));
jsonEdit->setEnabled(false);
break;
case ImageViewer:
// Clear any image from the image viewing widget
ui->editorImage->setPixmap(QPixmap(0,0));
@@ -281,12 +325,20 @@ void EditDialog::exportData()
QFile file(fileName);
if(file.open(QIODevice::WriteOnly))
{
if (dataSource == HexBuffer) {
switch (dataSource) {
case HexBuffer:
// Data source is the hex buffer
file.write(hexEdit->data());
} else {
break;
case TextBuffer:
// Data source is the text buffer
file.write(ui->editorText->toPlainText().toUtf8());
break;
case JsonBuffer:
// Data source is the JSON buffer
file.write(jsonEdit->text().toUtf8());
break;
}
file.close();
}
@@ -298,16 +350,19 @@ void EditDialog::setNull()
ui->editorText->clear();
ui->editorImage->clear();
hexEdit->setData(QByteArray());
jsonEdit->clear();
dataType = Null;
// Check if in text editor mode
int editMode = ui->editorStack->currentIndex();
if (editMode == TextEditor) {
if (editMode == TextEditor || editMode == JsonEditor) {
// Setting NULL in the text editor switches the data source to it
dataSource = TextBuffer;
// Ensure the text editor is enabled
ui->editorText->setEnabled(true);
// Ensure the JSON editor is enabled
jsonEdit->setEnabled(true);
// The text editor doesn't know the difference between an empty string
// and a NULL, so we need to record NULL outside of that
@@ -331,7 +386,8 @@ void EditDialog::accept()
if(!currentIndex.isValid())
return;
if (dataSource == TextBuffer) {
switch (dataSource) {
case TextBuffer:
// Check if a NULL is set in the text editor
if (textNullSet) {
emit recordTextUpdated(currentIndex, hexEdit->data(), true);
@@ -343,12 +399,28 @@ void EditDialog::accept()
// The data is different, so commit it back to the database
emit recordTextUpdated(currentIndex, newData.toUtf8(), false);
}
} else {
break;
case JsonBuffer:
// Check if a NULL is set in the text editor
if (textNullSet) {
emit recordTextUpdated(currentIndex, hexEdit->data(), true);
} else {
// It's not NULL, so proceed with normal text string checking
QString oldData = currentIndex.data(Qt::EditRole).toString();
QString newData = jsonEdit->text();
if (oldData != newData)
// The data is different, so commit it back to the database
emit recordTextUpdated(currentIndex, newData.toUtf8(), false);
}
break;
case HexBuffer:
// The data source is the hex widget buffer, thus binary data
QByteArray oldData = currentIndex.data(Qt::EditRole).toByteArray();
QByteArray newData = hexEdit->data();
if (newData != oldData)
emit recordTextUpdated(currentIndex, newData, true);
break;
}
}
@@ -356,12 +428,21 @@ void EditDialog::accept()
void EditDialog::editModeChanged(int newMode)
{
// * If the dataSource is the text buffer, the data is always text *
if (dataSource == TextBuffer) {
switch (dataSource) {
case TextBuffer:
switch (newMode) {
case TextEditor: // Switching to the text editor
// Nothing to do, as the text is already in the text buffer
break;
case JsonEditor: // Switching to the JSON editor
// Convert the text widget buffer for the JSON widget
jsonEdit->setText(ui->editorText->toPlainText().toUtf8());
// The JSON widget buffer is now the main data source
dataSource = JsonBuffer;
break;
case HexEditor: // Switching to the hex editor
// Convert the text widget buffer for the hex widget
hexEdit->setData(ui->editorText->toPlainText().toUtf8());
@@ -379,24 +460,56 @@ void EditDialog::editModeChanged(int newMode)
// Switch to the selected editor
ui->editorStack->setCurrentIndex(newMode);
return;
}
break;
case HexBuffer:
// * If the dataSource is the hex buffer, the contents could be anything
// so we just pass it to our loadData() function to handle *
if (dataSource == HexBuffer) {
// * If the dataSource is the hex buffer, the contents could be anything
// so we just pass it to our loadData() function to handle *
// Switch to the selected editor first, as loadData() relies on it
// being current
ui->editorStack->setCurrentIndex(newMode);
// Load the data into the appropriate widget, as done by loadData()
loadData(hexEdit->data());
}
break;
case JsonBuffer:
switch (newMode) {
case TextEditor: // Switching to the text editor
// Convert the text widget buffer for the JSON widget
ui->editorText->setText(jsonEdit->text());
// The Text widget buffer is now the main data source
dataSource = TextBuffer;
break;
case JsonEditor: // Switching to the JSON editor
// Nothing to do, as the text is already in the JSON buffer
break;
case HexEditor: // Switching to the hex editor
// Convert the text widget buffer for the hex widget
hexEdit->setData(jsonEdit->text().toUtf8());
// The hex widget buffer is now the main data source
dataSource = HexBuffer;
break;
case ImageViewer:
// Clear any image from the image viewing widget
ui->editorImage->setPixmap(QPixmap(0,0));
break;
}
// Switch to the selected editor
ui->editorStack->setCurrentIndex(newMode);
}
}
// Called for every keystroke in the text editor (only)
void EditDialog::editTextChanged()
{
if (dataSource == TextBuffer) {
if (dataSource == TextBuffer || dataSource == JsonBuffer) {
// Data has been changed in the text editor, so it can't be a NULL
// any more
textNullSet = false;
@@ -442,6 +555,7 @@ void EditDialog::toggleOverwriteMode()
hexEdit->setOverwriteMode(currentMode);
ui->editorText->setOverwriteMode(currentMode);
jsonEdit->setOverwriteMode(currentMode);
}
void EditDialog::setFocus()
@@ -467,6 +581,7 @@ void EditDialog::setReadOnly(bool ro)
ui->buttonImport->setEnabled(!ro);
ui->editorText->setReadOnly(ro);
ui->editorBinary->setEnabled(!ro); // We disable the entire hex editor here instead of setting it to read only because it doesn't have a setReadOnly() method
jsonEdit->setReadOnly(ro);
}
// Update the information labels in the bottom left corner of the dialog
@@ -544,9 +659,16 @@ QString EditDialog::humanReadableSize(double byteCount) const
void EditDialog::reloadSettings()
{
// Set the font for the text and hex editors
QFont editorFont(Settings::getValue("databrowser", "font").toString());
editorFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
ui->editorText->setFont(editorFont);
hexEdit->setFont(editorFont);
// Set the databrowser font for the text editor but the (SQL) editor
// font for hex editor, since it needs a Monospace font and the
// databrowser font would be usually of variable width.
QFont textFont(Settings::getValue("databrowser", "font").toString());
textFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
ui->editorText->setFont(textFont);
QFont hexFont(Settings::getValue("editor", "font").toString());
hexFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt());
hexEdit->setFont(hexFont);
jsonEdit->reloadSettings();
}

View File

@@ -4,6 +4,8 @@
#include <QDialog>
#include <QPersistentModelIndex>
#include "jsontextedit.h"
class QHexEdit;
namespace Ui {
@@ -47,6 +49,7 @@ signals:
private:
Ui::EditDialog* ui;
QHexEdit* hexEdit;
JsonTextEdit* jsonEdit;
QPersistentModelIndex currentIndex;
int dataSource;
int dataType;
@@ -55,7 +58,8 @@ private:
enum DataSources {
TextBuffer,
HexBuffer
HexBuffer,
JsonBuffer
};
enum DataTypes {
@@ -68,7 +72,8 @@ private:
enum EditModes {
TextEditor = 0,
HexEditor = 1,
ImageViewer = 2
JsonEditor = 2,
ImageViewer = 3
};
int checkDataType(const QByteArray& data);

View File

@@ -47,6 +47,11 @@
<string>Binary</string>
</property>
</item>
<item>
<property name="text">
<string>JSON</string>
</property>
</item>
<item>
<property name="text">
<string>Image</string>
@@ -151,6 +156,7 @@
</layout>
</widget>
<widget class="QWidget" name="editorBinary"/>
<widget class="QWidget" name="editorJSON"/>
<widget class="QScrollArea" name="editorImageScrollArea">
<property name="widgetResizable">
<bool>true</bool>