Change the internal data type for cell contents to a binary type

Store the data of a DB cell in a QByteArray, i.e. a binary data type,
instead of putting it in a QString, thus converting it to a UTF8 string.

Rewrite the reading and writing of DB cells to correctly handle binary
data containing 0x00 bytes.

Change the edit dialog to actually do all the data checks etc. on a
currently invisible QHexEdit widget instead of a QTextEdit.

All these changes combined make it possible to actually store binary
data without it being corrupted. You can for example import pictures
now, export them and actually open the exported file. So this is an
improvement.
This commit is contained in:
Martin Kleusberg
2013-03-17 01:38:48 +01:00
parent 0cf9ecd158
commit 6c8712d804
7 changed files with 104 additions and 86 deletions

View File

@@ -4,12 +4,17 @@
#include <QMessageBox>
#include <QFileDialog>
#include "sqlitedb.h"
#include <src/qhexedit.h>
EditDialog::EditDialog(QWidget* parent)
: QDialog(parent),
ui(new Ui::EditDialog)
{
ui->setupUi(this);
hexEdit = new QHexEdit(this);
hexEdit->setVisible(false);
reset();
}
@@ -24,6 +29,7 @@ void EditDialog::reset()
curCol = -1;
ui->editData->setPlainText("");
ui->editData->setFocus();
hexEdit->setData(QByteArray());
setDataType(kSQLiteMediaType_Void, 0);
}
@@ -57,14 +63,15 @@ void EditDialog::closeEvent(QCloseEvent*)
emit goingAway();
}
void EditDialog::loadText(const QString& text, int row, int col)
void EditDialog::loadText(const QByteArray& data, int row, int col)
{
ui->editData->setPlainText(text);
ui->editData->setPlainText(data);
ui->editData->setFocus();
ui->editData->selectAll();
hexEdit->setData(data);
curRow = row;
curCol = col;
if(ui->editData->toPlainText().length() > 0)
if(hexEdit->data().length() > 0)
setDataType(kSQLiteMediaType_String, 0);
else
setDataType(kSQLiteMediaType_Void, 0);
@@ -84,11 +91,12 @@ void EditDialog::importData()
QFile file(fileName);
if(file.open(QIODevice::ReadOnly))
{
QTextStream stream(&file);
ui->editData->setPlainText(stream.readAll());
QByteArray d = file.readAll();
hexEdit->setData(d);
ui->editData->setPlainText(d);
file.close();
}
setDataType(type, ui->editData->toPlainText().length());
setDataType(type, hexEdit->data().length());
}
}
@@ -119,8 +127,7 @@ void EditDialog::exportData()
QFile file(fileName);
if(file.open(QIODevice::WriteOnly))
{
QTextStream stream(&file);
stream << ui->editData->toPlainText();
file.write(hexEdit->data());
file.close();
}
}
@@ -134,13 +141,14 @@ void EditDialog::exportData()
void EditDialog::clearData()
{
ui->editData->setPlainText("");
hexEdit->setData(QByteArray());
setDataType(kSQLiteMediaType_Void, 0);
}
void EditDialog::accept()
{
if(dataType == kSQLiteMediaType_String)
emit updateRecordText(curRow, curCol, ui->editData->toPlainText());
emit updateRecordText(curRow, curCol, hexEdit->data());
if (dataType == kSQLiteMediaType_Void)
emit updateRecordText(curRow, curCol, "");
@@ -150,8 +158,11 @@ void EditDialog::accept()
void EditDialog::editTextChanged()
{
if(ui->editData->hasFocus())
hexEdit->setData(ui->editData->toPlainText().toUtf8());
int newtype = kSQLiteMediaType_String;
if(ui->editData->toPlainText().length() == 0)
if(hexEdit->data().length() == 0)
newtype = kSQLiteMediaType_Void;
setDataType(newtype, ui->editData->toPlainText().length());
setDataType(newtype, hexEdit->data().length());
}

View File

@@ -2,6 +2,7 @@
#define __EDITDIALOG_H__
#include <QDialog>
class QHexEdit;
namespace Ui {
class EditDialog;
@@ -23,7 +24,7 @@ public:
public slots:
virtual void reset();
virtual void loadText(const QString& text, int row, int col);
virtual void loadText(const QByteArray& data, int row, int col);
private slots:
virtual void enableExport(bool enabled);
@@ -37,10 +38,11 @@ private slots:
signals:
void goingAway();
void updateRecordText(int, int, const QString&);
void updateRecordText(int, int, const QByteArray&);
private:
Ui::EditDialog* ui;
QHexEdit* hexEdit;
int dataType;
int dataSize;
int curCol;

View File

@@ -73,7 +73,7 @@ void ExportCsvDialog::accept()
rowList data = pdb->browseRecs;
for(int i=0;i<data.size();i++)
{
QStringList& row = data[i];
QList<QByteArray> row = data[i];
for(int j=1;j<row.size();j++)
{
QString content = row[j];

View File

@@ -105,7 +105,7 @@ void MainWindow::init()
connect(ui->dataTable->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(browseTableHeaderClicked(int)));
connect(ui->dataTable->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(setRecordsetLabel()));
connect(editWin, SIGNAL(goingAway()), this, SLOT(editWinAway()));
connect(editWin, SIGNAL(updateRecordText(int, int , QString)), this, SLOT(updateRecordText(int, int , QString)));
connect(editWin, SIGNAL(updateRecordText(int, int, QByteArray)), this, SLOT(updateRecordText(int, int , QByteArray)));
// Load window settings
QSettings settings(QApplication::organizationName(), QApplication::organizationName());
@@ -449,10 +449,10 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths)
rowLabel.setNum(rowNum+1);
browseTableModel->setVerticalHeaderItem(rowNum, new QStandardItem(rowLabel));
colNum = 0;
QStringList& rt = tab[i];
QList<QByteArray> rt = tab[i];
for (int e = 1; e < rt.size(); ++e)
{
QString& content = rt[e];
QString content = rt[e];
QStandardItem* item = new QStandardItem(content);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
@@ -704,20 +704,19 @@ void MainWindow::helpAbout()
dialog.exec();
}
void MainWindow::updateRecordText(int row, int col, const QString& newtext)
void MainWindow::updateRecordText(int row, int col, const QByteArray& newtext)
{
if (!db.updateRecord(row, col, newtext)){
QMessageBox::information( this, QApplication::applicationName(), tr("Data could not be updated"));
}
rowList tab = db.browseRecs;
QStringList& rt = tab[row];
QString& cv = rt[col+1];//must account for rowid
QList<QByteArray>& rt = tab[row];
QByteArray& cv = rt[col+1];//must account for rowid
QStandardItem* item = new QStandardItem(cv);
QStandardItem* item = new QStandardItem(QString(cv));
item->setToolTip( wrapText(cv) );
browseTableModel->setItem(row, col, item);
}
void MainWindow::editWinAway()
@@ -730,8 +729,8 @@ void MainWindow::editWinAway()
void MainWindow::editText(int row, int col)
{
rowList tab = db.browseRecs;
QStringList& rt = tab[row];
QString cv = rt[col+1];//must account for rowid
QList<QByteArray> rt = tab[row];
QByteArray cv = rt[col+1];//must account for rowid
editWin->loadText(cv , row, col);
editWin->show();

View File

@@ -127,7 +127,7 @@ private slots:
virtual void editTable();
virtual void helpWhatsThis();
virtual void helpAbout();
virtual void updateRecordText( int row, int col, const QString& newtext );
virtual void updateRecordText(int row, int col, const QByteArray& newtext);
virtual void editWinAway();
virtual void editText( int row, int col );
virtual void doubleClickTable(const QModelIndex& index);

View File

@@ -386,8 +386,8 @@ bool DBBrowserDB::deleteRecord( int wrow)
if (!isOpen()) return false;
bool ok = false;
rowList tab = browseRecs;
QStringList& rt = tab[wrow];
QString& rowid = rt[0];
QList<QByteArray> rt = tab[wrow];
QString rowid = rt[0];
lastErrorMessage = QString("no error");
QString statement = QString("DELETE FROM `%1` WHERE rowid=%2;").arg(curBrowseTableName).arg(rowid);
@@ -406,45 +406,52 @@ bool DBBrowserDB::deleteRecord( int wrow)
return ok;
}
bool DBBrowserDB::updateRecord(int wrow, int wcol, const QString & wtext)
bool DBBrowserDB::updateRecord(int wrow, int wcol, const QByteArray& wtext)
{
char * errmsg;
if (!hasValidBrowseSet) return false;
if (!isOpen()) return false;
bool ok = false;
lastErrorMessage = QString("no error");
QStringList& rt = browseRecs[wrow];
QString& rowid = rt[0];
QString& cv = rt[wcol+1];//must account for rowid
QList<QByteArray>& rt = browseRecs[wrow];
QString rowid = rt[0];
QByteArray& cv = rt[wcol+1];//must account for rowid
QString ct = browseFields.at(wcol);
QString statement = QString("UPDATE `%1` SET `%2`=").arg(curBrowseTableName).arg(ct);
QString sql = QString("UPDATE `%1` SET `%2`=? WHERE rowid=%4;").arg(curBrowseTableName).arg(ct).arg(rowid);
char * formSQL = sqlite3_mprintf("%Q", wtext.toUtf8().constData());
statement.append(formSQL);
if (formSQL) sqlite3_free(formSQL);
statement.append(" WHERE rowid=");
statement.append(rowid);
statement.append(";");
logSQL(sql, kLogMsg_App);
setRestorePoint();
if (_db){
logSQL(statement, kLogMsg_App);
setRestorePoint();
if (SQLITE_OK==sqlite3_exec(_db,statement.toUtf8(),
NULL,NULL,&errmsg)){
ok=true;
/*update local copy*/
cv = wtext;
} else {
lastErrorMessage = QString::fromUtf8(errmsg);
qCritical() << "update Record: " << lastErrorMessage;
}
sqlite3_stmt* stmt;
if(sqlite3_prepare(_db, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
{
lastErrorMessage = sqlite3_errmsg(_db);
qCritical() << "updateRecord: " << lastErrorMessage;
return false;
}
if(sqlite3_bind_blob(stmt, 1, wtext.constData(), wtext.length(), SQLITE_STATIC) != SQLITE_OK)
{
lastErrorMessage = sqlite3_errmsg(_db);
qCritical() << "updateRecord: " << lastErrorMessage;
return false;
}
if(sqlite3_step(stmt) != SQLITE_DONE)
{
lastErrorMessage = sqlite3_errmsg(_db);
qCritical() << "updateRecord: " << lastErrorMessage;
return false;
}
if(sqlite3_finalize(stmt) != SQLITE_OK)
{
lastErrorMessage = sqlite3_errmsg(_db);
qCritical() << "updateRecord: " << lastErrorMessage;
return false;
}
return ok;
cv = wtext;
return true;
}
bool DBBrowserDB::browseTable( const QString & tablename, const QString& orderby )
@@ -664,44 +671,43 @@ bool DBBrowserDB::renameTable(const QString& from_table, const QString& to_table
void DBBrowserDB::getTableRecords( const QString & tablename, const QString& orderby )
{
sqlite3_stmt *vm;
const char *tail;
sqlite3_stmt* stmt;
int ncol;
QStringList r;
// char *errmsg;
int err=0;
// int tabnum = 0;
QList<QByteArray> r;
browseRecs.clear();
idmap.clear();
lastErrorMessage = QObject::tr("no error");
QString statement = QString("SELECT rowid, * FROM `%1` ORDER BY %2;").arg(tablename).arg(orderby);
logSQL(statement, kLogMsg_App);
QByteArray utf8Statement = statement.toUtf8();
err=sqlite3_prepare(_db,utf8Statement,utf8Statement.length(),
&vm, &tail);
if (err == SQLITE_OK){
int rownum = 0;
while ( sqlite3_step(vm) == SQLITE_ROW ){
r.clear();
ncol = sqlite3_data_count(vm);
for (int e=0; e<ncol; ++e){
QString rv = QString::fromUtf8((const char*)sqlite3_column_text(vm,e));
r << rv;
if (e==0){
idmap.insert(rv.toInt(),rownum);
rownum++;
}
}
browseRecs.append(r);
}
sqlite3_finalize(vm);
}else{
QString sql = QString("SELECT rowid, * FROM `%1` ORDER BY %2;").arg(tablename).arg(orderby);
logSQL(sql, kLogMsg_App);
if(sqlite3_prepare(_db, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
{
lastErrorMessage = QObject::tr("could not get fields");
return;
}
int rownum = 0;
while(sqlite3_step(stmt) == SQLITE_ROW)
{
r.clear();
ncol = sqlite3_data_count(stmt);
for(int e=0;e<ncol;++e)
{
QByteArray rv = QByteArray(static_cast<const char*>(sqlite3_column_blob(stmt, e)), sqlite3_column_bytes(stmt, e));
r.append(rv);
if(e == 0)
{
idmap.insert(rv.toInt(), rownum);
rownum++;
}
}
browseRecs.append(r);
}
sqlite3_finalize(stmt);
}
resultMap DBBrowserDB::getFindResults( const QString & wstatement)

View File

@@ -26,7 +26,7 @@ typedef QMap<int, class DBBrowserField> fieldMap;
typedef QMultiMap<QString, class DBBrowserObject> objectMap;
typedef QMap<int, int> rowIdMap;
typedef QList<QStringList> rowList;
typedef QList<QList<QByteArray> > rowList;
typedef QMap<int, QString> resultMap;
class DBBrowserField
@@ -97,7 +97,7 @@ public:
void updateSchema() ;
bool addRecord();
bool deleteRecord(int wrow);
bool updateRecord(int wrow, int wcol, const QString & wtext);
bool updateRecord(int wrow, int wcol, const QByteArray& wtext);
bool browseTable( const QString & tablename, const QString& orderby = "rowid" );
bool createTable(const QString& name, const QList<DBBrowserField>& structure);