Initial commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#include "auth_dialog.h"
|
||||
|
||||
#include "repository_manager.h"
|
||||
#include "repository_result.h"
|
||||
#include "role_dto.h"
|
||||
#include "roles_repository.h"
|
||||
#include "schema_metadata.h"
|
||||
#include "user_dto.h"
|
||||
#include "users_repository.h"
|
||||
#include <QCryptographicHash>
|
||||
#include <QErrorMessage>
|
||||
#include <QMessageBox>
|
||||
|
||||
AuthDialog::AuthDialog(QWidget *parent) : QDialog(parent) {
|
||||
setupUi(this);
|
||||
|
||||
// WARNING: Models must be initialized before setting up table view
|
||||
if (initializeRepositories()) {
|
||||
setupConnections();
|
||||
} else {
|
||||
qWarning() << "Initialization failed";
|
||||
}
|
||||
}
|
||||
|
||||
bool AuthDialog::initializeRepositories() {
|
||||
RepositoryManager &repositoryManager = RepositoryManager::instance();
|
||||
SchemaMetadata metadata = SchemaMetadata::defaultSchema();
|
||||
|
||||
rolesRepository_ = repositoryManager.getRepositoryAs<RolesRepository>(
|
||||
metadata.repositoryTableName("roles"));
|
||||
|
||||
usersRepository_ = repositoryManager.getRepositoryAs<UsersRepository>(
|
||||
metadata.repositoryTableName("users"));
|
||||
|
||||
return rolesRepository_ && usersRepository_;
|
||||
}
|
||||
|
||||
void AuthDialog::setupConnections() {
|
||||
connect(btnLogin, &QPushButton::clicked, this, &AuthDialog::onLoginClicked);
|
||||
connect(btnCancel, &QPushButton::clicked, this, &AuthDialog::onCancelClicked);
|
||||
}
|
||||
|
||||
void AuthDialog::onCancelClicked() {
|
||||
emit loginFailed();
|
||||
reject();
|
||||
}
|
||||
|
||||
void AuthDialog::onLoginClicked() {
|
||||
QString username = txtUsername->text().trimmed();
|
||||
QString password = txtPassword->text();
|
||||
|
||||
UserDTO userDTO;
|
||||
RepositoryResult result =
|
||||
usersRepository_->getUserByUsername(username, userDTO);
|
||||
|
||||
bool userExists = result.success;
|
||||
bool passwordMatch = !userExists ? false : verifyPassword(password, userDTO);
|
||||
|
||||
if (!userExists || !passwordMatch) {
|
||||
QMessageBox::warning(this, QMessageBox::tr("Error"),
|
||||
QMessageBox::tr("Wrong user name or password"));
|
||||
return;
|
||||
}
|
||||
|
||||
RoleDTO roleDTO;
|
||||
result = rolesRepository_->getRoleById(userDTO.roleId(), roleDTO);
|
||||
|
||||
if (!result.success) {
|
||||
QMessageBox::warning(this, QMessageBox::tr("Error"),
|
||||
QMessageBox::tr("Role of user not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
qint32 userId = userDTO.userId();
|
||||
qint32 accessLevel_ = roleDTO.accessLevel();
|
||||
|
||||
emit loginSuccessful(userId, accessLevel_);
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
QString AuthDialog::hashPassword(const QString &password, const QString &salt) {
|
||||
QByteArray data = (password + salt).toUtf8();
|
||||
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
|
||||
|
||||
return QString(hash.toHex());
|
||||
}
|
||||
|
||||
bool AuthDialog::verifyPassword(const QString &password,
|
||||
const UserDTO &userDTO) {
|
||||
QString inputHash = hashPassword(password, userDTO.salt());
|
||||
|
||||
return (inputHash == userDTO.passwordHash());
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef AUTH_DIALOG_H
|
||||
#define AUTH_DIALOG_H
|
||||
|
||||
#include "ui_auth_dialog.h"
|
||||
#include <QDialog>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
// Forward declaration
|
||||
class RolesRepositoryInterface;
|
||||
class UserDTO;
|
||||
class UsersRepositoryInterface;
|
||||
|
||||
class AuthDialog : public QDialog, private Ui::AuthDialog {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
RolesRepositoryInterface *rolesRepository_;
|
||||
UsersRepositoryInterface *usersRepository_;
|
||||
|
||||
public:
|
||||
explicit AuthDialog(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void loginSuccessful(qint32 userId, qint32 accessLevel);
|
||||
void loginFailed();
|
||||
|
||||
private slots:
|
||||
void onCancelClicked();
|
||||
void onLoginClicked();
|
||||
|
||||
private:
|
||||
bool initializeRepositories();
|
||||
void setupConnections();
|
||||
|
||||
QString hashPassword(const QString &password, const QString &salt);
|
||||
bool verifyPassword(const QString &password, const UserDTO &userDTO);
|
||||
};
|
||||
|
||||
#endif // AUTH_DIALOG_H
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AuthDialog</class>
|
||||
<widget class="QDialog" name="AuthDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>120</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Аuthorization</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelUsername">
|
||||
<property name="text">
|
||||
<string>Login:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtUsername"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelPassword">
|
||||
<property name="text">
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtPassword">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::EchoMode::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnLogin">
|
||||
<property name="text">
|
||||
<string>Enter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnCancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>btnCancel</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>AuthDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>118</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>150</x>
|
||||
<y>100</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -0,0 +1,217 @@
|
||||
#include "error_dialog.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
#include <QErrorMessage>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
QErrorMessage *ErrorDialog::getDialog(QWidget *parent,
|
||||
const QString &errorMsg) {
|
||||
// Initialize the error dialog
|
||||
QErrorMessage *dialog =
|
||||
new QErrorMessage(parent); // parent is needed for the correct location
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose); // delete the dialog when closed
|
||||
|
||||
// Hide the "don't show again" checkbox
|
||||
#define ERROR_DIALOG_NEW_VERSION 0
|
||||
#if (ERROR_DIALOG_NEW_VERSION == 1 && QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
|
||||
// You need to set DontShowAgainVisible to true in Qt 6.3
|
||||
errorDialog->setDontShowAgainVisible(false);
|
||||
#else
|
||||
QCheckBox *cb = dialog->findChild<QCheckBox *>();
|
||||
if (cb) {
|
||||
cb->setEnabled(false);
|
||||
cb->hide();
|
||||
}
|
||||
#endif
|
||||
#undef ERROR_DIALOG_NEW_VERSION
|
||||
|
||||
// Set the window title
|
||||
dialog->setWindowTitle(QObject::tr("Information messages"));
|
||||
|
||||
// Set minimum width size
|
||||
dialog->setMinimumWidth(600);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void ErrorDialog::displayError(QWidget *parent, const QString &errorMsg) {
|
||||
qDebug() << "Displaying error message:" << errorMsg;
|
||||
|
||||
QErrorMessage *dialog = getDialog(parent, errorMsg);
|
||||
|
||||
if (errorMsg.contains("constraint failed")) {
|
||||
QString detailedMessage = handleSqlConstraints(errorMsg);
|
||||
dialog->showMessage(detailedMessage);
|
||||
dialog->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorMsg.contains("not found")) {
|
||||
QString detailedMessage = handleNotFoundErrors(errorMsg);
|
||||
dialog->showMessage(detailedMessage);
|
||||
dialog->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
QRegularExpression regex("Error (\\d+):");
|
||||
QRegularExpressionMatch match = regex.match(errorMsg);
|
||||
|
||||
if (!match.hasMatch()) {
|
||||
dialog->showMessage(QObject::tr(
|
||||
"An error occurred from an unknown source of the problem."));
|
||||
dialog->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
int errorCode = match.captured(1).toInt();
|
||||
QString detailedMessage = getDetailedMessage(errorCode);
|
||||
|
||||
dialog->showMessage(detailedMessage);
|
||||
dialog->exec();
|
||||
}
|
||||
|
||||
QString ErrorDialog::handleNotFoundErrors(const QString &errorMsg) {
|
||||
if (errorMsg.contains("Genre", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified genre was not found.");
|
||||
}
|
||||
if (errorMsg.contains("Hall", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified hall was not found.");
|
||||
}
|
||||
if (errorMsg.contains("Movie", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified movie was not found.");
|
||||
}
|
||||
if (errorMsg.contains("Refund", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified refund was not found.");
|
||||
}
|
||||
if (errorMsg.contains("Session", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified session was not found.");
|
||||
}
|
||||
if (errorMsg.contains("Ticket", Qt::CaseInsensitive)) {
|
||||
return QObject::tr("The specified ticket was not found.");
|
||||
}
|
||||
|
||||
// If the specific error is not recognized, return a general message
|
||||
return QObject::tr("The requested object was not found in the database.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::handleSqlConstraints(const QString &errorMsg) {
|
||||
if (errorMsg.contains("UNIQUE constraint failed")) {
|
||||
return handleUniqueConstraint(errorMsg);
|
||||
}
|
||||
if (errorMsg.contains("FOREIGN KEY constraint failed")) {
|
||||
return handleForeignKeyConstraint(errorMsg);
|
||||
}
|
||||
if (errorMsg.contains("PRIMARY KEY constraint failed")) {
|
||||
return handlePrimaryKeyConstraint();
|
||||
}
|
||||
if (errorMsg.contains("CHECK constraint failed")) {
|
||||
return handleCheckConstraint(errorMsg);
|
||||
}
|
||||
if (errorMsg.contains("NOT NULL constraint failed")) {
|
||||
return tr("A required field is missing. Please fill all required fields.");
|
||||
}
|
||||
|
||||
return tr("An SQL constraint violation occurred, but at the moment it has "
|
||||
"not been described in detail yet.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::handleUniqueConstraint(const QString &errorMsg) {
|
||||
if (errorMsg.contains("genres.genre_name")) {
|
||||
return tr("A genre with the same name already exists.");
|
||||
}
|
||||
if (errorMsg.contains("movies.title")) {
|
||||
return tr("A movie with the same title already exists.");
|
||||
}
|
||||
if (errorMsg.contains("halls.hall_name")) {
|
||||
return tr("A hall with the same name already exists.");
|
||||
}
|
||||
if (errorMsg.contains("tickets.session_id, tickets.seat_number")) {
|
||||
return tr("A ticket with the same session and seat number already exists.");
|
||||
}
|
||||
if (errorMsg.contains("refunds.ticket_id")) {
|
||||
return tr("A refund for the same ticket already exists.");
|
||||
}
|
||||
if (errorMsg.contains("sessions.hall_id, sessions.begin_at")) {
|
||||
return tr("A session is already scheduled in this hall at the same time.");
|
||||
}
|
||||
|
||||
return tr("A unique constraint violation occurred, but at the moment it has "
|
||||
"not been described in detail yet.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::handleForeignKeyConstraint(const QString &errorMsg) {
|
||||
if (errorMsg.contains("sessions.movie_id")) {
|
||||
return tr("The movie ID for the session does not exist.");
|
||||
}
|
||||
if (errorMsg.contains("sessions.hall_id")) {
|
||||
return tr("The hall ID for the session does not exist.");
|
||||
}
|
||||
if (errorMsg.contains("movies.genre_id")) {
|
||||
return tr("The genre ID for the movie does not exist.");
|
||||
}
|
||||
if (errorMsg.contains("tickets.session_id")) {
|
||||
return tr("The session ID for the ticket does not exist.");
|
||||
}
|
||||
if (errorMsg.contains("refunds.ticket_id")) {
|
||||
return tr("The ticket ID for the refund does not exist.");
|
||||
}
|
||||
|
||||
return tr("Operation violates a foreign key constraint, but at the moment it "
|
||||
"has not been described in detail yet.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::handlePrimaryKeyConstraint() {
|
||||
return tr("Duplicate primary key value. Ensure the primary key is unique.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::handleCheckConstraint(const QString &errorMsg) {
|
||||
if (errorMsg.contains("length(genre_name) > 0")) {
|
||||
return tr("Genre name must not be empty.");
|
||||
}
|
||||
if (errorMsg.contains("length(title) > 0")) {
|
||||
return tr("Movie title must not be empty.");
|
||||
}
|
||||
if (errorMsg.contains("duration > 0")) {
|
||||
return tr("Movie duration must be a positive value.");
|
||||
}
|
||||
if (errorMsg.contains("length(hall_name) > 0")) {
|
||||
return tr("Hall name must not be empty.");
|
||||
}
|
||||
if (errorMsg.contains("capacity > 0")) {
|
||||
return tr("Hall capacity must be a positive number.");
|
||||
}
|
||||
if (errorMsg.contains("ticket_price >= 0")) {
|
||||
return tr("Ticket price must be a non-negative value.");
|
||||
}
|
||||
if (errorMsg.contains("seat_number > 0")) {
|
||||
return tr("Seat number must be a positive value.");
|
||||
}
|
||||
if (errorMsg.contains("refund_amount >= 0")) {
|
||||
return tr("Refund amount must be a non-negative value.");
|
||||
}
|
||||
|
||||
return tr("A value violates a CHECK constraint, but at the moment it has not "
|
||||
"been described in detail yet.");
|
||||
}
|
||||
|
||||
QString ErrorDialog::getDetailedMessage(int errorCode) {
|
||||
switch (errorCode) {
|
||||
case 1001:
|
||||
return tr("Seat number exceeds hall capacity.");
|
||||
case 1002:
|
||||
return tr("Cannot purchase ticket after the session has started.");
|
||||
case 1003:
|
||||
return tr("Refunds cannot be made after the session has started.");
|
||||
case 1004:
|
||||
return tr("Refund amount cannot exceed the sale amount.");
|
||||
case 1005:
|
||||
return tr("Refund date cannot be earlier than the sale date.");
|
||||
case 1006:
|
||||
return tr("The new session overlaps with an ongoing movie in the hall.");
|
||||
default:
|
||||
return tr("A known error has occurred, but at the moment it has not been "
|
||||
"described in detail yet.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef ERROR_DIALOG_H
|
||||
#define ERROR_DIALOG_H
|
||||
|
||||
#include <QErrorMessage>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class ErrorDialog : private QObject {
|
||||
// For translation
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Method to dispose the error dialog
|
||||
static void displayError(QWidget *parent, const QString &errorMsg);
|
||||
|
||||
ErrorDialog() = delete;
|
||||
|
||||
private:
|
||||
// A method for initializing the error dialog
|
||||
static QErrorMessage *getDialog(QWidget *parent, const QString &errorMsg);
|
||||
|
||||
// A method for obtaining a "human-readable" text based on an error code
|
||||
static QString getDetailedMessage(int errorCode);
|
||||
|
||||
// Methods for handling various SQL constraints
|
||||
static QString handleNotFoundErrors(const QString &errorMsg);
|
||||
static QString handleCheckConstraint(const QString &errorMsg);
|
||||
static QString handleForeignKeyConstraint(const QString &errorMsg);
|
||||
static QString handlePrimaryKeyConstraint();
|
||||
static QString handleSqlConstraints(const QString &errorMsg);
|
||||
static QString handleUniqueConstraint(const QString &errorMsg);
|
||||
};
|
||||
|
||||
#endif // ERROR_DIALOG_H
|
||||
@@ -0,0 +1,154 @@
|
||||
#include "search_dialog.h"
|
||||
|
||||
#include "base_sql_table_model.h"
|
||||
#include "model_manager.h"
|
||||
#include "multi_column_filter_proxy_model.h"
|
||||
#include <QMessageBox>
|
||||
|
||||
SearchDialog::SearchDialog(QWidget *parent)
|
||||
: QDialog(parent), originalModel_(nullptr) {
|
||||
setupUi(this);
|
||||
|
||||
initializeProxyModel();
|
||||
setupTableView(); // After initializing proxy model
|
||||
setupConnections();
|
||||
}
|
||||
|
||||
SearchDialog::SearchDialog(const QString &modelTableName,
|
||||
const QString &fieldName, QWidget *parent)
|
||||
: SearchDialog(parent) {
|
||||
if (!setTableName(modelTableName)) {
|
||||
qFatal("SearchDialog::SearchDialog: Failed to set table name");
|
||||
}
|
||||
if (!setFieldName(fieldName)) {
|
||||
qFatal("SearchDialog::SearchDialog: Failed to set field name");
|
||||
}
|
||||
}
|
||||
|
||||
SearchDialog::~SearchDialog() {
|
||||
if (originalModel_ != nullptr) {
|
||||
originalModel_->resetFilter();
|
||||
}
|
||||
}
|
||||
|
||||
bool SearchDialog::setFieldName(const QString &fieldName) {
|
||||
int columnIndex = originalModel_->columnIndex(fieldName);
|
||||
if (columnIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
columnIndex_ = columnIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SearchDialog::setTableName(const QString &modelTableName) {
|
||||
ModelManager &modelManger = ModelManager::instance();
|
||||
|
||||
if (originalModel_ != nullptr) {
|
||||
originalModel_->resetFilter();
|
||||
}
|
||||
|
||||
modelTableName_ = modelTableName;
|
||||
|
||||
originalModel_ = modelManger.getModelAs<BaseSqlTableModel>(modelTableName);
|
||||
|
||||
proxyModel_->setSourceModel(originalModel_);
|
||||
|
||||
tableView->clearSelection();
|
||||
|
||||
columnIndex_ = -1;
|
||||
|
||||
if (originalModel_->isCompleteDatabaseFiltering()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef NOPTIMIZATION
|
||||
while (originalModel_->canFetchMore()) {
|
||||
originalModel_->fetchMore();
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SearchDialog::initializeProxyModel() {
|
||||
proxyModel_ = new MultiColumnSortFilterProxyModel(this);
|
||||
}
|
||||
|
||||
void SearchDialog::setupConnections() {
|
||||
connect(lineEditSearch, &QLineEdit::textChanged, this,
|
||||
&SearchDialog::onLineEditSearchTextChanged);
|
||||
|
||||
connect(pushButtonSelect, &QPushButton::clicked, this,
|
||||
&SearchDialog::onPushButtonSelectClicked);
|
||||
}
|
||||
|
||||
void SearchDialog::setupTableView() {
|
||||
QHeaderView *horizontalHeader = tableView->horizontalHeader();
|
||||
horizontalHeader->setHighlightSections(false);
|
||||
horizontalHeader->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
|
||||
tableView->setAlternatingRowColors(true);
|
||||
|
||||
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
|
||||
tableView->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
tableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
tableView->setSortingEnabled(true);
|
||||
|
||||
tableView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
tableView->sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
tableView->setModel(proxyModel_);
|
||||
}
|
||||
|
||||
void SearchDialog::onLineEditSearchTextChanged(const QString &text) {
|
||||
ModelManager &modelManger = ModelManager::instance();
|
||||
|
||||
#ifdef NOPTIMIZATION
|
||||
if (originalModel_->isCompleteDatabaseFiltering()) {
|
||||
originalModel_->setMultiColumnFilter(text);
|
||||
return;
|
||||
}
|
||||
|
||||
// Model filtering
|
||||
QRegularExpression regex(text, QRegularExpression::CaseInsensitiveOption);
|
||||
proxyModel_->setFilterRegularExpression(regex);
|
||||
#else
|
||||
// Database filtering
|
||||
originalModel_->setMultiColumnFilter(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SearchDialog::onPushButtonSelectClicked() {
|
||||
if (columnIndex_ == -1) {
|
||||
qFatal("SearchDialog::onPushButtonSelectClicked: Column index not set");
|
||||
}
|
||||
|
||||
QModelIndexList selectedIndexes = tableView->selectionModel()->selectedRows();
|
||||
if (selectedIndexes.isEmpty()) {
|
||||
QMessageBox::warning(this, QMessageBox::tr("Error"),
|
||||
QMessageBox::tr("No row selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex selectedRowIndex = selectedIndexes.first();
|
||||
emit rowSelected(selectedRowIndex.row());
|
||||
|
||||
QSqlRecord record = originalModel_->record(selectedRowIndex.row());
|
||||
emit recordRetrieved(record);
|
||||
|
||||
if (columnIndex_ != -1) {
|
||||
QSqlRecord record = originalModel_->record(selectedRowIndex.row());
|
||||
QSqlField field = record.field(columnIndex_);
|
||||
emit fieldRetrieved(field);
|
||||
}
|
||||
|
||||
accept();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef SEARCH_DIALOG_H
|
||||
#define SEARCH_DIALOG_H
|
||||
|
||||
#include "ui_search_dialog.h"
|
||||
#include <QList>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QSqlField>
|
||||
#include <QSqlRecord>
|
||||
|
||||
// Forward declaration
|
||||
class BaseSqlTableModel;
|
||||
|
||||
class SearchDialog : public QDialog, private Ui::SearchDialog {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
BaseSqlTableModel *originalModel_;
|
||||
QSortFilterProxyModel *proxyModel_;
|
||||
QString modelTableName_;
|
||||
int columnIndex_;
|
||||
|
||||
public:
|
||||
explicit SearchDialog(const QString &modelTableName, const QString &fieldName,
|
||||
QWidget *parent = nullptr);
|
||||
explicit SearchDialog(QWidget *parent = nullptr);
|
||||
~SearchDialog();
|
||||
|
||||
bool setFieldName(const QString &fieldName);
|
||||
bool setTableName(const QString &tableName);
|
||||
|
||||
signals:
|
||||
void rowSelected(int rowIndex);
|
||||
void recordRetrieved(QSqlRecord rowValues);
|
||||
void fieldRetrieved(QSqlField field);
|
||||
|
||||
private slots:
|
||||
void onLineEditSearchTextChanged(const QString &text);
|
||||
void onPushButtonSelectClicked();
|
||||
|
||||
private:
|
||||
void initializeProxyModel();
|
||||
void setupConnections();
|
||||
void setupTableView();
|
||||
};
|
||||
|
||||
#endif // SEARCH_DIALOG_H
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SearchDialog</class>
|
||||
<widget class="QDialog" name="SearchDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>460</width>
|
||||
<height>346</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Finding a database entry</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEditSearch">
|
||||
<property name="placeholderText">
|
||||
<string>Enter text to search...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView">
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonSelect">
|
||||
<property name="text">
|
||||
<string>Choose</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonCancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>pushButtonCancel</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>SearchDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>258</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>200</x>
|
||||
<y>250</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user