475 lines
12 KiB
C++
Executable File
475 lines
12 KiB
C++
Executable File
#include "ui_QueryUi.h"
|
|
|
|
#include "Query.h"
|
|
#include "QueryThread.h"
|
|
#include "AddLine.h"
|
|
|
|
#include <QMessageBox>
|
|
#include <QFileDialog>
|
|
#include <QCheckBox>
|
|
#include <QRadioButton>
|
|
#include <QDebug>
|
|
|
|
#ifdef Q_OS_WIN
|
|
#define NEWLINE "\r\n"
|
|
#else
|
|
#define NEWLINE "\n"
|
|
#endif
|
|
|
|
Query::Query(//const QString &queryString,
|
|
QueryWorker *queryWorker,
|
|
QWidget* parent) // MV[C]
|
|
: QWidget(parent)
|
|
, m_ui(new Ui::Query)
|
|
, m_model(new DataModel())
|
|
, m_queryWorker(queryWorker)
|
|
, m_addLines(nullptr)
|
|
{
|
|
m_ui->setupUi(this);
|
|
|
|
setCustomQuery(); // for safety, disable table sensitive buttons, until table name is set
|
|
|
|
qRegisterMetaType<QList<QModelIndex>>("QList<QModelIndex>");
|
|
|
|
|
|
connect(m_ui->pbQueryDelete, &QPushButton::clicked, this, &Query::onQueryDelete);
|
|
connect(m_ui->pbQueryInsert, &QPushButton::clicked, this, &Query::onQueryInsert);
|
|
connect(m_ui->pbQueryUpdate, &QPushButton::clicked, this, &Query::onQueryUpdate);
|
|
|
|
// NEW ARCH
|
|
// Delete Lines
|
|
connect(this, &Query::signalDeleteLines,
|
|
queryWorker, &QueryWorker::slotDeleteLines); // request => QueryWorker
|
|
|
|
connect(queryWorker, &QueryWorker::signalDeleteLinesResult,
|
|
this, &Query::slotDeleteLinesResult); // reply => this
|
|
|
|
|
|
// Custom Query
|
|
connect(this, &Query::signalCustomQuery,
|
|
queryWorker, &QueryWorker::slotCustomQuery);
|
|
|
|
connect(queryWorker, &QueryWorker::signalCustomQueryResult,
|
|
this, &Query::slotCustomQueryResult);
|
|
|
|
|
|
// Table Query
|
|
connect(this, &Query::signalTableQuery,
|
|
queryWorker, &QueryWorker::slotTableQuery);
|
|
|
|
connect(queryWorker, &QueryWorker::signalTableQueryResult,
|
|
this, &Query::slotTableQueryResult);
|
|
|
|
|
|
// Add Lines
|
|
connect(this, &Query::signalAddLines,
|
|
queryWorker, &QueryWorker::slotAddLines);
|
|
|
|
connect(queryWorker, &QueryWorker::signalAddLinesResult,
|
|
this, &Query::slotAddLinesResult);
|
|
|
|
|
|
// Set Data
|
|
connect(m_model, &DataModel::signalSetData, // comes from the model ..
|
|
this, &Query::slotSetData);
|
|
|
|
connect(this, &Query::signalSetData,
|
|
queryWorker, &QueryWorker::slotSetData);
|
|
|
|
connect(queryWorker, &QueryWorker::signalSetDataResult, // .. and comes back to THIS ! (query)
|
|
this, &Query::slotSetDataResult);
|
|
|
|
|
|
connect(m_ui->pbQuery, &QPushButton::clicked, this, &Query::slotCustomQuery);
|
|
connect(m_ui->pbAddLine, &QPushButton::clicked, this, &Query::slotStartAddLines);
|
|
connect(m_ui->pbDeleteLine, &QPushButton::clicked, this, &Query::slotDeleteLine);
|
|
connect(m_ui->pbReload, &QPushButton::clicked, this, &Query::slotTableQuery);
|
|
connect(m_ui->pbExport, &QPushButton::clicked, this, &Query::slotExportCSV);
|
|
|
|
m_ui->dataTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); // TODO: qt4
|
|
|
|
setModel();
|
|
}
|
|
|
|
|
|
Query::~Query()
|
|
{
|
|
delete m_ui;
|
|
delete m_model;
|
|
}
|
|
|
|
|
|
void Query::slotExportCSV()
|
|
{
|
|
//qWarning() << "slotExportCSV";
|
|
|
|
QFileDialog dialog(this); // save dialog
|
|
//dialog.setFileMode(QFileDialog::ExistingFile); // single file selection
|
|
dialog.setNameFilter(tr("CSV File (*.csv)"));
|
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
|
|
|
QStringList fileNames;
|
|
if (dialog.exec())
|
|
fileNames = dialog.selectedFiles();
|
|
|
|
if (!fileNames.count())
|
|
{
|
|
return;
|
|
}
|
|
|
|
QFile file;
|
|
file.setFileName(fileNames.at(0));
|
|
|
|
if (!file.open(QFile::ReadWrite))
|
|
{
|
|
QMessageBox::critical(this, tr("CSV Export Error"), tr("File '%1' is not accessible!").arg(fileNames.at(0)));
|
|
return;
|
|
}
|
|
|
|
|
|
// file is open, now save to csv file
|
|
int colCount = m_model->columnCount();
|
|
|
|
// get column names
|
|
QStringList columnNames;
|
|
columnNames.reserve(colCount);
|
|
|
|
for (int i = 0; i < colCount; i++)
|
|
{
|
|
columnNames.append(m_model->headerData(i, Qt::Horizontal).toString());
|
|
}
|
|
|
|
|
|
// get rows & row values
|
|
QStringList rows;
|
|
int rowsCount = m_sortModel.rowCount();
|
|
rows.reserve(rowsCount);
|
|
|
|
QStringList rowData;
|
|
for (int row = 0; row < rowsCount; row++)
|
|
{
|
|
// get row's values
|
|
rowData.clear();
|
|
|
|
for (int col = 0; col < colCount; col++)
|
|
{
|
|
rowData.append(m_sortModel.data(m_sortModel.index(row, col)).toString());
|
|
}
|
|
|
|
rows.append(rowData.join(QLatin1Char(',')));
|
|
}
|
|
|
|
|
|
file.write(columnNames.join(QLatin1Char(',')).toUtf8()); // write header
|
|
file.write(NEWLINE);
|
|
|
|
for (const QString &row : qAsConst(rows))
|
|
{
|
|
file.write(row.toUtf8());
|
|
file.write(NEWLINE);
|
|
}
|
|
|
|
file.close();
|
|
|
|
QMessageBox::information(this, tr("CSV Export Success"), tr("CSV Export was successful"));
|
|
}
|
|
|
|
void Query::onQueryDelete()
|
|
{
|
|
m_ui->queryText->setText(tr("DELETE FROM %1 WHERE %2").arg(m_model->getTableName(), m_idInWhere ? QStringLiteral("id = ") : QString()));
|
|
}
|
|
|
|
void Query::onQueryInsert()
|
|
{
|
|
m_ui->queryText->setText(tr("INSERT INTO %1 (%2) VALUES ()").arg(m_model->getTableName(), checkedColumnsNames().join(QStringLiteral(", "))));
|
|
}
|
|
|
|
void Query::onQueryUpdate()
|
|
{
|
|
const QStringList sl = checkedColumnsNames();
|
|
QStringList sl2;
|
|
sl2.reserve(sl.size());
|
|
for (const QString &s : sl)
|
|
sl2.append(tr("%1 = ").arg(s));
|
|
m_ui->queryText->setText(tr("UPDATE %1 SET %2 WHERE %3").arg(m_model->getTableName(), sl2.join(QStringLiteral(", ")), m_idInWhere ? QStringLiteral("id = ") : QString()));
|
|
}
|
|
|
|
void Query::handleError(const QString &errorText)
|
|
{
|
|
emit signalHideWait();
|
|
|
|
if (errorText.isEmpty())
|
|
return; // nothing to handle
|
|
|
|
QMessageBox::critical(this, tr("Error while executing query"),
|
|
tr("There was an error executing the query:\n%1").arg(errorText));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Delete Lines
|
|
void Query::slotDeleteLine() // called from UI
|
|
{
|
|
int result = QMessageBox::question(this, tr("SqlBrowser"),
|
|
tr("Do you really want to delete selected data?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
if (result == QMessageBox::No)
|
|
return;
|
|
|
|
emit signalShowWait(QStringLiteral("Deleting line(s).."));
|
|
|
|
const QModelIndexList unmapped = m_ui->dataTable->selectionModel()->selectedRows();
|
|
QModelIndexList mapped;
|
|
mapped.reserve(unmapped.size());
|
|
|
|
for (const auto &idx : unmapped)
|
|
mapped.append(m_sortModel.mapToSource(idx));
|
|
|
|
emit signalDeleteLines(this, mapped, m_model); // => QueryWorker
|
|
}
|
|
|
|
|
|
void Query::slotDeleteLinesResult(Query* caller, int affectedRowsCount, QString errorText, const QList<QModelIndex> &affectedRowsList) // => from QueryWorker
|
|
{
|
|
if (caller != this)
|
|
return;
|
|
|
|
if (errorText.isEmpty() && !affectedRowsCount) // no error but no rows affected?
|
|
{
|
|
errorText = tr("The row to be deleted could not be found - This is probably a type-conversion error! Please report that to Mike");
|
|
}
|
|
|
|
handleError(errorText);
|
|
|
|
//qWarning() << "Query::slotDeleteLinesResult: errorText = " << errorText << "affectedRowsCount = " << affectedRowsCount;
|
|
|
|
if (affectedRowsCount == affectedRowsList.count())
|
|
{
|
|
m_model->deleteLines(affectedRowsList); // tell the model to delete that rows (and tell the view about it)
|
|
}
|
|
}
|
|
|
|
// Custom Query
|
|
void Query::slotCustomQuery()
|
|
{
|
|
emit signalShowWait(QStringLiteral("Executing query.."));
|
|
emit signalCustomQuery(this, m_ui->queryText->document()->toPlainText(), m_model);
|
|
}
|
|
|
|
|
|
void Query::slotCustomQueryResult(Query* caller, const QString &errorText)
|
|
{
|
|
if (caller != this)
|
|
return;
|
|
|
|
setCustomQuery();
|
|
|
|
handleError(errorText);
|
|
|
|
//qWarning() << "Query::slotCustomQueryResult: errorText = " << errorText;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Table Query
|
|
void Query::slotTableQuery()
|
|
{
|
|
emit signalShowWait(QStringLiteral("Getting table data .."));
|
|
//qWarning() << "Query: model" << m_model;
|
|
emit signalTableQuery(this, m_model);
|
|
}
|
|
|
|
void Query::slotTableQueryResult(Query* caller, const QString &errorText)
|
|
{
|
|
if (caller != this)
|
|
return;
|
|
|
|
handleError(errorText);
|
|
|
|
// Don't put it in twice
|
|
if (!m_checkboxes.isEmpty())
|
|
return;
|
|
|
|
for(const auto &item : m_model->getHeaderList())
|
|
{
|
|
QCheckBox *cb = new QCheckBox(item.first, this);
|
|
m_ui->checkboxes->addWidget(cb);
|
|
m_checkboxes << cb;
|
|
|
|
if (item.first.compare(QStringLiteral("id"), Qt::CaseInsensitive) != 0)
|
|
continue;
|
|
|
|
// Only for ID:
|
|
QRadioButton *rbwhere = new QRadioButton(tr("in WHERE"), this);
|
|
m_ui->checkboxes->addWidget(rbwhere);
|
|
QRadioButton *rbnormal = new QRadioButton(tr("normal"), this);
|
|
m_ui->checkboxes->addWidget(rbnormal);
|
|
|
|
rbnormal->setEnabled(cb->isChecked());
|
|
rbwhere->setEnabled(cb->isChecked());
|
|
|
|
connect(cb, &QCheckBox::toggled, rbwhere, &QRadioButton::setEnabled);
|
|
connect(cb, &QCheckBox::toggled, rbnormal, &QRadioButton::setEnabled);
|
|
connect(rbwhere, &QRadioButton::toggled, this, [this, rbwhere, cb] { m_idInWhere = rbwhere->isChecked() && cb->isChecked(); });
|
|
connect(cb, &QRadioButton::toggled, this, [this, rbwhere, cb] { m_idInWhere = rbwhere->isChecked() && cb->isChecked(); });
|
|
|
|
rbwhere->setChecked(true);
|
|
}
|
|
m_ui->checkboxes->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
|
//qWarning() << "Query::slotTableQueryResult: errorText = " << errorText;
|
|
}
|
|
|
|
QStringList Query::checkedColumnsNames() const
|
|
{
|
|
QStringList sl;
|
|
for(const auto &cb : m_checkboxes)
|
|
{
|
|
if (cb->isChecked())
|
|
{
|
|
if ((cb->text().compare(QStringLiteral("id"), Qt::CaseInsensitive) == 0) && m_idInWhere)
|
|
continue;
|
|
sl << cb->text();
|
|
}
|
|
}
|
|
return sl;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Add Lines
|
|
void Query::slotStartAddLines()
|
|
{
|
|
if (!m_addLines)
|
|
{
|
|
m_addLines = new AddLines(this);
|
|
|
|
connect(m_addLines, &AddLines::signalAddLines,
|
|
this, &Query::slotAddLines);
|
|
|
|
m_addLines->copyDataFromModel(m_model);
|
|
}
|
|
|
|
m_addLines->show();
|
|
}
|
|
|
|
|
|
void Query::slotAddLines(AddModel *model)
|
|
{
|
|
emit signalShowWait(QStringLiteral("Adding line(s).."));
|
|
emit signalAddLines(this, model);
|
|
}
|
|
|
|
|
|
void Query::slotAddLinesResult(Query* caller, int , const QString &errorText)
|
|
{
|
|
if (caller != this)
|
|
return;
|
|
|
|
handleError(errorText);
|
|
|
|
//qWarning() << "Query::slotAddLinesResult: affectedRows = " << affectedRows << "errorText = " << errorText;
|
|
|
|
if (errorText.isEmpty()) // no error
|
|
{
|
|
// if (affectedRows) // only get new data when something changed
|
|
// {
|
|
// emit signalTableQuery(m_model); // re-get table!
|
|
// }
|
|
|
|
m_addLines->deleteLater(); // done, close add lines window and delete it..
|
|
m_addLines = nullptr;
|
|
|
|
emit signalTableQuery(this, m_model); // get fresh data from db
|
|
}
|
|
else // error
|
|
{
|
|
if (!m_addLines) // FIXME: needed! but not logically needed ;) what's going on here?
|
|
{
|
|
//qWarning() << "Query::slotAddLinesResult: !m_addLines";
|
|
}
|
|
else
|
|
m_addLines->show(); // show again, error!
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set Data
|
|
void Query::slotSetData(DataModel* model, const QModelIndex &index, const QVariant &val)
|
|
{
|
|
int result = QMessageBox::question(this, tr("SqlBrowser"),
|
|
tr("Do you really want to change the data?"),
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
if (result == QMessageBox::No)
|
|
return;
|
|
|
|
emit signalShowWait(QStringLiteral("Setting data.."));
|
|
emit signalSetData(this, model, index, val);
|
|
}
|
|
|
|
|
|
void Query::slotSetDataResult(Query* caller, const QString &errorText)
|
|
{
|
|
if (caller != this)
|
|
return;
|
|
|
|
handleError(errorText);
|
|
|
|
//qWarning() << "Query::slotSetDataResult: errorText =" << errorText;
|
|
}
|
|
|
|
|
|
|
|
void Query::setTable(const QString &tableName)
|
|
{
|
|
emit signalShowWait(QStringLiteral("Updating value.."));
|
|
|
|
if (tableName.isEmpty())
|
|
{
|
|
//qWarning() << "Query::setTable: tableName.isEmpty()";
|
|
return;
|
|
}
|
|
|
|
m_model->setTableName(tableName);
|
|
|
|
setTableQuery();
|
|
|
|
slotTableQuery();
|
|
}
|
|
|
|
|
|
void Query::setModel()
|
|
{
|
|
m_sortModel.setSourceModel(m_model);
|
|
m_ui->dataTable->setModel(/*(QAbstractTableModel*)*/&m_sortModel);
|
|
|
|
}
|
|
|
|
|
|
void Query::setCustomQuery() // cannot add/delete/reload
|
|
{
|
|
m_ui->pbAddLine->setEnabled(false);
|
|
m_ui->pbDeleteLine->setEnabled(false);
|
|
m_ui->pbReload->setEnabled(false);
|
|
}
|
|
|
|
|
|
void Query::setTableQuery() // cannot add/delete/reload
|
|
{
|
|
m_ui->pbAddLine->setEnabled(true);
|
|
m_ui->pbDeleteLine->setEnabled(true);
|
|
m_ui->pbReload->setEnabled(true);
|
|
}
|
|
|