From bd5414d8bfe2be18ba051d4bbf936e9ead0cdf66 Mon Sep 17 00:00:00 2001 From: Janne Koschinski Date: Thu, 1 Mar 2018 21:04:50 -0600 Subject: [PATCH] Automatically synchronize CoreInfo when on connect and disconnect This refactors CoreInfo to be a single common class rather than separate classes for the core and client, adjusts it to properly use the SyncableObject infrastructure, and adds support for dynamically updating the list on both the client and core when a client connects or disconnects, keeping the list up-to-date at all times. Forwards and backwards compatibility is maintained, though the updated client is required in order for the automatic updating to work. Signed-off-by: Janne Koschinski Co-authored-by: Janne Koschinski Co-authored-by: Michael Marley --- src/client/CMakeLists.txt | 1 - src/client/client.cpp | 11 +++ src/client/client.h | 3 + src/client/clientcoreinfo.h | 50 ---------- src/common/CMakeLists.txt | 2 +- .../corecoreinfo.h => common/coreinfo.cpp} | 41 ++++---- src/common/coreinfo.h | 28 +++--- src/core/CMakeLists.txt | 1 - src/core/corecoreinfo.cpp | 45 --------- src/core/coresession.cpp | 14 ++- src/core/coresession.h | 4 +- src/qtui/coreinfodlg.cpp | 93 ++++++++++++------- src/qtui/coreinfodlg.h | 24 ++--- 13 files changed, 130 insertions(+), 187 deletions(-) delete mode 100644 src/client/clientcoreinfo.h rename src/{core/corecoreinfo.h => common/coreinfo.cpp} (72%) delete mode 100644 src/core/corecoreinfo.cpp diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index f0733f01..7e171d25 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -36,7 +36,6 @@ set(SOURCES # needed for automoc abstractui.h - clientcoreinfo.h ) if (USE_QT5) diff --git a/src/client/client.cpp b/src/client/client.cpp index f8627d02..0c71befb 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -101,6 +101,7 @@ Client::Client(QObject *parent) _backlogManager(new ClientBacklogManager(this)), _bufferViewManager(0), _bufferViewOverlay(new BufferViewOverlay(this)), + _coreInfo(nullptr), _dccConfig(0), _ircListHelper(new ClientIrcListHelper(this)), _inputHandler(0), @@ -400,6 +401,11 @@ void Client::setSyncedToCore() SignalProxy *p = signalProxy(); p->synchronize(bufferSyncer()); + // create CoreInfo + Q_ASSERT(!_coreInfo); + _coreInfo = new CoreInfo(this); + p->synchronize(coreInfo()); + // create a new BufferViewManager Q_ASSERT(!_bufferViewManager); _bufferViewManager = new ClientBufferViewManager(p, this); @@ -500,6 +506,11 @@ void Client::setDisconnectedFromCore() _bufferSyncer = 0; } + if (_coreInfo) { + _coreInfo->deleteLater(); + _coreInfo = nullptr; + } + if (_bufferViewManager) { _bufferViewManager->deleteLater(); _bufferViewManager = 0; diff --git a/src/client/client.h b/src/client/client.h index 4b8c4bcf..3dc261a4 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -24,6 +24,7 @@ #include #include "bufferinfo.h" +#include "coreinfo.h" #include "coreaccount.h" #include "coreconnection.h" #include "highlightrulemanager.h" @@ -115,6 +116,7 @@ public: static inline ClientAliasManager *aliasManager() { return instance()->_aliasManager; } static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; } + static inline CoreInfo *coreInfo() { return instance()->_coreInfo; } static inline DccConfig *dccConfig() { return instance()->_dccConfig; } static inline ClientIrcListHelper *ircListHelper() { return instance()->_ircListHelper; } static inline ClientBufferViewManager *bufferViewManager() { return instance()->_bufferViewManager; } @@ -264,6 +266,7 @@ private: ClientBacklogManager *_backlogManager; ClientBufferViewManager *_bufferViewManager; BufferViewOverlay *_bufferViewOverlay; + CoreInfo *_coreInfo; DccConfig *_dccConfig; ClientIrcListHelper *_ircListHelper; ClientUserInputHandler *_inputHandler; diff --git a/src/client/clientcoreinfo.h b/src/client/clientcoreinfo.h deleted file mode 100644 index 60a96d01..00000000 --- a/src/client/clientcoreinfo.h +++ /dev/null @@ -1,50 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005-2018 by the Quassel Project * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) version 3. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef CLIENTCOREINFO_H -#define CLIENTCOREINFO_H - -#include "coreinfo.h" - -/* - * Yes this name is somewhat stupid... but it fits the general naming scheme - * which is prefixing client specific sync objects with "Client"... ;) - */ -class ClientCoreInfo : public CoreInfo -{ - Q_OBJECT - SYNCABLE_OBJECT - -public: - ClientCoreInfo(QObject *parent = 0) : CoreInfo(parent) {} - - inline virtual const QMetaObject *syncMetaObject() const { return &CoreInfo::staticMetaObject; } - - inline QVariant &operator[](const QString &key) { return _coreData[key]; } - -public slots: - inline virtual void setCoreData(const QVariantMap &data) { _coreData = data; } - -private: - QVariantMap _coreData; -}; - - -#endif //CLIENTCOREINFO_H diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8ec2bed8..d330d2c1 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -10,6 +10,7 @@ set(SOURCES bufferviewconfig.cpp bufferviewmanager.cpp compressor.cpp + coreinfo.cpp ctcpevent.cpp dccconfig.cpp event.cpp @@ -47,7 +48,6 @@ set(SOURCES protocols/legacy/legacypeer.cpp # needed for automoc - coreinfo.h irccap.h protocol.h ) diff --git a/src/core/corecoreinfo.h b/src/common/coreinfo.cpp similarity index 72% rename from src/core/corecoreinfo.h rename to src/common/coreinfo.cpp index 991ebf90..e4019c7a 100644 --- a/src/core/corecoreinfo.h +++ b/src/common/coreinfo.cpp @@ -18,33 +18,26 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef CORECOREINFO_H -#define CORECOREINFO_H - #include "coreinfo.h" -class CoreSession; +INIT_SYNCABLE_OBJECT(CoreInfo) +CoreInfo::CoreInfo(QObject *parent) : SyncableObject(parent) {} -/* - * Yes this name is somewhat stupid... but it fits the general naming scheme - * which is prefixing core specific sync objects with "Core"... ;) - */ -class CoreCoreInfo : public CoreInfo +QVariantMap CoreInfo::coreData() const { - SYNCABLE_OBJECT - Q_OBJECT - -public: - CoreCoreInfo(CoreSession *parent); - - inline virtual const QMetaObject *syncMetaObject() const { return &CoreInfo::staticMetaObject; } - -public slots: - virtual QVariantMap coreData() const; - -private: - CoreSession *_coreSession; -}; + return _coreData; +} +void CoreInfo::setCoreData(const QVariantMap &coreData) +{ + _coreData = coreData; + SYNC(ARG(coreData)); + emit coreDataChanged(coreData); +} -#endif //CORECOREINFO_H +void CoreInfo::setConnectedClientData(const int peerCount, const QVariantList peerData) +{ + _coreData["sessionConnectedClients"] = peerCount; + _coreData["sessionConnectedClientData"] = peerData; + setCoreData(_coreData); +} diff --git a/src/common/coreinfo.h b/src/common/coreinfo.h index 291f5a1e..26879d4c 100644 --- a/src/common/coreinfo.h +++ b/src/common/coreinfo.h @@ -18,28 +18,34 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef COREINFO_H -#define COREINFO_H +#pragma once #include "syncableobject.h" /* - * gather various informations about the core. + * gather various information about the core. */ class CoreInfo : public SyncableObject { Q_OBJECT + SYNCABLE_OBJECT - Q_PROPERTY(QVariantMap coreData READ coreData WRITE setCoreData STORED false) + Q_PROPERTY(QVariantMap coreData READ coreData WRITE setCoreData) -public : - CoreInfo(QObject *parent = 0) : SyncableObject(parent) {} +public: + explicit CoreInfo(QObject *parent = nullptr); + inline QVariant &at(const QString &key) { return _coreData[key]; } -public slots: - virtual inline QVariantMap coreData() const { return QVariantMap(); } - virtual inline void setCoreData(const QVariantMap &) {} -}; + void setConnectedClientData(int, QVariantList); +signals: + void coreDataChanged(QVariantMap); -#endif //COREINFO_H +public slots: + QVariantMap coreData() const; + void setCoreData(const QVariantMap &); + +private: + QVariantMap _coreData; +}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1ec6797d..be5133b9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -12,7 +12,6 @@ set(SOURCES corebuffersyncer.cpp corebufferviewconfig.cpp corebufferviewmanager.cpp - corecoreinfo.cpp coredccconfig.cpp corehighlightrulemanager.cpp coreidentity.cpp diff --git a/src/core/corecoreinfo.cpp b/src/core/corecoreinfo.cpp deleted file mode 100644 index b92e4d44..00000000 --- a/src/core/corecoreinfo.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2005-2018 by the Quassel Project * - * devel@quassel-irc.org * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) version 3. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include "corecoreinfo.h" - -#include "core.h" -#include "coresession.h" -#include "quassel.h" -#include "signalproxy.h" - -INIT_SYNCABLE_OBJECT(CoreCoreInfo) -CoreCoreInfo::CoreCoreInfo(CoreSession *parent) - : CoreInfo(parent), - _coreSession(parent) -{ -} - - -QVariantMap CoreCoreInfo::coreData() const -{ - QVariantMap data; - data["quasselVersion"] = Quassel::buildInfo().fancyVersionString; - data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility - data["startTime"] = Core::instance()->startTime(); - data["sessionConnectedClients"] = _coreSession->signalProxy()->peerCount(); - data["sessionConnectedClientData"] = _coreSession->signalProxy()->peerData(); - return data; -} diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 64f46088..afaf48de 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -31,6 +31,7 @@ #include "coreeventmanager.h" #include "coreidentity.h" #include "coreignorelistmanager.h" +#include "coreinfo.h" #include "coreirclisthelper.h" #include "corenetwork.h" #include "corenetworkconfig.h" @@ -68,7 +69,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) _dccConfig(new CoreDccConfig(this)), _ircListHelper(new CoreIrcListHelper(this)), _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)), - _coreInfo(this), + _coreInfo(new CoreInfo(this)), _transferManager(new CoreTransferManager(this)), _eventManager(new CoreEventManager(this)), _eventStringifier(new EventStringifier(this)), @@ -109,6 +110,13 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->attachSlot(SIGNAL(kickClient(int)), this, SLOT(kickClient(int))); p->attachSignal(this, SIGNAL(disconnectFromCore())); + QVariantMap data; + data["quasselVersion"] = Quassel::buildInfo().fancyVersionString; + data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility + data["startTime"] = Core::instance()->startTime(); + data["sessionConnectedClients"] = 0; + _coreInfo->setCoreData(data); + loadSettings(); initScriptEngine(); @@ -130,7 +138,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->synchronize(dccConfig()); p->synchronize(ircListHelper()); p->synchronize(networkConfig()); - p->synchronize(&_coreInfo); + p->synchronize(_coreInfo); p->synchronize(&_ignoreListManager); p->synchronize(&_highlightRuleManager); p->synchronize(transferManager()); @@ -266,6 +274,7 @@ void CoreSession::addClient(RemotePeer *peer) peer->dispatch(sessionState()); signalProxy()->addPeer(peer); + _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData()); signalProxy()->setTargetPeer(nullptr); } @@ -283,6 +292,7 @@ void CoreSession::removeClient(Peer *peer) RemotePeer *p = qobject_cast(peer); if (p) quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt())); + _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData()); } diff --git a/src/core/coresession.h b/src/core/coresession.h index 72843a5f..e13ff64f 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -24,7 +24,7 @@ #include #include -#include "corecoreinfo.h" +#include "coreinfo.h" #include "corealiasmanager.h" #include "corehighlightrulemanager.h" #include "coreignorelistmanager.h" @@ -223,7 +223,7 @@ private: CoreDccConfig *_dccConfig; CoreIrcListHelper *_ircListHelper; CoreNetworkConfig *_networkConfig; - CoreCoreInfo _coreInfo; + CoreInfo *_coreInfo; CoreTransferManager *_transferManager; EventManager *_eventManager; diff --git a/src/qtui/coreinfodlg.cpp b/src/qtui/coreinfodlg.cpp index 35528803..e5eb7f4c 100644 --- a/src/qtui/coreinfodlg.cpp +++ b/src/qtui/coreinfodlg.cpp @@ -20,62 +20,83 @@ #include "coreinfodlg.h" -#include - #include "client.h" -#include "signalproxy.h" #include "bufferwidget.h" -#include "coresessionwidget.h" -CoreInfoDlg::CoreInfoDlg(QWidget *parent) - : QDialog(parent), - _coreInfo(this) -{ +CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) { ui.setupUi(this); - connect(&_coreInfo, SIGNAL(initDone()), this, SLOT(coreInfoAvailable())); - Client::signalProxy()->synchronize(&_coreInfo); + CoreInfo *coreInfo = Client::coreInfo(); + connect(coreInfo, SIGNAL(coreDataChanged(const QVariantMap &)), this, SLOT(coreInfoChanged(const QVariantMap &))); + + coreInfoChanged(coreInfo->coreData()); + + updateUptime(); + startTimer(1000); } -void CoreInfoDlg::coreInfoAvailable() -{ - ui.labelCoreVersion->setText(_coreInfo["quasselVersion"].toString()); - ui.labelCoreVersionDate->setText(_coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility - ui.labelClientCount->setNum(_coreInfo["sessionConnectedClients"].toInt()); +void CoreInfoDlg::coreInfoChanged(const QVariantMap &coreInfo) { + ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString()); + ui.labelCoreVersionDate->setText(coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility + ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt()); auto coreSessionSupported = false; - for (const auto &peerData : _coreInfo["sessionConnectedClientData"].toList()) { + auto ids = _widgets.keys(); + for (const auto &peerData : coreInfo["sessionConnectedClientData"].toList()) { coreSessionSupported = true; - auto coreSessionWidget = new CoreSessionWidget(ui.coreSessionScrollContainer); - coreSessionWidget->setData(peerData.toMap()); - ui.coreSessionContainer->addWidget(coreSessionWidget); - connect(coreSessionWidget, SIGNAL(disconnectClicked(int)), this, SLOT(disconnectClicked(int))); + auto peerMap = peerData.toMap(); + int peerId = peerMap["id"].toInt(); + + ids.removeAll(peerId); + + bool isNew = false; + CoreSessionWidget *coreSessionWidget = _widgets[peerId]; + if (coreSessionWidget == nullptr) { + coreSessionWidget = new CoreSessionWidget(ui.coreSessionScrollContainer); + isNew = true; + } + coreSessionWidget->setData(peerMap); + if (isNew) { + _widgets[peerId] = coreSessionWidget; + ui.coreSessionContainer->addWidget(coreSessionWidget); + connect(coreSessionWidget, SIGNAL(disconnectClicked(int)), this, SLOT(disconnectClicked(int))); + } } - ui.coreSessionScrollArea->setVisible(coreSessionSupported); + for (const auto &key : ids) { + delete _widgets[key]; + _widgets.remove(key); + } + ui.coreSessionScrollArea->setVisible(coreSessionSupported); ui.coreSessionContainer->addStretch(1); - - updateUptime(); - startTimer(1000); } -void CoreInfoDlg::updateUptime() -{ - QDateTime startTime = _coreInfo["startTime"].toDateTime(); +void CoreInfoDlg::updateUptime() { + CoreInfo *coreInfo = Client::coreInfo(); + if (coreInfo) { + QDateTime startTime = coreInfo->at("startTime").toDateTime(); - int uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC()); - int updays = uptime / 86400; uptime %= 86400; - int uphours = uptime / 3600; uptime %= 3600; - int upmins = uptime / 60; uptime %= 60; + int64_t uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC()); + int64_t updays = uptime / 86400; + uptime %= 86400; + int64_t uphours = uptime / 3600; + uptime %= 3600; + int64_t upmins = uptime / 60; + uptime %= 60; - QString uptimeText = tr("%n Day(s)", "", updays) - + tr(" %1:%2:%3 (since %4)").arg(uphours, 2, 10, QChar('0')).arg(upmins, 2, 10, QChar('0')).arg(uptime, 2, 10, QChar('0')).arg(startTime.toLocalTime().toString(Qt::TextDate)); - ui.labelUptime->setText(uptimeText); + QString uptimeText = tr("%n Day(s)", "", updays) + + tr(" %1:%2:%3 (since %4)") + .arg(uphours, 2, 10, QChar('0')) + .arg(upmins, 2, 10, QChar('0')) + .arg(uptime, 2, 10, QChar('0')) + .arg(startTime.toLocalTime().toString(Qt::TextDate)); + ui.labelUptime->setText(uptimeText); + } } -void CoreInfoDlg::disconnectClicked(int peerId) -{ + +void CoreInfoDlg::disconnectClicked(int peerId) { Client::kickClient(peerId); } diff --git a/src/qtui/coreinfodlg.h b/src/qtui/coreinfodlg.h index 038c4270..85a92116 100644 --- a/src/qtui/coreinfodlg.h +++ b/src/qtui/coreinfodlg.h @@ -18,26 +18,25 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef COREINFODLG_H -#define COREINFODLG_H +#pragma once -#include "ui_coreinfodlg.h" #include -#include "clientcoreinfo.h" +#include "ui_coreinfodlg.h" +#include "coreinfo.h" +#include "coresessionwidget.h" -class CoreInfoDlg : public QDialog -{ - Q_OBJECT +class CoreInfoDlg : public QDialog { +Q_OBJECT public: - CoreInfoDlg(QWidget *parent = 0); + explicit CoreInfoDlg(QWidget *parent = nullptr); public slots: - void coreInfoAvailable(); + void coreInfoChanged(const QVariantMap &); protected: - virtual void timerEvent(QTimerEvent *) { updateUptime(); } + void timerEvent(QTimerEvent *) override { updateUptime(); } private slots: void on_closeButton_clicked() { reject(); } @@ -46,8 +45,5 @@ private slots: private: Ui::CoreInfoDlg ui; - ClientCoreInfo _coreInfo; + QMap _widgets; }; - - -#endif //COREINFODLG_H -- 2.20.1