modernize: Replace most remaining old-style connects by PMF ones
[quassel.git] / src / qtui / coreinfodlg.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "coreinfodlg.h"
22
23 #include <QMessageBox>
24
25 #include "bufferwidget.h"
26 #include "client.h"
27 #include "icon.h"
28 #include "util.h"
29
30 CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) {
31     ui.setupUi(this);
32
33     // Listen for resynchronization events (pre-0.13 cores only)
34     connect(Client::instance(), &Client::coreInfoResynchronized,
35             this, &CoreInfoDlg::coreInfoResynchronized);
36
37     // Update legacy core info for Quassel cores earlier than 0.13.  This does nothing on modern
38     // cores.
39     refreshLegacyCoreInfo();
40
41     // Display existing core info, set up signal handlers
42     coreInfoResynchronized();
43
44     // Warning icon
45     ui.coreUnsupportedIcon->setPixmap(icon::get("dialog-warning").pixmap(16));
46
47     updateUptime();
48     startTimer(1000);
49 }
50
51
52 void CoreInfoDlg::refreshLegacyCoreInfo() {
53     if (!Client::isConnected() || Client::isCoreFeatureEnabled(Quassel::Feature::SyncedCoreInfo)) {
54         // If we're not connected, or the core supports SyncedCoreInfo (0.13+), bail out
55         return;
56     }
57
58     // Request legacy (pre-0.13) CoreInfo object to be resynchronized (does nothing on modern cores)
59     Client::refreshLegacyCoreInfo();
60
61     // On legacy cores, CoreInfo data does not send signals.  Periodically poll for information.
62     // 15 seconds seems like a reasonable trade-off as this only happens while the dialog is open.
63     QTimer::singleShot(15 * 1000, this, &CoreInfoDlg::refreshLegacyCoreInfo);
64 }
65
66
67 void CoreInfoDlg::coreInfoResynchronized() {
68     // CoreInfo object has been recreated, or this is the first time the dialog's been shown
69
70     CoreInfo *coreInfo = Client::coreInfo();
71     // Listen for changes to core information
72     connect(coreInfo, &CoreInfo::coreDataChanged,
73             this, &CoreInfoDlg::coreInfoChanged);
74
75     // Update with any known core information set before connecting the signal.  This is needed for
76     // both modern (0.13+) and legacy cores.
77     coreInfoChanged(coreInfo->coreData());
78 }
79
80
81 void CoreInfoDlg::coreInfoChanged(const QVariantMap &coreInfo) {
82     if(coreInfo.isEmpty()) {
83         // We're missing data for some reason
84         if (Client::isConnected()) {
85             // Core info is entirely empty despite being connected.  Something's probably wrong.
86             ui.labelCoreVersion->setText(tr("Unknown"));
87             ui.labelCoreVersionDate->setText(tr("Unknown"));
88         } else {
89             // We're disconnected.  Mark as such.
90             ui.labelCoreVersion->setText(tr("Disconnected from core"));
91             ui.labelCoreVersionDate->setText(tr("Not available"));
92         }
93         ui.labelClientCount->setNum(0);
94         // Don't return, allow the code below to remove any existing session widgets
95     } else {
96         ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString());
97         // "BuildDate" for compatibility
98         if (coreInfo["quasselBuildDate"].toString().isEmpty()) {
99             ui.labelCoreVersionDate->setText(QString("<i>%1</i>").arg(tr("Unknown date")));
100         }
101         else {
102             ui.labelCoreVersionDate->setText(
103                         tryFormatUnixEpoch(coreInfo["quasselBuildDate"].toString(),
104                         Qt::DateFormat::DefaultLocaleShortDate));
105         }
106         ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt());
107     }
108
109     auto coreSessionSupported = false;
110     auto ids = _widgets.keys();
111     for (const auto &peerData : coreInfo["sessionConnectedClientData"].toList()) {
112         coreSessionSupported = true;
113
114         auto peerMap = peerData.toMap();
115         int peerId = peerMap["id"].toInt();
116
117         ids.removeAll(peerId);
118
119         bool isNew = false;
120         CoreSessionWidget *coreSessionWidget = _widgets[peerId];
121         if (coreSessionWidget == nullptr) {
122             coreSessionWidget = new CoreSessionWidget(ui.coreSessionScrollContainer);
123             isNew = true;
124         }
125         coreSessionWidget->setData(peerMap);
126         if (isNew) {
127             _widgets[peerId] = coreSessionWidget;
128             // Add this to the end of the session list, but before the default layout stretch item.
129             // The layout stretch item should never be removed, so count should always be >= 1.
130             ui.coreSessionContainer->insertWidget(ui.coreSessionContainer->count() - 1,
131                                                   coreSessionWidget, 0, Qt::AlignTop);
132             connect(coreSessionWidget, &CoreSessionWidget::disconnectClicked, this, &CoreInfoDlg::disconnectClicked);
133         }
134     }
135
136     for (const auto &key : ids) {
137         delete _widgets[key];
138         _widgets.remove(key);
139     }
140
141     ui.coreSessionScrollArea->setVisible(coreSessionSupported);
142
143     // Hide the information bar when core sessions are supported or when disconnected
144     ui.coreUnsupportedWidget->setVisible(
145                 !(coreSessionSupported || Client::isConnected() == false));
146
147     // Update uptime for immediate display, don't wait for the timer
148     updateUptime();
149 }
150
151
152 void CoreInfoDlg::updateUptime() {
153     CoreInfo *coreInfo = Client::coreInfo();
154
155     if (!Client::isConnected()) {
156         // Not connected, don't bother trying to calculate the uptime
157         ui.labelUptime->setText(tr("Not available"));
158     } else if (coreInfo->coreData().isEmpty()) {
159         // Core info is entirely empty despite being connected.  Something's probably wrong.
160         ui.labelUptime->setText(tr("Unknown"));
161     } else {
162         // Connected, format the uptime for display
163         QDateTime startTime = coreInfo->at("startTime").toDateTime();
164
165         int64_t uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC());
166         int64_t updays = uptime / 86400;
167         uptime %= 86400;
168         int64_t uphours = uptime / 3600;
169         uptime %= 3600;
170         int64_t upmins = uptime / 60;
171         uptime %= 60;
172
173         QString uptimeText = tr("%n Day(s)", "", updays) +
174                              tr(" %1:%2:%3 (since %4)")
175                                      .arg(uphours, 2, 10, QChar('0'))
176                                      .arg(upmins, 2, 10, QChar('0'))
177                                      .arg(uptime, 2, 10, QChar('0'))
178                                      .arg(startTime.toLocalTime()
179                                           .toString(Qt::DefaultLocaleShortDate));
180         ui.labelUptime->setText(uptimeText);
181     }
182 }
183
184 void CoreInfoDlg::disconnectClicked(int peerId) {
185     Client::kickClient(peerId);
186 }
187
188 void CoreInfoDlg::on_coreUnsupportedDetails_clicked()
189 {
190     QMessageBox::warning(this,
191                          tr("Active sessions unsupported"),
192                          QString("<p><b>%1</b></p></br><p>%2</p>"
193                                  ).arg(tr("Your Quassel core is too old to show active sessions"),
194                                        tr("You need a Quassel core v0.13.0 or newer to view and "
195                                           "disconnect other connected clients.")));
196 }