Document channel list lifetime and validate row counters

This commit is contained in:
evgeny committed 2026-10-27 10:56:43 +01:00
1 parent 8552cf8316
commit 1e3633ee56
2 files changed
+41 -11

No files matched your search

+6
View File
@@ -453,6 +453,9 @@ void ChannelList::selectChannel(const QString& channelId) {
}
void ChannelList::setChannelPeersOnline(const QString& channelId, int count) {
if (count < 0) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "ChannelList: invalid online count=%d channel=%s", count, qPrintable(channelId)); return;
}
int found = 0;
for (int row = 0; row < m_model->rowCount(); row++) {
QStandardItem* item = m_model->item(row);
@@ -480,6 +483,9 @@ void ChannelList::setAutoConnectActive(bool active) {
}
void ChannelList::setChannelUnreadCount(const QString& channelId, int count) {
if (count < 0) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT, "ChannelList: invalid unread count=%d channel=%s", count, qPrintable(channelId)); return;
}
for (int row = 0; row < m_model->rowCount(); row++) {
QStandardItem* item = m_model->item(row);
if (item && item->data(ChannelChannelIdRole).toString() == channelId) {
+35 -11
View File
@@ -1,5 +1,8 @@
/* Список каналов и PM с unread/online; загружает данные DbManager и принимает обновления bridge.
* Выбор и действия пользователя передаёт наружу signals; виджет используется в GUI-потоке. */
/* Список каналов и PM с unread/online; все методы и события используются в GUI-потоке.
* DbManager заимствуется через QPointer; setDb/закрытие SQLite остаются обязанностью владельца БД.
* loadChannels() читает самостоятельные снимки БД, bridge-события передаёт сюда внешний контроллер.
* Собственные дочерние model/view/timer принадлежат виджету. Изменения ядра запрашиваются signals.
* Контекстное меню хранит ID цели и проверяет наличие строки/поколение PM после вложенного event loop. */
#pragma once
#include <QWidget>
@@ -18,43 +21,64 @@ class CpuLoadIndicator;
class ChannelList : public QWidget {
Q_OBJECT
public:
/* Создаёт виджет с необязательной БД (без неё список пуст); parent владеет виджетом. */
explicit ChannelList(DbManager* db = nullptr, QWidget *parent = nullptr);
/* Перечитывает список/непрочитанные из БД. Сохраняет выбор и онлайн-счётчики существующих групп;
* если выбранная строка исчезла, выбирает первую доступную группу/PM. Выбор испускает channelSelected. */
void loadChannels();
/* Объединяет запросы в один запуск через 50 мс; таймер не периодический.
* Отправляет owned-команды маршрута для видимых в БД PM; при недоступном ядре сбрасывает их online. */
void refreshDmPresence();
/* Принимает заимствованный снимок [conv_len:1][UTF-8 conv][peer:8][group:8], числа native-endian.
* Проверяет точную длину; online = ненулевые peer и group, это доступность BGP-маршрута. */
void onDmCallRoute(const uint8_t* data, int len);
/* Останавливает отложенный запрос и сбрасывает кеш/точки доступности PM; не отменяет уже отправленные команды. */
void clearDmPresence();
/* Отмечает ожидающее удаление поколения PM; повторное действие в меню недоступно до результата. */
void setDmDeleting(const QString& convId, quint64 generation, bool deleting);
/* Выбирает существующий ID группы или "dm:<conv_id>"; пустой/неизвестный ID сохраняет текущий выбор. */
void selectChannel(const QString& channelId);
/* Обновляет онлайн-счётчик существующей строки; отрицательное count отклоняется с предупреждением. */
void setChannelPeersOnline(const QString& channelId, int count);
/* Задаёт общий индикатор автоподключения для существующих и последующих строк групп. */
void setAutoConnectActive(bool active);
/* Показывает процент CPU, ограниченный диапазоном 0..100. */
void setCpuLoad(int percent);
/* Задаёт unread существующей строки; отрицательное count отклоняется, изменившаяся роль уведомляется один раз. */
void setChannelUnreadCount(const QString& channelId, int count);
/* Возвращает unread строки либо 0, если ID отсутствует. */
int getChannelUnreadCount(const QString& channelId) const;
signals:
/* Выбрана строка (также после loadChannels); ID для PM имеет префикс "dm:". */
void channelSelected(const QString& channelId);
/* Запрос контроллеру подтвердить/удалить поколение PM; convId без префикса. */
void dmDeleteRequested(const QString& convId, quint64 generation, const QString& name);
/* Открыть файлы захваченной меню группы, если она по-прежнему присутствует в списке. */
void filesRequested(const QString& channelId);
/* Приняты локальные пути с CopyAction для выбранной числовой группы при готовом ядре/своём node ID.
* Сигнал отложен до следующей итерации Qt, paths копируются; проверка файлов/загрузка — у получателя. */
void ownFilesDropped(const QString& channelId, const QStringList& paths);
/* Кнопки footer: присоединиться, создать группу, настройки и монитор соединений. */
void joinRequested();
void createGroupRequested();
void settingsRequested();
void connMonitorRequested();
protected:
/* Принимает drag/drop в footer; фильтры устанавливаются на него и его кнопки/подписи. */
bool eventFilter(QObject* target, QEvent* event) override;
private:
QListView *m_listView;
QStandardItemModel *m_model;
QPointer<DbManager> m_db;
QWidget *m_footer;
QLabel *m_dropHint;
bool m_autoConnectActive = false;
QHash<QString, bool> m_dmOnline;
QListView *m_listView; /* Дочерний view; секции не выбираются мышью. */
QStandardItemModel *m_model; /* Дочерняя плоская модель, роли из channeldelegate.h. */
QPointer<DbManager> m_db; /* Не владеет БД; обнуляется при уничтожении QObject. */
QWidget *m_footer; /* Дочерняя панель действий и приёма файлов. */
QLabel *m_dropHint; /* Дочерняя footer-подсказка, не перехватывает мышь. */
bool m_autoConnectActive = false; /* Общее состояние автоподключения групп. */
QHash<QString, bool> m_dmOnline; /* Последние снимки доступности conv_id, сохраняются при reload. */
QHash<QString, quint64> m_dmDeleting; /* conv_id → поколение ожидающего удаления */
QTimer* m_dmPresenceTimer;
CpuLoadIndicator* m_cpuLoad;
QTimer* m_dmPresenceTimer; /* Дочерний single-shot, debounce 50 мс. */
CpuLoadIndicator* m_cpuLoad; /* Дочерний индикатор CPU 0..100. */
};