#include "entity_updater_widget.h" #include "genres_repository_interface.h" #include "halls_repository_interface.h" #include "movies_repository_interface.h" #include "refunds_repository_interface.h" #include "sessions_repository_interface.h" #include "tickets_repository_interface.h" #include "update_genre_request.h" #include "update_hall_request.h" #include "update_movie_request.h" #include "update_refund_request.h" #include "update_session_request.h" #include "update_ticket_request.h" #include "error_dialog.h" #include "model_manager.h" #include "base_sql_table_model.h" #include #include namespace DatabaseTableNames { static constexpr char Genres[] = "genres"; static constexpr char Halls[] = "halls"; static constexpr char Movies[] = "movies"; static constexpr char Refunds[] = "refunds"; static constexpr char Sessions[] = "sessions"; static constexpr char Tickets[] = "tickets"; } // namespace DatabaseTableNames EntityUpdaterWidget::EntityUpdaterWidget(QWidget *parent) : QWidget(parent), primaryKey_(-1) { setupUi(this); setupConnections(); setupComboBoxCurrentTable(); // After setup connections setupParentEntityFinderWidget(); setupChildEntityFinderWidget(); } void EntityUpdaterWidget::setupComboBoxCurrentTable() { SchemaMetadata metadata = SchemaMetadata::defaultSchema(); QList databaseTableNames = { DatabaseTableNames::Genres, DatabaseTableNames::Halls, DatabaseTableNames::Movies, DatabaseTableNames::Refunds, DatabaseTableNames::Sessions, DatabaseTableNames::Tickets}; for (const QString &tableName : databaseTableNames) { comboBoxCurrentTable->addItem(metadata.translatedTableName(tableName), tableName); } } void EntityUpdaterWidget::setupConnections() { connect(foreignKeyFinder, &EntityFinderWidget::fieldRetrieved, this, &EntityUpdaterWidget::onForeignFieldRetrieved); connect(primaryKeyFinder, &EntityFinderWidget::fieldRetrieved, this, &EntityUpdaterWidget::onPrimaryFieldRetrieved); connect(primaryKeyFinder, &EntityFinderWidget::recordRetrieved, this, &EntityUpdaterWidget::onPrimaryEntityRetrieved); connect(comboBoxCurrentTable, &QComboBox::currentIndexChanged, this, &EntityUpdaterWidget::onTableSelected); connect(comboBoxCurrentColumn, &QComboBox::currentIndexChanged, this, &EntityUpdaterWidget::onColumnSelected); connect(pushButtonUpdate, &QPushButton::clicked, this, &EntityUpdaterWidget::onPushButtonUpdateClicked); } void EntityUpdaterWidget::setupChildEntityFinderWidget() { foreignKeyFinder->setLabelText( EntityFinderWidget::tr("Select entity for replacement")); foreignKeyFinder->setLineEditPlaceholder( EntityFinderWidget::tr("Here will be information about selected entity")); foreignKeyFinder->setHiddenFrame(true); } void EntityUpdaterWidget::setupParentEntityFinderWidget() { primaryKeyFinder->setLabelText( EntityFinderWidget::tr("Select entity for updating")); primaryKeyFinder->setLineEditPlaceholder( EntityFinderWidget::tr("Here will be information about selected entry")); } void EntityUpdaterWidget::configureForeignKeyFinder( const QString &columnName, const QString &databaseTableName) { TableInfoSQLite tableInfo(databaseTableName); if (tableInfo.isPrimaryKey(columnName)) { // NOTE: Change Primary Key is prohibited // configurePrimaryKeyFinder(databaseTableName); return; } QString foreignKeyDatabaseTableName = tableInfo.foreignKeyTable(columnName); if (foreignKeyDatabaseTableName.isEmpty()) { qCritical() << "Could not find the database table name for the key column, which " "contains \"_id\":" << columnName; return; } configureForeignKeyFinder(foreignKeyDatabaseTableName); } void EntityUpdaterWidget::configureForeignKeyFinder( const QString &databaseTableName) { foreignKeyFinder->resetToDefault(); foreignKeyFinder->setDefaultRelation(databaseTableName); } void EntityUpdaterWidget::configurePrimaryKeyFinder( const QString &databaseTableName) { primaryKeyFinder->resetToDefault(); primaryKeyFinder->setDefaultRelation(databaseTableName); } void EntityUpdaterWidget::onPrimaryFieldRetrieved(const QSqlField &field) { qInfo() << "Selected primary field: Name:" << field.name() << "Value:" << field.value(); primaryKey_ = field.value().toInt(); } void EntityUpdaterWidget::onForeignFieldRetrieved(const QSqlField &field) { qInfo() << "Selected foreign field: Name:" << field.name() << "Value:" << field.value(); selectedForeignField_ = field; } void EntityUpdaterWidget::onPrimaryEntityRetrieved(const QSqlRecord &entity) { qInfo() << "Retrieved foreign entity:" << entity; selectedPrimaryEntity_ = entity; } template <> QString EntityUpdaterWidget::actualColumnValue(const QString &columnName) { QString value = isColumnsEqual(columnName) ? lineEdit->text() : selectedPrimaryEntity_.value(columnName).toString(); qInfo() << "Actual column QString value:" << value; return value; } template <> QDateTime EntityUpdaterWidget::actualColumnValue(const QString &columnName) { QDateTime value = isColumnsEqual(columnName) ? dateTimeEdit->dateTime() : selectedPrimaryEntity_.value(columnName).toDateTime(); qInfo() << "Actual column QDateTime value:" << value; return value; } template <> int EntityUpdaterWidget::actualColumnValue(const QString &columnName) { int value = isColumnsEqual(columnName) ? spinBox->value() : selectedPrimaryEntity_.value(columnName).toInt(); qInfo() << "Actual column int value:" << value; return value; } template <> double EntityUpdaterWidget::actualColumnValue(const QString &columnName) { double value = isColumnsEqual(columnName) ? doubleSpinBox->value() : selectedPrimaryEntity_.value(columnName).toDouble(); qInfo() << "Actual column double value:" << value; return value; } qint32 EntityUpdaterWidget::actualForeignKey(const QString &columnName) { qint32 value = isColumnsEqual(columnName) ? selectedForeignField_.value().toInt() : selectedPrimaryEntity_.value(columnName).toInt(); qInfo() << "Actual foreign key:" << value; return value; } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateGenreRequest request; request.setGenreId(primaryKey_); request.setGenreName(actualColumnValue("genre_name")); return currentRepository()->updateGenre(request); } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateHallRequest request; request.setHallId(primaryKey_); request.setCapacity(actualColumnValue("capacity")); request.setHallName(actualColumnValue("hall_name")); return currentRepository()->updateHall(request); } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateMovieRequest request; request.setMovieId(primaryKey_); request.setDuration(actualColumnValue("duration")); request.setGenreId(actualForeignKey("genre_id")); request.setTitle(actualColumnValue("title")); return currentRepository()->updateMovie(request); } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateRefundRequest request; request.setRefundId(primaryKey_); request.setRefundAmount(actualColumnValue("refund_amount")); request.setRefundAt(actualColumnValue("refund_at")); request.setTicketId(actualForeignKey("ticket_id")); return currentRepository()->updateRefund(request); } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateSessionRequest request; request.setSessionId(primaryKey_); request.setHallId(actualForeignKey("hall_id")); request.setMovieId(actualForeignKey("movie_id")); request.setBeginAt(actualColumnValue("begin_at")); request.setTicketPrice(actualColumnValue("ticket_price")); return currentRepository()->updateSession( request); } template <> RepositoryResult EntityUpdaterWidget::updateEntity() { UpdateTicketRequest request; request.setTicketId(primaryKey_); request.setSeatNumber(actualColumnValue("seat_number")); request.setSessionId(actualForeignKey("session_id")); request.setSoldAt(actualColumnValue("sold_at")); return currentRepository()->updateTicket(request); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Genre updated successfully")); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Hall updated successfully")); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Movie updated successfully")); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Refund updated successfully")); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Session updated successfully")); } template <> void EntityUpdaterWidget::processEntityUpdate( RepositoryResult &resultOut) { resultOut = updateEntity(); if (!resultOut.success) { ErrorDialog::displayError(this, resultOut.errorMessage); return; } showMessageDialog(resultOut, EntityUpdaterWidget::tr("Ticket updated successfully")); } void EntityUpdaterWidget::onPushButtonUpdateClicked() { const QString &databaseTableName = comboBoxCurrentTable->currentData().toString(); RepositoryResult result; if (databaseTableName == DatabaseTableNames::Genres) { processEntityUpdate(result); } else if (databaseTableName == DatabaseTableNames::Halls) { processEntityUpdate(result); } else if (databaseTableName == DatabaseTableNames::Movies) { processEntityUpdate(result); } else if (databaseTableName == DatabaseTableNames::Refunds) { processEntityUpdate(result); } else if (databaseTableName == DatabaseTableNames::Sessions) { processEntityUpdate(result); } else if (databaseTableName == DatabaseTableNames::Tickets) { processEntityUpdate(result); } else { qFatal() << "EntityDeleterWidget::onPressPushButtonDeleteEntity: " "Unknown database table name:" << databaseTableName; } processUpdateResult(result); } void EntityUpdaterWidget::onTableSelected(int tableIndex) { SchemaMetadata metadata = SchemaMetadata::defaultSchema(); const QString &databaseTableName = comboBoxCurrentTable->itemData(tableIndex).toString(); ModelManager &modelManager = ModelManager::instance(); BaseSqlTableModel *model = modelManager.getModelAs( metadata.modelTableName(databaseTableName)); comboBoxCurrentColumn->clear(); for (const auto &columnName : model->columnNames()) { if (metadata.primaryIdColumnName(databaseTableName) == columnName) { // NOTE: Change Primary Key is prohibited continue; } int headerIndex = model->columnIndex(columnName); QString displayName = model->headerData(headerIndex, Qt::Horizontal).toString(); comboBoxCurrentColumn->addItem(displayName, columnName); } configurePrimaryKeyFinder(databaseTableName); } void EntityUpdaterWidget::onColumnSelected(int columnIndex) { Q_UNUSED(columnIndex); const QString &databaseTableName = comboBoxCurrentTable->currentData().toString(); TableInfoSQLite tableInfoSQLite(databaseTableName); QString columnName = comboBoxCurrentColumn->currentData().toString(); bool isKey = columnName.contains("_id", Qt::CaseInsensitive); QWidget *page; switch (tableInfoSQLite.columnMetaType(columnName)) { case QMetaType::Int: { page = findChild(isKey ? "pageChildFinderWidget" : "pageSpinBox"); } break; case QMetaType::Double: page = findChild("pageDoubleSpinBox"); break; case QMetaType::QString: page = findChild("pageLineEdit"); break; case QMetaType::QDateTime: page = findChild("pageDateTimeEdit"); break; default: qCritical() << "Unknown column selected"; return; } stackedWidget->setCurrentWidget(page); if (isKey) { configureForeignKeyFinder(columnName, databaseTableName); } } QModelIndex EntityUpdaterWidget::findIndexByColumn(QAbstractItemModel *model, int column, const QVariant &value) { if (!model || column < 0 || column >= model->columnCount()) return QModelIndex(); for (int row = 0; row < model->rowCount(); ++row) { QModelIndex index = model->index(row, column); if (model->data(index) == value) { return index; } } return QModelIndex(); } bool EntityUpdaterWidget::isColumnsEqual(const QString &other) { TableInfoSQLite tableInfo(comboBoxCurrentTable->currentData().toString()); QString current = comboBoxCurrentColumn->currentData().toString(); bool isEqual = tableInfo.columnIndex(current) == tableInfo.columnIndex(other); const static QString billet("Column \"%1\" and column \"%2\": %3"); qInfo().noquote() << billet.arg(current).arg(other).arg( isEqual ? "Equal" : "Not equal"); return isEqual; }; void EntityUpdaterWidget::processUpdateResult(const RepositoryResult &result) { if (!result.success) { return; } const QString &databaseTableName = comboBoxCurrentTable->currentData().toString(); SchemaMetadata metadata = SchemaMetadata::defaultSchema(); ModelManager &modelManager = ModelManager::instance(); QSqlTableModel *model = modelManager.getModel(metadata.modelTableName(databaseTableName)); QString primaryKeyColumnName = metadata.primaryIdColumnName(databaseTableName); int columnIndex = selectedPrimaryEntity_.indexOf(primaryKeyColumnName); QModelIndex rowIndex = findIndexByColumn(model, columnIndex, primaryKey_); selectedPrimaryEntity_ = model->record(rowIndex.row()); primaryKeyFinder->refreshLineEditText(selectedPrimaryEntity_); foreignKeyFinder->resetToDefault(); } void EntityUpdaterWidget::showMessageDialog(const RepositoryResult &result, const QString &successMessage) { if (!result.success) { ErrorDialog::displayError(this, result.errorMessage); } else { QMessageBox::information(this, QMessageBox::tr("Success"), successMessage); } }