/* * connectwindow.cpp * * Created on: 28.01.2013 * Author: sr */ #include #include "../../shared/settings.h" #include "../../shared/network.h" #include "../../shared/util.h" #include "../net/serverconnection.h" #include "../clientapp/clientapp.h" #include "connectwindow.h" #include "ui_connect.h" #define UDPBUFSIZ 9000 #define SALT_LEN 18 /***************************************************************************//** * Initialize Connection Window. * @param parent */ ConnectWindow::ConnectWindow(QWidget *parent) : QWidget(parent) { _ui = new Ui::ConnectWindow; _timerHide = 0; _state = Idle; _hashSslErrorCount = 0; _pendingConnection = nullptr; // Initialize the GUI _ui->setupUi(this); // Set window properties setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Tool); // Set page 0 as default _ui->stackedWidget->setCurrentIndex(0); // Set actions of buttons connect(_ui->btn_connection, SIGNAL(clicked()), this, SLOT(onBtnConnection())); connect(_ui->btn_hide, SIGNAL(clicked()), this, SLOT(onBtnCancel())); connect(_ui->comboBox_rooms, SIGNAL(currentIndexChanged(int)), this, SLOT(onRoomSelection(int))); // React on discovery signal connect(&_serverDiscovery, SIGNAL(serverDetected(QString, quint16, QByteArray, QByteArray, bool)), this, SLOT(onServerDetected(QString, quint16, QByteArray, QByteArray, bool))); /* finally the most requested feature: connect on press of the enter key */ connect(_ui->lineEditName, SIGNAL(returnPressed()), _ui->btn_connection, SIGNAL(clicked())); /* by default don't show the manual connection box */ _ui->box_manual->setVisible(false); this->updateUserInterface(); } /***************************************************************************//** * @brief ConnectWindow::~ConnectWindow */ ConnectWindow::~ConnectWindow() {} /***************************************************************************//** * Handle changes in state and update window. * Also changing TextLabel which shows the user what the program is doing. */ void ConnectWindow::updateUserInterface() { _ui->lineEditName->setEnabled(_state == Idle); if (_state == Connected) { _ui->btn_connection->setEnabled(true); _ui->btn_connection->setText(tr("&Disconnect")); _ui->lblStatus->setText(tr("Connected to %1").arg(clientApp->connection()->getPeerAdress())); _ui->lineEditName->setEnabled(false); _ui->stackedWidget->setCurrentIndex(1); return; } if (_state != Idle) _ui->btn_connection->setText(tr("&Stop")); else _ui->btn_connection->setText(tr("&Connect")); switch (_state) { case Idle: _ui->lblStatus->setText(tr("Ready to connect.")); break; case Scanning: _ui->lblStatus->setText(tr("Scanning for session %1.").arg(_ui->lineEditName->text())); break; case Connecting: _ui->lblStatus->setText(tr("Found session, connecting...")); break; case AwaitingChallenge: _ui->lblStatus->setText(tr("Waiting for server challenge...")); break; case AwaitingChallengeResponse: _ui->lblStatus->setText(tr("Replied to challenge, sent own...")); break; case LoggingIn: _ui->lblStatus->setText(tr("Logging in...")); break; case Connected: _ui->lblStatus->setText(tr("Connection established!")); break; case InvalidCert: _ui->lblStatus->setText(tr("Invalid certificate.")); break; case InvalidSslHash: _ui->lblStatus->setText(tr("Invalid TLS hash: %1.").arg(_hashSslErrorCount)); break; default: _ui->lblStatus->setText(tr("Unknown state :-(")); break; } } /* * Overrides */ /***************************************************************************//** * Called when a Qt timer fires; used for server discovery and * auto-hiding the connect dialog. */ void ConnectWindow::timerEvent(QTimerEvent* event) { if (event->timerId() == _timerHide) { killTimer(_timerHide); _timerHide = 0; this->hide(); _ui->stackedWidget->setCurrentIndex(0); } else // Unknown/Old timer id, kill it ??? PALM -> FACE killTimer(event->timerId()); } /***************************************************************************//** * Handle incoming closeEvent and hide window. * @param e */ void ConnectWindow::closeEvent(QCloseEvent *e) { e->ignore(); this->hide(); } void ConnectWindow::doShow() { /* reset to automatic connect window */ _ui->stackedWidget->setCurrentIndex(0); _ui->comboBox_rooms->setCurrentIndex(0); show(); showNormal(); activateWindow(); raise(); } /***************************************************************************//** * Gives the keyboard input focus to the input line. * @param event */ void ConnectWindow::showEvent(QShowEvent* /* event */ ) { activateWindow(); raise(); _ui->lineEditName->setFocus(); } /***************************************************************************//** * Public function connect to session. * Check if currently connected to server, * if not --> connect to given sessionName. * @param sessionName */ void ConnectWindow::connectToSession(const QByteArray sessionName, QString mgrIP) { if (_state != Idle) return; _currentSession = sessionName; _currentIp = mgrIP; _state = Scanning; this->updateUserInterface(); _tryReconnect = true; _serverDiscovery.start(sessionName, mgrIP); } /* * Slots */ void ConnectWindow::DoConnect() { qDebug() << "DoConnect()"; // Connect (scan for session) // qDebug() << _ui->lineEditName->text().toUtf8(); int index = _ui->comboBox_rooms->currentIndex(); QString selectedMgrIP = _ui->comboBox_rooms->itemData(index).toString(); if (selectedMgrIP == "manual_connection") { qDebug() << "connect to sessionName by manual connection"; QByteArray sessionName = _ui->lineEditName->text().toUtf8(); connectToSession(sessionName, ""); } else { qDebug() << "connect to mgrIP (through room selection) " << selectedMgrIP; connectToSession("", selectedMgrIP); } } void ConnectWindow::DoDisconnect() { qDebug() << "DoDisconnect()"; _tryReconnect = false; // Stop or disconnect emit disconnect(); _state = Idle; } /***************************************************************************//** * Handle click on Connect/Disconnect button. * If already connected --> Stop/disconnect. * Else scanning for given sessionId. */ void ConnectWindow::onBtnConnection() { if (_timerHide) { killTimer(_timerHide); _timerHide = 0; _ui->stackedWidget->setCurrentIndex(0); } if (_serverDiscovery.isActive()) _serverDiscovery.stop(); if (_state != Idle) { DoDisconnect(); } else { DoConnect(); } this->updateUserInterface(); } /** set the available rooms. * If the list of rooms is empty, switches automatically to the "manual * connection" page */ void ConnectWindow::setAvailableRooms(QList m) { _ui->comboBox_rooms->clear(); foreach (Room r, m) { _ui->comboBox_rooms->addItem(r.name, r.mgr); } /* also add a pseudo-room "manual choice" */ _ui->comboBox_rooms->addItem(tr("Session Name..."), "manual_connection"); } /***************************************************************************//** * Handle click on Cancel/Hide Button. * Just hide the window. */ void ConnectWindow::onBtnCancel() { this->hide(); } /** check if "manual_connection" is selected, then switch to manual * connection page */ void ConnectWindow::onRoomSelection(int index) { QString sessionName = _ui->comboBox_rooms->itemData(index).toString(); if (sessionName == "manual_connection") { qDebug() << "switch to manual connection"; _ui->box_manual->setVisible(true); //this->setSize(QSize(300,200)); this->resize(300, 200); } else { _ui->box_manual->setVisible(false); this->resize(300, 140); } } /***************************************************************************//** * @brief ConnectWindow::onServerDetected * @param host * @param port * @param sessionName * @param certHash */ void ConnectWindow::onServerDetected(const QString& host, const quint16 port, const QByteArray& sessionName, const QByteArray& certHash, bool autoConnect) { _pendingConnection = new ServerConnection(host, port, sessionName, certHash, autoConnect); connect(_pendingConnection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState))); connect(_pendingConnection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*))); connect(_pendingConnection, SIGNAL(disconnected(ServerConnection*)), this, SLOT(onConnectionDisconnected(ServerConnection*))); } /***************************************************************************//** * Handle connection state changes and update member variables describing state. * @param state */ void ConnectWindow::onConnectionStateChange(ConnectWindow::ConnectionState state) { bool reset = (_state == Scanning); if (state == InvalidSslHash) ++_hashSslErrorCount; _state = state; if (reset) { _state = Scanning; } if (state == Connected) { QObject::disconnect(_pendingConnection, SIGNAL(stateChange(ConnectWindow::ConnectionState)), this, SLOT(onConnectionStateChange(ConnectWindow::ConnectionState))); QObject::disconnect(_pendingConnection, SIGNAL(destroyed(QObject*)), this, SLOT(onConnectionClosed(QObject*))); emit connected(_pendingConnection); _pendingConnection = nullptr; this->updateUserInterface(); _timerHide = startTimer(2000); } else { this->updateUserInterface(); } } void ConnectWindow::onComboBox_keyPressed(QKeyEvent* e) { qDebug() << "key released"; if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return ) { qDebug() << "enter pressed"; } } /***************************************************************************//** * If connection is closed set _pendingConnection = nullptr. * @param connection */ void ConnectWindow::onConnectionClosed(QObject* /* connection */ ) { _pendingConnection = nullptr; } /***************************************************************************//** * @brief ConnectWindow::onConnectionDisconnected */ void ConnectWindow::onConnectionDisconnected(ServerConnection*) { _state = Idle; this->updateUserInterface(); if (_tryReconnect) { this->updateUserInterface(); connectToSession(_currentSession, _currentIp); } }