diff --git a/tools/chatgui/src/renamedialog.cpp b/tools/chatgui/src/renamedialog.cpp index e0154b5f6..685de8370 100644 --- a/tools/chatgui/src/renamedialog.cpp +++ b/tools/chatgui/src/renamedialog.cpp @@ -1,6 +1,8 @@ #include #include "renamedialog.h" #include "../db/db_manager.h" +#include "../transport/member_edit.h" +#include "debug_config.h" #include #include #include @@ -19,18 +21,22 @@ RenameDialog::RenameDialog(DbManager* db, const QString& channelId, setModal(true); QString curNick; - if (m_db->m_db) { + bool loaded = false; + if (m_db && m_db->m_db) { QString tbl = m_db->peersTableName(channelId); QByteArray sql = QString( "SELECT local_nick FROM \"%1\" WHERE node_id=?" ).arg(tbl).toUtf8(); sqlite3_stmt* st = nullptr; - if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &st, nullptr) == SQLITE_OK) { - sqlite3_bind_int64(st, 1, (sqlite3_int64)nodeId); - if (sqlite3_step(st) == SQLITE_ROW) - curNick = DbManager::colText(st, 0); - sqlite3_finalize(st); - } + int rc = sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &st, nullptr); + if (rc == SQLITE_OK) rc = sqlite3_bind_int64(st, 1, (sqlite3_int64)nodeId); + if (rc == SQLITE_OK) rc = sqlite3_step(st); + if (rc == SQLITE_ROW) curNick = DbManager::colText(st, 0); + int finish = sqlite3_finalize(st); loaded = rc == SQLITE_ROW && finish == SQLITE_OK; + if (!loaded) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "rename: read ch=%s node=%016llx rc=%d finalize=%d: %s", + qPrintable(channelId), (unsigned long long)nodeId, rc, finish, sqlite3_errmsg(m_db->m_db)); + } else { + DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "rename: database unavailable at open"); } auto* layout = new QVBoxLayout(this); @@ -45,6 +51,9 @@ RenameDialog::RenameDialog(DbManager* db, const QString& channelId, m_edit->setText(curNick); m_edit->setPlaceholderText(displayName); layout->addWidget(m_edit); + m_errorLabel = new QLabel(this); m_errorLabel->setWordWrap(true); + if (!loaded) m_errorLabel->setText(QCoreApplication::translate("ChatGui", "Could not load member details.")); + layout->addWidget(m_errorLabel); layout->addStretch(); @@ -61,6 +70,7 @@ RenameDialog::RenameDialog(DbManager* db, const QString& channelId, btnLayout->addWidget(cancelBtn); auto* saveBtn = new QPushButton(QCoreApplication::translate("ChatGui", "Save"), this); + m_saveBtn = saveBtn; saveBtn->setMinimumWidth(90); saveBtn->setDefault(true); saveBtn->setStyleSheet( @@ -72,22 +82,26 @@ RenameDialog::RenameDialog(DbManager* db, const QString& channelId, btnLayout->addWidget(saveBtn); layout->addLayout(btnLayout); + connect(this, &QDialog::finished, this, [this] { + delete m_saveContext; m_saveContext = nullptr; + m_edit->setEnabled(true); m_saveBtn->setEnabled(true); + }); +} + +/* Результат адресован context запроса; после закрытия/удаления формы мост его не вызовет. */ +void RenameDialog::finishSave(int result) { + delete m_saveContext; m_saveContext = nullptr; + m_edit->setEnabled(true); m_saveBtn->setEnabled(true); + if (!result) { accept(); return; } + m_errorLabel->setText(QCoreApplication::translate("ChatGui", "Could not save member changes. Please try again.")); + DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "rename: save refused ch=%s node=%016llx result=%d", + qPrintable(m_channelId), (unsigned long long)m_nodeId, result); } void RenameDialog::onSave() { - if (!m_db->m_db) return; - QString tbl = m_db->peersTableName(m_channelId); - QString nick = m_edit->text().trimmed(); - QByteArray sql = QString( - "UPDATE \"%1\" SET local_nick=? WHERE node_id=?" - ).arg(tbl).toUtf8(); - sqlite3_stmt* st = nullptr; - if (sqlite3_prepare_v2(m_db->m_db, sql.constData(), -1, &st, nullptr) == SQLITE_OK) { - sqlite3_bind_text(st, 1, nick.isEmpty() ? nullptr : nick.toUtf8().constData(), - -1, nick.isEmpty() ? SQLITE_STATIC : SQLITE_TRANSIENT); - sqlite3_bind_int64(st, 2, (sqlite3_int64)m_nodeId); - sqlite3_step(st); - sqlite3_finalize(st); - } - accept(); + if (m_saveContext) return; + m_errorLabel->clear(); m_edit->setEnabled(false); m_saveBtn->setEnabled(false); + m_saveContext = new QObject(this); + if (!gui_bridge_save_member(m_db ? m_db->m_db : nullptr, m_channelId, m_nodeId, m_edit->text().trimmed(), {}, + m_saveContext, [this](int result) { finishSave(result); })) finishSave(-1); } diff --git a/tools/chatgui/src/renamedialog.h b/tools/chatgui/src/renamedialog.h index 87eee2289..20e7aeb05 100644 --- a/tools/chatgui/src/renamedialog.h +++ b/tools/chatgui/src/renamedialog.h @@ -1,25 +1,34 @@ -/* Локальное переименование участника: сохраняет local_nick в таблице peers канала для этого UI. */ +/* Локальный псевдоним участника: GUI только читает SQLite, запись подтверждает поток ядра. + * Отказ сохраняет форму и введённый текст; закрытие формы снимает callback, но не отменяет принятую запись. */ #pragma once #include #include #include +#include class DbManager; +class QLabel; +class QPushButton; class RenameDialog : public QDialog { Q_OBJECT public: + /* db заимствован через QPointer; channelId/nodeId выбирают строку, displayName — заголовок/подсказка, parent владеет диалогом. */ explicit RenameDialog(DbManager* db, const QString& channelId, quint64 nodeId, const QString& displayName, QWidget* parent = nullptr); private slots: - void onSave(); + void onSave(); // Передать собственный снимок ника в uasync; повтор до результата игнорируется. private: - DbManager* m_db; - QString m_channelId; - quint64 m_nodeId; - QLineEdit* m_edit; + void finishSave(int result); // GUI: 0 закрывает с Accepted, отказ возвращает редактирование и показывает ошибку. + QPointer m_db; // Заимствованная read-only проекция, может исчезнуть во время запроса. + QString m_channelId; // Собственный снимок канала. + quint64 m_nodeId; // Узел участника. + QLineEdit* m_edit; // Локальный черновик; пробелы по краям удаляются при сохранении. + QLabel* m_errorLabel; // Ошибка чтения/сохранения без технических подробностей. + QPushButton* m_saveBtn; // Отключена до результата. + QObject* m_saveContext = nullptr; // Собственный context одного запроса; удаляется при результате/закрытии. };