_backlogManager(new ClientBacklogManager(this)),
_bufferViewManager(0),
_bufferViewOverlay(new BufferViewOverlay(this)),
- _coreInfo(nullptr),
+ _coreInfo(new CoreInfo(this)),
_dccConfig(0),
_ircListHelper(new ClientIrcListHelper(this)),
_inputHandler(0),
coreAccountModel()->load();
+ // Attach CoreInfo
+ p->synchronize(coreInfo());
+
connect(coreConnection(), SIGNAL(stateChanged(CoreConnection::ConnectionState)), SLOT(connectionStateChanged(CoreConnection::ConnectionState)));
coreConnection()->init();
}
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);
}
+void Client::requestLegacyCoreInfo()
+{
+ // On older cores, the CoreInfo object was only synchronized on demand. Synchronize now if
+ // needed.
+ if (isConnected() && !isCoreFeatureEnabled(Quassel::Feature::SyncedCoreInfo)) {
+ // Delete the existing core info object (it will always exist as client is single-threaded)
+ _coreInfo->deleteLater();
+ // No need to set to null when creating new one immediately after
+
+ // Create a fresh, unsynchronized CoreInfo object, emulating legacy behavior of CoreInfo not
+ // persisting
+ _coreInfo = new CoreInfo(this);
+ // Synchronize the new object
+ signalProxy()->synchronize(_coreInfo);
+
+ // Let others know signal handlers have been reset
+ emit coreInfoResynchronized();
+ }
+}
+
+
void Client::disconnectFromCore()
{
if (!coreConnection()->isConnected())
_bufferSyncer = 0;
}
- if (_coreInfo) {
- _coreInfo->deleteLater();
- _coreInfo = nullptr;
- }
+ _coreInfo->reset();
if (_bufferViewManager) {
_bufferViewManager->deleteLater();
}
+void Client::refreshLegacyCoreInfo()
+{
+ instance()->requestLegacyCoreInfo();
+}
+
+
void Client::changePassword(const QString &oldPassword, const QString &newPassword) {
CoreAccount account = currentCoreAccount();
account.setPassword(newPassword);
static void mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2);
static void purgeKnownBufferIds();
+ /**
+ * Requests client to resynchronize the CoreInfo object for legacy (pre-0.13) cores
+ *
+ * This provides compatibility with updating core information for legacy cores, and can be
+ * removed after protocol break.
+ *
+ * NOTE: On legacy (pre-0.13) cores, any existing connected signals will be destroyed and must
+ * be re-added after calling this, in addition to checking for existing data in coreInfo().
+ */
+ static void refreshLegacyCoreInfo();
+
static void changePassword(const QString &oldPassword, const QString &newPassword);
static void kickClient(int peerId);
void disconnected();
void coreConnectionStateChanged(bool);
+ /**
+ * Signals that core information has been resynchronized, removing existing signal handlers
+ *
+ * Whenever this is emitted, one should re-add any handlers for CoreInfo::coreDataChanged() and
+ * apply any existing information in the coreInfo() object.
+ *
+ * Only emitted on legacy (pre-0.13) cores. Generally, one should use the
+ * CoreInfo::coreDataChanged() signal too.
+ */
+ void coreInfoResynchronized();
+
//! The identity with the given ID has been newly created in core and client.
/** \param id The ID of the newly created identity.
*/
void requestInitialBacklog();
+ /**
+ * Deletes and resynchronizes the CoreInfo object for legacy (pre-0.13) cores
+ *
+ * This provides compatibility with updating core information for legacy cores, and can be
+ * removed after protocol break.
+ *
+ * NOTE: On legacy (pre-0.13) cores, any existing connected signals will be destroyed and must
+ * be re-added after calling this, in addition to checking for existing data in coreInfo().
+ */
+ void requestLegacyCoreInfo();
+
static void addNetwork(Network *);
static QPointer<Client> instanceptr;
_coreData["sessionConnectedClientData"] = peerData;
setCoreData(_coreData);
}
+
+void CoreInfo::reset()
+{
+ // Clear any stored data
+ _coreData.clear();
+ // Propagate changes to listeners
+ emit coreDataChanged(_coreData);
+}
void setConnectedClientData(int, QVariantList);
+ /**
+ * Reset the core info state, clearing anything saved
+ */
+ void reset();
+
signals:
+ /**
+ * Signals that core information has changed
+ */
void coreDataChanged(QVariantMap);
public slots:
EcdsaCertfpKeys, ///< ECDSA keys for CertFP in identities
#endif
LongMessageId, ///< 64-bit IDs for messages
+ SyncedCoreInfo, ///< CoreInfo dynamically updated using signals
};
Q_ENUMS(Feature)
CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) {
ui.setupUi(this);
- CoreInfo *coreInfo = Client::coreInfo();
- connect(coreInfo, SIGNAL(coreDataChanged(const QVariantMap &)), this, SLOT(coreInfoChanged(const QVariantMap &)));
- coreInfoChanged(coreInfo->coreData());
+ // Listen for resynchronization events (pre-0.13 cores only)
+ connect(Client::instance(), SIGNAL(coreInfoResynchronized()),
+ this, SLOT(coreInfoResynchronized()));
+
+ // Update legacy core info for Quassel cores earlier than 0.13. This does nothing on modern
+ // cores.
+ Client::refreshLegacyCoreInfo();
+
+ // Display existing core info, set up signal handlers
+ coreInfoResynchronized();
// Warning icon
ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16));
}
+void CoreInfoDlg::coreInfoResynchronized() {
+ // CoreInfo object has been recreated, or this is the first time the dialog's been shown
+
+ CoreInfo *coreInfo = Client::coreInfo();
+ // Listen for changes to core information
+ connect(coreInfo, SIGNAL(coreDataChanged(const QVariantMap &)),
+ this, SLOT(coreInfoChanged(const QVariantMap &)));
+
+ // Update with any known core information set before connecting the signal. This is needed for
+ // both modern (0.13+) and legacy cores.
+ coreInfoChanged(coreInfo->coreData());
+}
+
+
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());
+ if(coreInfo.isEmpty()) {
+ // We're missing data for some reason
+ if (Client::isConnected()) {
+ // Core info is entirely empty despite being connected. Something's probably wrong.
+ ui.labelCoreVersion->setText(tr("Unknown"));
+ ui.labelCoreVersionDate->setText(tr("Unknown"));
+ } else {
+ // We're disconnected. Mark as such.
+ ui.labelCoreVersion->setText(tr("Disconnected from core"));
+ ui.labelCoreVersionDate->setText(tr("Not available"));
+ }
+ ui.labelClientCount->setNum(0);
+ // Don't return, allow the code below to remove any existing session widgets
+ } else {
+ ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString());
+ // "BuildDate" for compatibility
+ ui.labelCoreVersionDate->setText(coreInfo["quasselBuildDate"].toString());
+ ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt());
+ }
auto coreSessionSupported = false;
auto ids = _widgets.keys();
ui.coreSessionScrollArea->setVisible(coreSessionSupported);
- // Hide the information bar when core sessions are supported
- ui.coreUnsupportedWidget->setVisible(!coreSessionSupported);
+ // Hide the information bar when core sessions are supported or when disconnected
+ ui.coreUnsupportedWidget->setVisible(
+ !(coreSessionSupported || Client::isConnected() == false));
+
+ // Update uptime for immediate display, don't wait for the timer
+ updateUptime();
}
void CoreInfoDlg::updateUptime() {
CoreInfo *coreInfo = Client::coreInfo();
- if (coreInfo) {
+
+ if (!Client::isConnected()) {
+ // Not connected, don't bother trying to calculate the uptime
+ ui.labelUptime->setText(tr("Not available"));
+ } else if (coreInfo->coreData().isEmpty()) {
+ // Core info is entirely empty despite being connected. Something's probably wrong.
+ ui.labelUptime->setText(tr("Unknown"));
+ } else {
+ // Connected, format the uptime for display
QDateTime startTime = coreInfo->at("startTime").toDateTime();
int64_t uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC());
void timerEvent(QTimerEvent *) override { updateUptime(); }
private slots:
+ /**
+ * Handler for recreation of CoreInfo object, including first-time setup
+ *
+ * Applies existing CoreInfo information to the dialog, too.
+ */
+ void coreInfoResynchronized();
+
void on_closeButton_clicked() { reject(); }
void updateUptime();
void disconnectClicked(int peerId);