Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Adam <dev@robert-adam.de>2021-03-28 19:58:34 +0300
committerRobert Adam <dev@robert-adam.de>2021-03-28 21:23:38 +0300
commit5fabceee9daeb53d76e804b2e54a6855a48151ac (patch)
tree1e3555fb59a40bfee3ade2f2964d18c5137fda17 /src
parent604427ccdd2c36804d55dad72367abb27f0d2433 (diff)
FEAT(client, ui): Revamped server information dialog
The previous dialog was simply a message box with a bunch of HTML in order to give a little structure to the contents. This approach is very limiting in terms of UI flexibility though and therefore this commit replaces the old HTML approach with a dedicated dialog class that uses proper UI elements instead. While doing so, the ordering and grouping of information was also changed in order to make it more suitable for the every-day-user. Fixes #4733
Diffstat (limited to 'src')
-rw-r--r--src/mumble/CMakeLists.txt3
-rw-r--r--src/mumble/MainWindow.cpp134
-rw-r--r--src/mumble/ServerInformation.cpp199
-rw-r--r--src/mumble/ServerInformation.h37
-rw-r--r--src/mumble/ServerInformation.ui643
5 files changed, 885 insertions, 131 deletions
diff --git a/src/mumble/CMakeLists.txt b/src/mumble/CMakeLists.txt
index 96266ee8f..e90272181 100644
--- a/src/mumble/CMakeLists.txt
+++ b/src/mumble/CMakeLists.txt
@@ -176,6 +176,9 @@ set(MUMBLE_SOURCES
"Screen.h"
"ServerHandler.cpp"
"ServerHandler.h"
+ "ServerInformation.cpp"
+ "ServerInformation.h"
+ "ServerInformation.ui"
"Settings.cpp"
"Settings.h"
"SharedMemory.cpp"
diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp
index 1b7723ed4..6d955c9d6 100644
--- a/src/mumble/MainWindow.cpp
+++ b/src/mumble/MainWindow.cpp
@@ -39,6 +39,7 @@
#include "SSLCipherInfo.h"
#include "Screen.h"
#include "ServerHandler.h"
+#include "ServerInformation.h"
#include "Settings.h"
#include "SvgIcon.h"
#include "TalkingUI.h"
@@ -1403,138 +1404,9 @@ void MainWindow::on_qaServerUserList_triggered() {
}
}
-static const QString currentCodec() {
- if (Global::get().bOpus)
- return QLatin1String("Opus");
-
- int v = Global::get().bPreferAlpha ? Global::get().iCodecAlpha : Global::get().iCodecBeta;
- CELTCodec *cc = Global::get().qmCodecs.value(v);
- if (cc)
- return QString::fromLatin1("CELT %1").arg(cc->version());
- else
- return QString::fromLatin1("CELT %1").arg(QString::number(v, 16));
-}
-
void MainWindow::on_qaServerInformation_triggered() {
- ConnectionPtr c = Global::get().sh->cConnection;
-
- if (!c)
- return;
-
- QSslCipher qsc = Global::get().sh->qscCipher;
-
- QString qsVersion = tr("<h2>Version</h2><p>Protocol %1</p>").arg(MumbleVersion::toString(Global::get().sh->uiVersion));
-
- if (Global::get().sh->qsRelease.isEmpty() || Global::get().sh->qsOS.isEmpty() || Global::get().sh->qsOSVersion.isEmpty()) {
- qsVersion.append(tr("<p>No build information or OS version available</p>"));
- } else {
- qsVersion.append(
- tr("<p>%1 (%2)<br />%3</p>")
- .arg(Global::get().sh->qsRelease.toHtmlEscaped(), Global::get().sh->qsOS.toHtmlEscaped(), Global::get().sh->qsOSVersion.toHtmlEscaped()));
- }
-
- QString host, uname, pw;
- unsigned short port;
-
- Global::get().sh->getConnectionInfo(host, port, uname, pw);
-
- const SSLCipherInfo *ci = SSLCipherInfoLookupByOpenSSLName(qsc.name().toLatin1().constData());
-
- QString cipherDescription;
- if (ci && ci->message_authentication && ci->encryption && ci->key_exchange_verbose && ci->rfc_name) {
- if (QString::fromLatin1(ci->message_authentication) == QLatin1String("AEAD")) {
- // Authenticated Encryption with Associated Data
- // See https://en.wikipedia.org/wiki/Authenticated_encryption
- cipherDescription =
- tr("The connection is encrypted and authenticated "
- "using %1 and uses %2 as the key exchange mechanism (%3)")
- .arg(QString::fromLatin1(ci->encryption), QString::fromLatin1(ci->key_exchange_verbose),
- QString::fromLatin1(ci->rfc_name));
- } else {
- cipherDescription =
- tr("The connection is encrypted using %1, with %2 "
- "for message authentication and %3 as the key "
- "exchange mechanism (%4)")
- .arg(QString::fromLatin1(ci->encryption), QString::fromLatin1(ci->message_authentication),
- QString::fromLatin1(ci->key_exchange_verbose), QString::fromLatin1(ci->rfc_name));
- }
- }
- if (cipherDescription.isEmpty()) {
- cipherDescription =
- tr("The connection is secured by the cipher suite that OpenSSL identifies as %1").arg(qsc.name());
- }
-
- QString cipherPFSInfo;
- if (ci) {
- if (ci->forward_secret) {
- cipherPFSInfo = tr("<p>The connection provides perfect forward secrecy</p>");
- } else {
- cipherPFSInfo = tr("<p>The connection does not provide perfect forward secrecy</p>");
- }
- }
-
- QString qsControl =
- tr("<h2>Control channel</h2>"
- "<p>The connection uses %1</p>"
- "%2"
- "%3"
- "<p>%4 ms average latency (%5 deviation)</p>"
- "<p>Remote host %6 (port %7)</p>")
- .arg(c->sessionProtocolString().toHtmlEscaped(), cipherDescription, cipherPFSInfo,
- QString::fromLatin1("%1").arg(boost::accumulators::mean(Global::get().sh->accTCP), 0, 'f', 2),
- QString::fromLatin1("%1").arg(sqrt(boost::accumulators::variance(Global::get().sh->accTCP)), 0, 'f', 2),
- host.toHtmlEscaped(), QString::number(port));
- if (Global::get().uiMaxUsers) {
- qsControl += tr("<p>Connected users: %1/%2</p>").arg(ModelItem::c_qhUsers.count()).arg(Global::get().uiMaxUsers);
- }
-
- QString qsVoice, qsCrypt, qsAudio;
-
- if (NetworkConfig::TcpModeEnabled()) {
- qsVoice = tr("Voice channel is sent over control channel");
- } else {
- qsVoice = tr("<h2>Voice channel</h2><p>Encrypted with 128 bit OCB-AES128<br />%1 ms average latency (%4 "
- "deviation)</p>")
- .arg(boost::accumulators::mean(Global::get().sh->accUDP), 0, 'f', 2)
- .arg(sqrt(boost::accumulators::variance(Global::get().sh->accUDP)), 0, 'f', 2);
- qsCrypt = QString::fromLatin1("<h2>%1</h2><table><tr><th></th><th>%2</th><th>%3</th></tr>"
- "<tr><th>%4</th><td>%8</td><td>%12</td></tr>"
- "<tr><th>%5</th><td>%9</td><td>%13</td></tr>"
- "<tr><th>%6</th><td>%10</td><td>%14</td></tr>"
- "<tr><th>%7</th><td>%11</td><td>%15</td></tr>"
- "</table>")
- .arg(tr("UDP Statistics"))
- .arg(tr("To Server"))
- .arg(tr("From Server"))
- .arg(tr("Good"))
- .arg(tr("Late"))
- .arg(tr("Lost"))
- .arg(tr("Resync"))
- .arg(c->csCrypt->uiRemoteGood)
- .arg(c->csCrypt->uiRemoteLate)
- .arg(c->csCrypt->uiRemoteLost)
- .arg(c->csCrypt->uiRemoteResync)
- .arg(c->csCrypt->uiGood)
- .arg(c->csCrypt->uiLate)
- .arg(c->csCrypt->uiLost)
- .arg(c->csCrypt->uiResync);
- }
- qsAudio = tr("<h2>Audio bandwidth</h2><p>Maximum %1 kbit/s<br />Current %2 kbit/s<br />Codec: %3</p>")
- .arg(Global::get().iMaxBandwidth / 1000.0, 0, 'f', 1)
- .arg(Global::get().iAudioBandwidth / 1000.0, 0, 'f', 1)
- .arg(currentCodec());
-
- QMessageBox qmb(QMessageBox::Information, tr("Mumble Server Information"),
- qsVersion + qsControl + qsVoice + qsCrypt + qsAudio, QMessageBox::Ok, this);
- qmb.setDefaultButton(QMessageBox::Ok);
- qmb.setEscapeButton(QMessageBox::Ok);
-
- QPushButton *qp = qmb.addButton(tr("&View Certificate"), QMessageBox::ActionRole);
- int res = qmb.exec();
- if ((res == 0) && (qmb.clickedButton() == qp)) {
- ViewCert vc(Global::get().sh->qscCert, this);
- vc.exec();
- }
+ ServerInformation *infoDialog = new ServerInformation(this);
+ infoDialog->show();
}
void MainWindow::on_qaServerTexture_triggered() {
diff --git a/src/mumble/ServerInformation.cpp b/src/mumble/ServerInformation.cpp
new file mode 100644
index 000000000..dd8e41278
--- /dev/null
+++ b/src/mumble/ServerInformation.cpp
@@ -0,0 +1,199 @@
+// Copyright 2021 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+#include "ServerInformation.h"
+#include "CELTCodec.h"
+#include "Connection.h"
+#include "MainWindow.h"
+#include "NetworkConfig.h"
+#include "SSL.h"
+#include "SSLCipherInfo.h"
+#include "ServerHandler.h"
+#include "UserModel.h"
+#include "Version.h"
+#include "ViewCert.h"
+#include "Global.h"
+
+#include <QTableWidgetItem>
+
+#include <boost/accumulators/accumulators.hpp>
+
+#include <cmath>
+
+QString ServerInformation::m_unknownStr = tr("Unknown");
+
+ServerInformation::ServerInformation(QWidget *parent) : QDialog(parent) {
+ setupUi(this);
+
+ updateFields();
+}
+
+void ServerInformation::updateFields() {
+ updateServerInformation();
+ updateAudioBandwidth();
+ updateConnectionDetails();
+}
+
+void ServerInformation::on_okButton_clicked() {
+ accept();
+}
+
+void ServerInformation::on_viewCertButton_clicked() {
+ hide();
+
+ ViewCert certViewer(Global::get().sh->qscCert, this);
+ certViewer.exec();
+
+ accept();
+}
+
+void ServerInformation::updateServerInformation() {
+ QString host, userName, password;
+ unsigned short port;
+
+ Global::get().sh->getConnectionInfo(host, port, userName, password);
+
+ const int userCount = ModelItem::c_qhUsers.count();
+ const unsigned int maxUserCount = Global::get().uiMaxUsers;
+
+ QString release = Global::get().sh->qsRelease;
+ if (release.isEmpty()) {
+ release = m_unknownStr;
+ }
+ QString os = Global::get().sh->qsOS;
+ if (os.isEmpty()) {
+ os = m_unknownStr;
+ } else if (!Global::get().sh->qsOSVersion.isEmpty()) {
+ os += QString::fromLatin1(" (%1)").arg(Global::get().sh->qsOSVersion);
+ }
+
+ serverInfo_host->setText(host);
+ serverInfo_port->setText(QString::number(port));
+ serverInfo_users->setText(QString::fromLatin1("%1 / %2").arg(userCount).arg(maxUserCount));
+ serverInfo_protocol->setText(MumbleVersion::toString(Global::get().sh->uiVersion));
+ serverInfo_release->setText(release);
+ serverInfo_os->setText(os);
+}
+
+static const QString currentCodec() {
+ if (Global::get().bOpus)
+ return QLatin1String("Opus");
+
+ int v = Global::get().bPreferAlpha ? Global::get().iCodecAlpha : Global::get().iCodecBeta;
+ CELTCodec *cc = Global::get().qmCodecs.value(v);
+ if (cc)
+ return QString::fromLatin1("CELT %1").arg(cc->version());
+ else
+ return QString::fromLatin1("CELT %1").arg(QString::number(v, 16));
+}
+
+void ServerInformation::updateAudioBandwidth() {
+ // The bandwidths are in bit/s, so we divide by 1000 to get kBit/s
+ const float maxBandwidthAllowed = Global::get().iMaxBandwidth / 1000.0f;
+ const float currentBandwidth = Global::get().iAudioBandwidth / 1000.0f;
+
+ audio_current->setText(QString::fromLatin1("%1 kBit/s").arg(currentBandwidth, 0, 'f', 1));
+ audio_allowed->setText(QString::fromLatin1("%1 kBit/s").arg(maxBandwidthAllowed, 0, 'f', 1));
+ audio_codec->setText(currentCodec());
+}
+
+QString getCipherID(const QSslCipher &cipher, const SSLCipherInfo *cipherInfo) {
+ if (cipherInfo && cipherInfo->rfc_name) {
+ return QString::fromUtf8(cipherInfo->rfc_name);
+ }
+
+ return cipher.name();
+}
+
+void ServerInformation::updateConnectionDetails() {
+ QString latencyString = QString::fromUtf8("%1 ms (σ = %2 ms)");
+ const ConnectionPtr connection = Global::get().sh->cConnection;
+
+ if (!connection) {
+ return;
+ }
+
+ // UDP
+ if (NetworkConfig::TcpModeEnabled()) {
+ connection_udp_infoMessage->show();
+
+ connection_udp_encryption->hide();
+ connection_udp_encryptionLabel->hide();
+ connection_udp_latency->hide();
+ connection_udp_latencyLabel->hide();
+ connection_udp_statisticsGroup->hide();
+ } else {
+ connection_udp_infoMessage->hide();
+
+ connection_udp_encryption->show();
+ connection_udp_encryptionLabel->show();
+ connection_udp_latency->show();
+ connection_udp_latencyLabel->show();
+ connection_udp_statisticsGroup->show();
+
+ // Actually fill in data
+ const float latency = boost::accumulators::mean(Global::get().sh->accUDP);
+ const float deviation = std::sqrt(boost::accumulators::variance(Global::get().sh->accUDP));
+
+ connection_udp_encryption->setText("128 bit OCB-AES128");
+ connection_udp_latency->setText(latencyString.arg(latency, 0, 'f', 1).arg(deviation, 0, 'f', 1));
+
+ populateUDPStatistics(*connection);
+ }
+
+
+ // TCP
+ const float latency = boost::accumulators::mean(Global::get().sh->accTCP);
+ const float deviation = std::sqrt(boost::accumulators::variance(Global::get().sh->accTCP));
+
+ QSslCipher cipher = Global::get().sh->qscCipher;
+ const SSLCipherInfo *cipherInfo = SSLCipherInfoLookupByOpenSSLName(cipher.name().toLatin1().constData());
+
+ const QString cipherID = getCipherID(cipher, cipherInfo);
+
+ connection_tcp_tls->setText(MumbleSSL::protocolToString(connection->sessionProtocol()).toHtmlEscaped());
+ connection_tcp_latency->setText(latencyString.arg(latency, 0, 'f', 1).arg(deviation, 0, 'f', 1));
+ connection_tcp_cipher->setText(cipherID.isEmpty() ? m_unknownStr : cipherID);
+
+ if (cipherInfo) {
+ if (cipherInfo->forward_secret) {
+ connection_tcp_forwardSecrecy->setText(tr("The connection provides perfect forward secrecy."));
+ } else {
+ connection_tcp_forwardSecrecy->setText(tr("The connection does NOT provide perfect forward secrecy."));
+ }
+ } else {
+ connection_tcp_forwardSecrecy->setText(tr("No information about forward secrecy available."));
+ }
+}
+
+void ServerInformation::populateUDPStatistics(const Connection &connection) {
+ // statistics
+ constexpr int toServerCol = 0;
+ constexpr int fromServerCol = 1;
+ constexpr int goodRow = 0;
+ constexpr int lateRow = 1;
+ constexpr int lostRow = 2;
+ constexpr int resyncRow = 3;
+
+ QTableWidgetItem *toGoodItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiRemoteGood));
+ QTableWidgetItem *fromGoodItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiGood));
+ QTableWidgetItem *toLateItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiRemoteLate));
+ QTableWidgetItem *fromLateItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiLate));
+ QTableWidgetItem *toLostItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiRemoteLost));
+ QTableWidgetItem *fromLostItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiLost));
+ QTableWidgetItem *toResyncItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiRemoteResync));
+ QTableWidgetItem *fromResyncItem = new QTableWidgetItem(QString::number(connection.csCrypt->uiResync));
+
+ connection_udp_statisticsTable->setItem(goodRow, toServerCol, toGoodItem);
+ connection_udp_statisticsTable->setItem(goodRow, fromServerCol, fromGoodItem);
+ connection_udp_statisticsTable->setItem(lateRow, toServerCol, toLateItem);
+ connection_udp_statisticsTable->setItem(lateRow, fromServerCol, fromLateItem);
+ connection_udp_statisticsTable->setItem(lostRow, toServerCol, toLostItem);
+ connection_udp_statisticsTable->setItem(lostRow, fromServerCol, fromLostItem);
+ connection_udp_statisticsTable->setItem(resyncRow, toServerCol, toResyncItem);
+ connection_udp_statisticsTable->setItem(resyncRow, fromServerCol, fromResyncItem);
+
+ connection_udp_statisticsTable->adjustSize();
+}
diff --git a/src/mumble/ServerInformation.h b/src/mumble/ServerInformation.h
new file mode 100644
index 000000000..41669b5d4
--- /dev/null
+++ b/src/mumble/ServerInformation.h
@@ -0,0 +1,37 @@
+// Copyright 2021 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+#ifndef MUMBLE_MUMBLE_SERVERINFORMATION_H_
+#define MUMBLE_MUMBLE_SERVERINFORMATION_H_
+
+#include <QDialog>
+
+#include "ui_ServerInformation.h"
+
+class Connection;
+
+class ServerInformation : public QDialog, private Ui::ServerInformation {
+ Q_OBJECT;
+ Q_DISABLE_COPY(ServerInformation);
+
+public:
+ ServerInformation(QWidget *parent = nullptr);
+
+ void updateFields();
+
+public slots:
+ void on_okButton_clicked();
+ void on_viewCertButton_clicked();
+
+private:
+ static QString m_unknownStr;
+
+ void updateServerInformation();
+ void updateAudioBandwidth();
+ void updateConnectionDetails();
+ void populateUDPStatistics(const Connection &connection);
+};
+
+#endif // MUMBLE_MUMBLE_SERVERINFORMATION_H_
diff --git a/src/mumble/ServerInformation.ui b/src/mumble/ServerInformation.ui
new file mode 100644
index 000000000..ba274deda
--- /dev/null
+++ b/src/mumble/ServerInformation.ui
@@ -0,0 +1,643 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerInformation</class>
+ <widget class="QDialog" name="ServerInformation">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>578</width>
+ <height>585</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Server information</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>-203</y>
+ <width>541</width>
+ <height>731</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="qgbServerInformation">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Server Information</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&lt;b&gt;Host:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="serverInfo_host">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;host&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Port:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="serverInfo_port">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;port&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>&lt;b&gt;Users&lt;/b&gt;:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="serverInfo_users">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;users&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Protocol:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="serverInfo_protocol">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;protocol&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Release:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="serverInfo_release">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;release&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;OS:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLabel" name="serverInfo_os">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;os&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="qgbAudioBandwidth">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Audio</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_4">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_31">
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Allowed:&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="audio_allowed">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;allowed&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_32">
+ <property name="text">
+ <string>&lt;b&gt;Current:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="audio_current">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;current&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_33">
+ <property name="text">
+ <string>&lt;b&gt;Codec:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="audio_codec">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;codec&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="qgbConnectionDetails">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Connection details</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="tabPosition">
+ <enum>QTabWidget::North</enum>
+ </property>
+ <property name="tabShape">
+ <enum>QTabWidget::Rounded</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>UDP (Voice)</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout_3">
+ <item row="1" column="0">
+ <widget class="QLabel" name="connection_udp_encryptionLabel">
+ <property name="text">
+ <string>&lt;b&gt;Encryption:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="connection_udp_encryption">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;encryption&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="connection_udp_latencyLabel">
+ <property name="text">
+ <string>&lt;b&gt;Avg. latency:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="connection_udp_latency">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;latency&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QGroupBox" name="connection_udp_statisticsGroup">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Statistics</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="QTableWidget" name="connection_udp_statisticsTable">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="verticalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="horizontalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="showGrid">
+ <bool>true</bool>
+ </property>
+ <property name="cornerButtonEnabled">
+ <bool>false</bool>
+ </property>
+ <row>
+ <property name="text">
+ <string>Good</string>
+ </property>
+ </row>
+ <row>
+ <property name="text">
+ <string>Late</string>
+ </property>
+ </row>
+ <row>
+ <property name="text">
+ <string>Lost</string>
+ </property>
+ </row>
+ <row>
+ <property name="text">
+ <string>Resync</string>
+ </property>
+ </row>
+ <column>
+ <property name="text">
+ <string>Outgoing</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Incoming</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="connection_udp_infoMessage">
+ <property name="text">
+ <string>Voice packets is currently sent over TCP.</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>TCP (Control)</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>&lt;b&gt;TLS version:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="connection_tcp_tls">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;TLS&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>&lt;b&gt;Cipher suite:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="connection_tcp_cipher">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;Cipher&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>&lt;b&gt;Avg. latency:&lt;/b&gt;</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="connection_tcp_latency">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">&lt;latency&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QLabel" name="connection_tcp_forwardSecrecy">
+ <property name="text">
+ <string>&lt;forward secrecy&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Maximum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="viewCertButton">
+ <property name="text">
+ <string>&amp;View certificate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>&amp;Ok</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>