#include "ui_QueryUi.h" #include "Query.h" #include "QueryThread.h" #include "AddLine.h" #include #include #include #include #include #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"); 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 &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); }