File indexing completed on 2024-04-21 15:07:59

0001 // Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com>
0002 //
0003 // This program is free software; you can redistribute it and/or
0004 // modify it under the terms of the GNU General Public License
0005 // version 2 as published by the Free Software Foundation.
0006 //
0007 // This program is distributed in the hope that it will be useful,
0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0010 // General Public License for more details.
0011 //
0012 // You should have received a copy of the GNU General Public License
0013 // along with this program; see the file COPYING.  If not, write to
0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0015 // Boston, MA 02110-1301, USA.
0016 
0017 #include <QTcpSocket>
0018 #include <QHeaderView>
0019 #include <QIntValidator>
0020 
0021 #include <klocalizedstring.h>
0022 #include <kiconloader.h>
0023 #include <kguiitem.h>
0024 #include <kstandardguiitem.h>
0025 
0026 #include <monopd.h>
0027 
0028 #include "metatlantic.h"
0029 
0030 #include "selectserver_widget.h"
0031 
0032 #include <atlantik_debug.h>
0033 
0034 MetaserverEntry::MetaserverEntry(const QString &host, int port, const QString &version, int users)
0035     : QObject()
0036     , QTreeWidgetItem(MetaserverType)
0037     , m_latency(9999)
0038     , m_users(users)
0039     , m_port(port)
0040     , m_isDev(version.indexOf(QLatin1String("CVS")) != -1 || version.indexOf(QLatin1String("-dev")) != -1)
0041 {
0042     setText(0, host);
0043     setText(1, QString::number(m_latency));
0044     setText(2, version);
0045     setText(3, users == -1 ? i18n("unknown") : QString::number(m_users));
0046     setIcon(0, KDE::icon(QStringLiteral("atlantik")));
0047     setDisabled(true);
0048 
0049     m_latencySocket = new QTcpSocket();
0050     m_latencySocket->setSocketOption(QAbstractSocket::LowDelayOption, true);
0051     connect(m_latencySocket, SIGNAL(hostFound()), this, SLOT(resolved()));
0052     connect(m_latencySocket, SIGNAL(connected()), this, SLOT(connected()));
0053 
0054     m_latencySocket->connectToHost(host, m_port);
0055 }
0056 
0057 bool MetaserverEntry::isDev() const
0058 {
0059     return m_isDev;
0060 }
0061 
0062 QString MetaserverEntry::host() const
0063 {
0064     return text(0);
0065 }
0066 
0067 int MetaserverEntry::port() const
0068 {
0069     return m_port;
0070 }
0071 
0072 bool MetaserverEntry::operator<(const QTreeWidgetItem &other) const
0073 {
0074     if (other.type() != MetaserverType)
0075         return QTreeWidgetItem::operator<(other);
0076 
0077     // sort by (less) latency first, then (most) users, then by host
0078     const MetaserverEntry *e = static_cast<const MetaserverEntry *>(&other);
0079     if (m_latency < e->m_latency)
0080         return true;
0081     if (m_users > e->m_users)
0082         return true;
0083     return QString::compare(host(), e->host()) > 0;
0084 }
0085 
0086 void MetaserverEntry::resolved()
0087 {
0088     m_timer.start();
0089     qCDebug(ATLANTIK_LOG) << host() << "resolved; timer starts";
0090 }
0091 
0092 void MetaserverEntry::connected()
0093 {
0094     m_latency = m_timer.elapsed();
0095     m_latencySocket->abort();
0096     qCDebug(ATLANTIK_LOG) << "connected to" << host() << "- latency =" << m_latency;
0097     setDisabled(false);
0098     setText(1, QString::number(m_latency));
0099     disconnect(m_latencySocket, nullptr, this, nullptr);
0100     m_latencySocket->deleteLater();
0101     m_latencySocket = nullptr;
0102 }
0103 
0104 SelectServer::SelectServer(bool hideDevelopmentServers, QWidget *parent)
0105     : QWidget(parent)
0106     , m_metatlantic(nullptr)
0107     , m_hideDevelopmentServers(hideDevelopmentServers)
0108 {
0109     setupUi(this);
0110     layout()->setContentsMargins(0, 0, 0, 0);
0111 
0112     connect(m_hostEdit, SIGNAL(returnPressed()), this, SLOT(customConnect()));
0113     connect(m_hostEdit, SIGNAL(textChanged(QString)), this, SLOT(validateCustomConnectButton()));
0114 
0115     m_portEdit->setText(QString::number(MONOPD_PORT));
0116     m_portEdit->setValidator(new QIntValidator(1, 65535, m_portEdit));
0117     connect(m_portEdit, SIGNAL(returnPressed()), this, SLOT(customConnect()));
0118     connect(m_portEdit, SIGNAL(textChanged(QString)), this, SLOT(validateCustomConnectButton()));
0119 
0120     m_customConnectButton->setIcon(KDE::icon(QStringLiteral("network-wired")));
0121     connect(m_customConnectButton, SIGNAL(clicked()), this, SLOT(customConnect()));
0122 
0123     // List of servers
0124     m_serverList->sortItems(1, Qt::AscendingOrder);
0125     m_serverList->header()->setSectionsClickable(false);
0126     m_serverList->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
0127     m_serverList->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
0128     m_serverList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
0129 
0130     connect(m_serverList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(validateConnectButton()));
0131     connect(m_serverList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotConnect()));
0132     connect(m_serverList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(validateConnectButton()));
0133 
0134     // Server List / Refresh
0135     KGuiItem::assign(m_refreshButton, KGuiItem(i18n("Get Server List"), QStringLiteral("network-wired")));
0136     connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(reloadServerList()));
0137 
0138     // Connect
0139     m_connectButton->setIcon(KStandardGuiItem::forward(KStandardGuiItem::UseRTL).icon());
0140 
0141     connect(m_connectButton, SIGNAL(clicked()), this, SLOT(slotConnect()));
0142 
0143     validateConnectButton();
0144     validateCustomConnectButton();
0145 }
0146 
0147 SelectServer::~SelectServer()
0148 {
0149     if (m_metatlantic)
0150         m_metatlantic->kill();
0151     delete m_metatlantic;
0152 }
0153 
0154 void SelectServer::setHideDevelopmentServers(bool hideDevelopmentServers)
0155 {
0156     if ( m_hideDevelopmentServers != hideDevelopmentServers )
0157     {
0158         m_hideDevelopmentServers = hideDevelopmentServers;
0159         foreach (MetaserverEntry *e, m_developmentServers)
0160             e->setHidden(m_hideDevelopmentServers);
0161     }
0162 }
0163 
0164 void SelectServer::initMetaserver()
0165 {
0166     // Hardcoded, but there aren't any other Metatlantic root servers at the moment
0167     Q_EMIT msgStatus(i18n("Retrieving server list..."));
0168 
0169     KGuiItem::assign(m_refreshButton, KGuiItem(i18n("Reload Server List"), QStringLiteral("view-refresh")));
0170     m_metatlantic = new Metatlantic(QString::fromLatin1(METATLANTIC_HOST), METATLANTIC_PORT);
0171 
0172     connect(m_metatlantic, SIGNAL(metatlanticAdd(QString,int,QString,int)), this, SLOT(slotMetatlanticAdd(QString,int,QString,int)));
0173     connect(m_metatlantic, SIGNAL(result(KJob*)), SLOT(metatlanticFinished()));
0174 
0175     m_metatlantic->start();
0176 }
0177 
0178 void SelectServer::slotMetatlanticAdd(const QString &host, int port, const QString &version, int users)
0179 {
0180     MetaserverEntry *item = new MetaserverEntry(host, port, version, users);
0181     m_serverList->addTopLevelItem(item);
0182     m_serverList->resizeColumnToContents(0);
0183 
0184     if ( item->isDev() )
0185     {
0186         m_developmentServers.append(item);
0187         item->setHidden(m_hideDevelopmentServers);
0188     }
0189 
0190     validateConnectButton();
0191 }
0192 
0193 void SelectServer::metatlanticFinished()
0194 {
0195     if (m_metatlantic->error())
0196         Q_EMIT msgStatus(i18n("Error while retrieving the server list."));
0197     else
0198         Q_EMIT msgStatus(i18n("Retrieved server list."));
0199     m_metatlantic = nullptr;
0200     m_refreshButton->setEnabled(true);
0201 }
0202 
0203 void SelectServer::validateConnectButton()
0204 {
0205     if (!m_serverList->selectedItems().isEmpty())
0206         m_connectButton->setEnabled(true);
0207     else
0208         m_connectButton->setEnabled(false);
0209 }
0210 
0211 void SelectServer::validateCustomConnectButton()
0212 {
0213     m_customConnectButton->setEnabled(!m_hostEdit->text().isEmpty() && !m_portEdit->text().isEmpty());
0214 }
0215 
0216 void SelectServer::reloadServerList()
0217 {
0218     m_developmentServers.resize(0); // Keep the capacity allocated
0219     m_serverList->clear();
0220     validateConnectButton();
0221 
0222     m_refreshButton->setEnabled(false);
0223     initMetaserver();
0224 }
0225 
0226 void SelectServer::slotConnect()
0227 {
0228     const QList<QTreeWidgetItem *> items = m_serverList->selectedItems();
0229     if (!items.isEmpty())
0230     {
0231         const QTreeWidgetItem *item = items.first();
0232         Q_ASSERT(item->type() == MetaserverEntry::MetaserverType);
0233         const MetaserverEntry *e = static_cast<const MetaserverEntry *>(item);
0234         Q_EMIT serverConnect(e->host(), e->port());
0235     }
0236 }
0237 
0238 void SelectServer::customConnect()
0239 {
0240     if (!m_hostEdit->text().isEmpty() && !m_portEdit->text().isEmpty())
0241         Q_EMIT serverConnect(m_hostEdit->text(), m_portEdit->text().toInt());
0242 }
0243 
0244 #include "moc_selectserver_widget.cpp"