mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-19 18:40:13 -06:00
Allow setting the default value, the check values and under some circumstances the not null flag when editing existing tables. This required some changes to DBBrowserDB::renameColumn() which is now using some more features of sqlitetypes.cpp but could still be improved.
218 lines
6.8 KiB
C++
218 lines
6.8 KiB
C++
#include "ImportCsvDialog.h"
|
|
#include "ui_ImportCsvDialog.h"
|
|
#include <QMessageBox>
|
|
#include <QProgressDialog>
|
|
#include <QPushButton>
|
|
#include <QDateTime>
|
|
#include "sqlitedb.h"
|
|
|
|
ImportCsvDialog::ImportCsvDialog(const QString& filename, DBBrowserDB* db, QWidget* parent)
|
|
: QDialog(parent),
|
|
ui(new Ui::ImportCsvDialog),
|
|
csvFilename(filename),
|
|
pdb(db)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
checkInput();
|
|
updatePreview();
|
|
}
|
|
|
|
ImportCsvDialog::~ImportCsvDialog()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
namespace {
|
|
void rollback(ImportCsvDialog* dialog, DBBrowserDB* pdb, QProgressDialog& progress, const QString& savepointName)
|
|
{
|
|
progress.hide();
|
|
QApplication::restoreOverrideCursor(); // restore original cursor
|
|
QString error = QObject::tr("Error importing data. Message from database engine: %1").arg(pdb->lastErrorMessage);
|
|
QMessageBox::warning(dialog, QApplication::applicationName(), error);
|
|
pdb->revert(savepointName);
|
|
}
|
|
}
|
|
|
|
void ImportCsvDialog::accept()
|
|
{
|
|
QString sql;
|
|
|
|
// Parse all csv data
|
|
int numfields;
|
|
QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), -1, &numfields);
|
|
|
|
// Can not operate on an empty result
|
|
if(numfields == 0)
|
|
return;
|
|
|
|
// Generate field names. These are either taken from the first CSV row or are generated in the format of "fieldXY" depending on the user input
|
|
QStringList fieldList;
|
|
if(ui->checkboxHeader->isChecked())
|
|
{
|
|
int cfieldnum = 0;
|
|
while(!curList.empty() && cfieldnum != numfields)
|
|
{
|
|
// Remove invalid characters
|
|
QString thisfield = curList.front();
|
|
thisfield.replace(" ", "");
|
|
thisfield.replace('"', "");
|
|
thisfield.replace("'","");
|
|
thisfield.replace(",","");
|
|
thisfield.replace(";","");
|
|
|
|
// Avoid empty field names
|
|
if(thisfield.isEmpty())
|
|
thisfield = QString("field%1").arg(cfieldnum+1);
|
|
|
|
fieldList.push_back(thisfield);
|
|
cfieldnum++;
|
|
curList.pop_front();
|
|
}
|
|
} else {
|
|
for(int i=0;i<numfields;i++)
|
|
fieldList.push_back(QString("field%1").arg(i+1));
|
|
}
|
|
|
|
// Show progress dialog
|
|
QProgressDialog progress(tr("Inserting data..."), tr("Cancel"), 0, curList.size());
|
|
progress.setWindowModality(Qt::ApplicationModal);
|
|
|
|
// declare local variables we will need before the rollback jump
|
|
int colNum = 0;
|
|
|
|
// Are we importing into an existing table?
|
|
bool importToExistingTable = false;
|
|
objectMap objects = pdb->getBrowsableObjects();
|
|
for(objectMap::ConstIterator i=objects.begin();i!=objects.end();++i)
|
|
{
|
|
if(i.value().gettype() == "table" && i.value().getname() == ui->editName->text())
|
|
{
|
|
if(i.value().fldmap.size() != numfields)
|
|
{
|
|
QMessageBox::warning(this, QApplication::applicationName(),
|
|
tr("There is already a table of that name and an import into an existing table is only possible if the number of columns match."));
|
|
return;
|
|
} else {
|
|
if(QMessageBox::question(this, QApplication::applicationName(), tr("There is already a table of that name. Do you want to import the data into it?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
|
|
{
|
|
importToExistingTable = true;
|
|
break;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create a savepoint, so we can rollback in case of any errors during importing
|
|
// db needs to be saved or an error will occur
|
|
QString restorepointName = QString("CSVIMPORT_%1").arg(QDateTime::currentMSecsSinceEpoch());
|
|
if(!pdb->setRestorePoint(restorepointName))
|
|
return rollback(this, pdb, progress, restorepointName);
|
|
|
|
// Create table
|
|
if(!importToExistingTable)
|
|
{
|
|
if(!pdb->createTable(ui->editName->text(), fieldList))
|
|
return rollback(this, pdb, progress, restorepointName);
|
|
}
|
|
|
|
// now lets import all data, one row at a time
|
|
for(int i=0;i<curList.size();++i)
|
|
{
|
|
if(colNum == 0)
|
|
sql = QString("INSERT INTO `%1` VALUES(").arg(ui->editName->text());
|
|
|
|
// need to mprintf here
|
|
char* formSQL = sqlite3_mprintf("%Q", (const char*)curList[i].toUtf8());
|
|
sql.append(formSQL);
|
|
if(formSQL)
|
|
sqlite3_free(formSQL);
|
|
|
|
colNum++;
|
|
if(colNum < numfields)
|
|
{
|
|
sql.append(",");
|
|
} else {
|
|
colNum = 0;
|
|
sql.append(");");
|
|
if(!pdb->executeSQL(sql, false, false))
|
|
return rollback(this, pdb, progress, restorepointName);
|
|
}
|
|
progress.setValue(i);
|
|
if(progress.wasCanceled())
|
|
return rollback(this, pdb, progress, restorepointName);
|
|
}
|
|
|
|
QApplication::restoreOverrideCursor(); // restore original cursor
|
|
QDialog::accept();
|
|
}
|
|
|
|
void ImportCsvDialog::updatePreview()
|
|
{
|
|
// Get preview data
|
|
int numfields;
|
|
int maxrecs = 20;
|
|
QStringList curList = pdb->decodeCSV(csvFilename, currentSeparatorChar(), currentQuoteChar(), maxrecs, &numfields);
|
|
|
|
// Reset preview widget
|
|
ui->tablePreview->clear();
|
|
ui->tablePreview->setColumnCount(numfields);
|
|
|
|
// Exit if there are no lines to preview at all
|
|
if(numfields == 0)
|
|
return;
|
|
|
|
// Use first row as header if necessary
|
|
if(ui->checkboxHeader->isChecked())
|
|
{
|
|
ui->tablePreview->setHorizontalHeaderLabels(curList);
|
|
|
|
// Remove this row to not show it in the data section
|
|
for(int e=0;e<numfields;e++)
|
|
curList.pop_front();
|
|
}
|
|
|
|
// Fill data section
|
|
ui->tablePreview->setRowCount(curList.count() / numfields);
|
|
int rowNum = 0;
|
|
int colNum = 0;
|
|
for(QStringList::Iterator ct=curList.begin();ct!=curList.end();++ct)
|
|
{
|
|
if(colNum == 0)
|
|
ui->tablePreview->setVerticalHeaderItem(rowNum, new QTableWidgetItem(QString::number(rowNum + 1)));
|
|
ui->tablePreview->setItem(rowNum, colNum, new QTableWidgetItem(*ct));
|
|
colNum++;
|
|
if(colNum == numfields)
|
|
{
|
|
colNum = 0;
|
|
rowNum++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImportCsvDialog::checkInput()
|
|
{
|
|
ui->editName->setText(ui->editName->text().trimmed());
|
|
|
|
bool valid = true;
|
|
if(ui->editName->text().isEmpty() || ui->editName->text().contains(" "))
|
|
valid = false;
|
|
|
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
|
|
}
|
|
|
|
char ImportCsvDialog::currentQuoteChar()
|
|
{
|
|
if(ui->comboQuote->currentText().length())
|
|
return ui->comboQuote->currentText().at(0).toAscii();
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
char ImportCsvDialog::currentSeparatorChar()
|
|
{
|
|
return ui->comboSeparator->currentText() == tr("Tab") ? '\t' : ui->comboSeparator->currentText().at(0).toAscii();
|
|
}
|