fix: minor fixes

This commit is contained in:
2026-01-20 09:44:07 +03:00
parent 955395345e
commit f055ad9cc4
4 changed files with 249 additions and 83 deletions

View File

@@ -229,4 +229,6 @@ void EditClientDialog::setClientInfo(int index)
m_cityLineEdit->setText(item.city); m_cityLineEdit->setText(item.city);
m_yourCompanyNameTextEdit->setText(item.yourCompany); m_yourCompanyNameTextEdit->setText(item.yourCompany);
m_hardwareHashLineEdit->setText(item.hardwareHash); m_hardwareHashLineEdit->setText(item.hardwareHash);
m_configPathLabel->setText(tr("Drop file here"));
} }

View File

@@ -11,58 +11,14 @@
#include <QtSql/QSqlRecord> #include <QtSql/QSqlRecord>
// Self // Self
#include <qfile.h>
#include "../def.h" #include "../def.h"
const static int COLUMN_COUNT = 9; const static int COLUMN_COUNT = 8;
namespace {
struct LoadResult
{
QList<LicenseModel::LicenseItem> data;
LicenseModel::Status status = LicenseModel::Status::Ok;
QString error;
};
struct DeleteResult
{
QList<QString> ids;
LicenseModel::Status status = LicenseModel::Status::Ok;
QString error;
};
}
LicenseModel::LicenseModel(QObject* parent) LicenseModel::LicenseModel(QObject* parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
{ {
m_db = QSqlDatabase::addDatabase("QSQLITE"); checkTables();
m_db.setDatabaseName(DB_PATH);
if (!m_db.open())
{
m_status = Status::DbExistError;
m_errors.append("Database connection failed: " + m_db.lastError().text());
}
else
{
if (!checkTables())
{
m_status = Status::DbStructError;
m_errors.append("Database tables are not valid");
}
else
{
m_status = Status::Ok;
}
}
if (m_db.open())
m_db.close();
}
LicenseModel::~LicenseModel()
{
} }
int LicenseModel::rowCount(const QModelIndex &parent) const int LicenseModel::rowCount(const QModelIndex &parent) const
@@ -103,8 +59,6 @@ QVariant LicenseModel::data(const QModelIndex &index, int role) const
case 6: case 6:
return m_data[index.row()].city ; return m_data[index.row()].city ;
case 7: case 7:
return m_data[index.row()].createdAtUtc ;
case 8:
return m_data[index.row()].comment ; return m_data[index.row()].comment ;
default: default:
return {}; return {};
@@ -136,8 +90,6 @@ QVariant LicenseModel::headerData(int section, Qt::Orientation orientation, int
case 6: case 6:
return tr("City"); return tr("City");
case 7: case 7:
return tr("Created date");
case 8:
return tr("Comment"); return tr("Comment");
default: default:
return {}; return {};
@@ -173,20 +125,52 @@ QString LicenseModel::getStatusText()
bool LicenseModel::checkTables() bool LicenseModel::checkTables()
{ {
auto db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(DB_PATH);
if (!db.open())
{
m_status = Status::DbExistError;
m_errors.append("Database connection failed: " + db.lastError().text());
return false;
}
bool clientTableExist = false; bool clientTableExist = false;
for (const auto &table : m_db.tables()) for (const auto &table : db.tables())
{ {
if (table == "clients") if (table == "clients")
{
m_status = Status::Ok;
return true; return true;
}
} }
db.close();
if (!clientTableExist) if (!clientTableExist)
{
m_status = Status::DbStructError;
return false; return false;
}
else else
{
m_status = Status::Ok;
return true; return true;
}
} }
bool LicenseModel::prepareDatabase() bool LicenseModel::prepareDatabase()
{ {
auto db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(DB_PATH);
if (!db.open())
{
m_status = Status::DbExistError;
m_errors << tr("Database not exist");
return false;
}
QFile tablesFile(QStringLiteral(":/deps/tables.ddl")); QFile tablesFile(QStringLiteral(":/deps/tables.ddl"));
if (!tablesFile.open(QIODevice::ReadOnly | QIODevice::Text)) if (!tablesFile.open(QIODevice::ReadOnly | QIODevice::Text))
return false; return false;
@@ -198,7 +182,7 @@ bool LicenseModel::prepareDatabase()
{ {
if (item.trimmed().isEmpty()) if (item.trimmed().isEmpty())
continue; continue;
QSqlQuery query(m_db); QSqlQuery query(db);
if (!query.exec(item.trimmed())) if (!query.exec(item.trimmed()))
{ {
m_status = Status::DbStructError; m_status = Status::DbStructError;
@@ -208,6 +192,9 @@ bool LicenseModel::prepareDatabase()
} }
} }
db.close();
m_status = Status::Ok;
return true; return true;
} }
@@ -216,12 +203,31 @@ void LicenseModel::addClient(const LicenseItem &item)
m_status = Status::Working; m_status = Status::Working;
emit statusChanged(); emit statusChanged();
// handler thread finish auto* watcher = new QFutureWatcher<Result>(this);
auto* watcher = new QFutureWatcher<LicenseItem>(this); connect(watcher, &QFutureWatcher<Result>::finished, this, [this, watcher]() {
connect(watcher, &QFutureWatcher<LicenseItem>::finished, this, [this, watcher]() { const Result result = watcher->result();
const int row = m_data.size(); if (result.status != Status::Ok)
{
m_status = result.status;
if (!result.error.isEmpty())
m_errors.append(result.error);
emit statusChanged();
watcher->deleteLater();
return;
}
if (result.data.isEmpty())
{
m_status = Status::DbStructError;
m_errors.append("Inserted client not found");
emit statusChanged();
watcher->deleteLater();
return;
}
const int row = 0;
beginInsertRows({}, row, row); beginInsertRows({}, row, row);
m_data.append(watcher->result()); m_data.insert(row, result.data.first());
endInsertRows(); endInsertRows();
m_status = Status::Ok; m_status = Status::Ok;
@@ -230,16 +236,17 @@ void LicenseModel::addClient(const LicenseItem &item)
watcher->deleteLater(); watcher->deleteLater();
}); });
// another thread lambda
watcher->setFuture(QtConcurrent::run([item]() { watcher->setFuture(QtConcurrent::run([item]() {
Result result;
const QString connectionName = QString("license_add_%1").arg(QUuid::createUuid().toString(QUuid::Id128)); const QString connectionName = QString("license_add_%1").arg(QUuid::createUuid().toString(QUuid::Id128));
LicenseItem output;
bool ok = false;
{ {
auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
db.setDatabaseName(DB_PATH); db.setDatabaseName(DB_PATH);
if (!db.open()) if (!db.open())
qDebug() << "db not open"; {
result.status = LicenseModel::Status::DbExistError;
result.error = "Database connection failed: " + db.lastError().text();
}
else else
{ {
QSqlQuery queryInsert(db); QSqlQuery queryInsert(db);
@@ -258,21 +265,31 @@ void LicenseModel::addClient(const LicenseItem &item)
queryInsert.bindValue(":comment", item.comment); queryInsert.bindValue(":comment", item.comment);
if (!queryInsert.exec()) if (!queryInsert.exec())
qDebug() << "queryInsert error" << queryInsert.lastError(); {
result.status = LicenseModel::Status::DbStructError;
result.error = queryInsert.lastError().text();
}
else else
{ {
QString itemId = QString::number(queryInsert.lastInsertId().toLongLong()); const QString itemId = QString::number(queryInsert.lastInsertId().toLongLong());
QSqlQuery querySelect(db); QSqlQuery querySelect(db);
querySelect.prepare(QString("SELECT * FROM clients WHERE id=:id;")); querySelect.prepare(QString("SELECT * FROM clients WHERE id=:id;"));
querySelect.bindValue(":id", itemId); querySelect.bindValue(":id", itemId);
if (!querySelect.exec()) if (!querySelect.exec())
qDebug() << "querySelect exec error" << querySelect.lastError(); {
result.status = LicenseModel::Status::DbStructError;
result.error = querySelect.lastError().text();
}
else if (!querySelect.next()) else if (!querySelect.next())
qDebug() << "querySelect no rows for id" << itemId; {
result.status = LicenseModel::Status::DbStructError;
result.error = "Inserted client not found: " + itemId;
}
else else
{ {
LicenseItem output;
output.id = itemId; output.id = itemId;
output.lastName = querySelect.value("lastName").toString(); output.lastName = querySelect.value("lastName").toString();
output.firstName = querySelect.value("firstName").toString(); output.firstName = querySelect.value("firstName").toString();
@@ -283,15 +300,16 @@ void LicenseModel::addClient(const LicenseItem &item)
output.yourCompany = querySelect.value("yourCompany").toString(); output.yourCompany = querySelect.value("yourCompany").toString();
output.hardwareHash = querySelect.value("hardwareHash").toString(); output.hardwareHash = querySelect.value("hardwareHash").toString();
output.comment = querySelect.value("comment").toString(); output.comment = querySelect.value("comment").toString();
ok = true; const int createdAtUtcIndex = querySelect.record().indexOf("createdAtUtc");
if (createdAtUtcIndex >= 0)
output.createdAtUtc = querySelect.value(createdAtUtcIndex).toString();
result.data.append(output);
} }
} }
} }
} }
QSqlDatabase::removeDatabase(connectionName); QSqlDatabase::removeDatabase(connectionName);
if (!ok) return result;
return LicenseItem();
return output;
})); }));
} }
@@ -311,9 +329,9 @@ void LicenseModel::deleteClient(const QList<int> &rows)
ids.append(id); ids.append(id);
} }
auto* watcher = new QFutureWatcher<DeleteResult>(this); auto* watcher = new QFutureWatcher<Result>(this);
connect(watcher, &QFutureWatcher<DeleteResult>::finished, this, [this, watcher]() { connect(watcher, &QFutureWatcher<Result>::finished, this, [this, watcher]() {
const DeleteResult result = watcher->result(); const Result result = watcher->result();
if (result.status != Status::Ok) if (result.status != Status::Ok)
{ {
m_status = result.status; m_status = result.status;
@@ -354,7 +372,7 @@ void LicenseModel::deleteClient(const QList<int> &rows)
}); });
watcher->setFuture(QtConcurrent::run([ids]() { watcher->setFuture(QtConcurrent::run([ids]() {
DeleteResult result; Result result;
result.ids = ids; result.ids = ids;
if (ids.isEmpty()) if (ids.isEmpty())
return result; return result;
@@ -399,8 +417,141 @@ void LicenseModel::editClient(const LicenseItem &item, int index)
m_status = Status::Working; m_status = Status::Working;
emit statusChanged(); emit statusChanged();
m_data[index] = item; if (index < 0 || index >= m_data.size())
dataChanged(this->index(index, 0), this->index(index, COLUMN_COUNT - 1)); {
m_status = Status::Ok;
emit statusChanged();
return;
}
LicenseItem updateItem = item;
updateItem.id = m_data[index].id;
if (updateItem.createdAtUtc.isEmpty())
updateItem.createdAtUtc = m_data[index].createdAtUtc;
if (updateItem.id.isEmpty())
{
m_status = Status::DbStructError;
m_errors.append("Client id is empty");
emit statusChanged();
return;
}
auto* watcher = new QFutureWatcher<Result>(this);
connect(watcher, &QFutureWatcher<Result>::finished, this, [this, watcher, index]() {
const Result result = watcher->result();
if (result.status != Status::Ok)
{
m_status = result.status;
if (!result.error.isEmpty())
m_errors.append(result.error);
emit statusChanged();
watcher->deleteLater();
return;
}
if (result.data.isEmpty())
{
m_status = Status::DbStructError;
m_errors.append("Updated client not found");
emit statusChanged();
watcher->deleteLater();
return;
}
if (index < 0 || index >= m_data.size())
{
m_status = Status::Ok;
emit statusChanged();
watcher->deleteLater();
return;
}
m_data[index] = result.data.first();
dataChanged(this->index(index, 0), this->index(index, COLUMN_COUNT - 1));
m_status = Status::Ok;
emit statusChanged();
watcher->deleteLater();
});
watcher->setFuture(QtConcurrent::run([updateItem]() {
Result result;
const QString connectionName = QString("license_edit_%1").arg(QUuid::createUuid().toString(QUuid::Id128));
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
db.setDatabaseName(DB_PATH);
if (!db.open())
{
result.status = LicenseModel::Status::DbExistError;
result.error = "Database connection failed: " + db.lastError().text();
}
else
{
QSqlQuery queryUpdate(db);
queryUpdate.prepare(QString(
"UPDATE clients SET lastName=:lastName, firstName=:firstName, patronymic=:patronymic, "
"phone=:phone, email=:email, city=:city, yourCompany=:yourCompany, hardwareHash=:hardwareHash, "
"comment=:comment WHERE id=:id;"
));
queryUpdate.bindValue(":lastName", updateItem.lastName);
queryUpdate.bindValue(":firstName", updateItem.firstName);
queryUpdate.bindValue(":patronymic", updateItem.patronymic);
queryUpdate.bindValue(":phone", updateItem.phone);
queryUpdate.bindValue(":email", updateItem.email);
queryUpdate.bindValue(":city", updateItem.city);
queryUpdate.bindValue(":yourCompany", updateItem.yourCompany);
queryUpdate.bindValue(":hardwareHash", updateItem.hardwareHash);
queryUpdate.bindValue(":comment", updateItem.comment);
queryUpdate.bindValue(":id", updateItem.id);
if (!queryUpdate.exec())
{
result.status = LicenseModel::Status::DbStructError;
result.error = queryUpdate.lastError().text();
}
else
{
QSqlQuery querySelect(db);
querySelect.prepare(QString("SELECT * FROM clients WHERE id=:id;"));
querySelect.bindValue(":id", updateItem.id);
if (!querySelect.exec())
{
result.status = LicenseModel::Status::DbStructError;
result.error = querySelect.lastError().text();
}
else if (!querySelect.next())
{
result.status = LicenseModel::Status::DbStructError;
result.error = "Updated client not found: " + updateItem.id;
}
else
{
LicenseItem output;
output.id = updateItem.id;
output.lastName = querySelect.value("lastName").toString();
output.firstName = querySelect.value("firstName").toString();
output.patronymic = querySelect.value("patronymic").toString();
output.phone = querySelect.value("phone").toString();
output.email = querySelect.value("email").toString();
output.city = querySelect.value("city").toString();
output.yourCompany = querySelect.value("yourCompany").toString();
output.hardwareHash = querySelect.value("hardwareHash").toString();
output.comment = querySelect.value("comment").toString();
const int createdAtUtcIndex = querySelect.record().indexOf("createdAtUtc");
if (createdAtUtcIndex >= 0)
output.createdAtUtc = querySelect.value(createdAtUtcIndex).toString();
else
output.createdAtUtc = updateItem.createdAtUtc;
result.data.append(output);
}
}
}
}
QSqlDatabase::removeDatabase(connectionName);
return result;
}));
} }
void LicenseModel::updateModel() void LicenseModel::updateModel()
@@ -408,9 +559,9 @@ void LicenseModel::updateModel()
m_status = Status::Working; m_status = Status::Working;
emit statusChanged(); emit statusChanged();
auto* watcher = new QFutureWatcher<LoadResult>(this); auto* watcher = new QFutureWatcher<Result>(this);
connect(watcher, &QFutureWatcher<LoadResult>::finished, this, [this, watcher]() { connect(watcher, &QFutureWatcher<Result>::finished, this, [this, watcher]() {
const LoadResult result = watcher->result(); const Result result = watcher->result();
if (result.status != Status::Ok) if (result.status != Status::Ok)
{ {
m_status = result.status; m_status = result.status;
@@ -431,7 +582,7 @@ void LicenseModel::updateModel()
}); });
watcher->setFuture(QtConcurrent::run([]() { watcher->setFuture(QtConcurrent::run([]() {
LoadResult result; Result result;
const QString connectionName = QString("license_load_%1") const QString connectionName = QString("license_load_%1")
.arg(QUuid::createUuid().toString(QUuid::Id128)); .arg(QUuid::createUuid().toString(QUuid::Id128));
{ {

View File

@@ -35,8 +35,15 @@ public:
QString comment; QString comment;
}; };
struct Result
{
QList<LicenseItem> data;
QStringList ids;
Status status = Status::Ok;
QString error;
};
explicit LicenseModel(QObject* parent = nullptr); explicit LicenseModel(QObject* parent = nullptr);
~LicenseModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
@@ -61,7 +68,6 @@ private:
QList<LicenseItem> m_data; QList<LicenseItem> m_data;
Status m_status = Status::None; Status m_status = Status::None;
QStringList m_errors; QStringList m_errors;
QSqlDatabase m_db;
}; };
#endif // LICENSEMANAGER_LICENSEMODEL_H #endif // LICENSEMANAGER_LICENSEMODEL_H

View File

@@ -184,7 +184,14 @@ void MainWidget::onDeleteClientTriggered()
for (auto i = selectedRows.size() - 1; i >= 0; --i) for (auto i = selectedRows.size() - 1; i >= 0; --i)
list << selectedRows.at(i).row(); list << selectedRows.at(i).row();
m_licenseModel->deleteClient(list); auto result = QMessageBox::question(
this,
tr("Delete rows"),
tr(QString("Do you want to delete %1 rows?").arg(list.size()).toUtf8())
);
if (result == QMessageBox::Yes)
m_licenseModel->deleteClient(list);
} }
void MainWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) void MainWidget::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)