From c635c7f40df0baf38cfe87e0ec9006edfc9c9576 Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Tue, 17 Apr 2018 23:06:02 -0600
Subject: [PATCH] Address more review comments

* Make Validation a singleton instead
* Wording changes for error messages
* Smart pointers for Ui members
* Other minor nitpicks
---
 src/citra_qt/configuration/config.cpp       |  8 +++-
 src/citra_qt/main.cpp                       |  2 -
 src/citra_qt/main.h                         |  5 +--
 src/citra_qt/multiplayer/chat_room.cpp      | 10 ++---
 src/citra_qt/multiplayer/chat_room.h        |  2 +-
 src/citra_qt/multiplayer/client_room.cpp    | 20 ++++-----
 src/citra_qt/multiplayer/client_room.h      |  2 +-
 src/citra_qt/multiplayer/direct_connect.cpp |  8 ++--
 src/citra_qt/multiplayer/direct_connect.h   |  2 +-
 src/citra_qt/multiplayer/host_room.cpp      | 18 ++++----
 src/citra_qt/multiplayer/host_room.h        |  2 +-
 src/citra_qt/multiplayer/lobby.cpp          |  6 +--
 src/citra_qt/multiplayer/lobby.h            |  4 +-
 src/citra_qt/multiplayer/message.cpp        | 12 +++---
 src/citra_qt/multiplayer/state.cpp          | 13 +++---
 src/citra_qt/multiplayer/validation.h       | 48 ++++++++++++++-------
 src/citra_qt/ui_settings.h                  |  2 +-
 17 files changed, 93 insertions(+), 71 deletions(-)

diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index fbc343037..868447a4a 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -238,8 +238,12 @@ void Config::ReadValues() {
     UISettings::values.port = qt_config->value("port", Network::DefaultRoomPort).toString();
     UISettings::values.room_nickname = qt_config->value("room_nickname", "").toString();
     UISettings::values.room_name = qt_config->value("room_name", "").toString();
-    UISettings::values.room_port = qt_config->value("room_port", 24872).toString();
-    UISettings::values.host_type = qt_config->value("host_type", 0).toString();
+    UISettings::values.room_port = qt_config->value("room_port", "24872").toString();
+    bool ok;
+    UISettings::values.host_type = qt_config->value("host_type", 0).toUInt(&ok);
+    if (!ok) {
+        UISettings::values.host_type = 0;
+    }
     UISettings::values.max_player = qt_config->value("max_player", 8).toUInt();
     UISettings::values.game_id = qt_config->value("game_id", 0).toULongLong();
     qt_config->endGroup();
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 306c79ace..519d1e2e5 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -133,8 +133,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
 
     SetupUIStrings();
 
-    setWindowTitle(QString("Citra %1| %2-%3")
-                       .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
     show();
 
     game_list->LoadCompatibilityList();
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index f0aaf9114..686624603 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -55,10 +55,11 @@ public:
     void filterBarSetChecked(bool state);
     void UpdateUITheme();
 
-    GameList* game_list;
     GMainWindow();
     ~GMainWindow();
 
+    GameList* game_list;
+
 signals:
 
     /**
@@ -180,8 +181,6 @@ private:
 
     GRenderWindow* render_window;
 
-    QFutureWatcher<Service::AM::InstallStatus>* watcher = nullptr;
-
     // Status bar elements
     QProgressBar* progress_bar = nullptr;
     QLabel* message_label = nullptr;
diff --git a/src/citra_qt/multiplayer/chat_room.cpp b/src/citra_qt/multiplayer/chat_room.cpp
index d55b39c22..36f15ba6b 100644
--- a/src/citra_qt/multiplayer/chat_room.cpp
+++ b/src/citra_qt/multiplayer/chat_room.cpp
@@ -22,7 +22,7 @@ class ChatMessage {
 public:
     explicit ChatMessage(const Network::ChatEntry& chat, QTime ts = {}) {
         /// Convert the time to their default locale defined format
-        static QLocale locale;
+        QLocale locale;
         timestamp = locale.toString(ts.isValid() ? ts : QTime::currentTime(), QLocale::ShortFormat);
         nickname = QString::fromStdString(chat.nickname);
         message = QString::fromStdString(chat.message);
@@ -60,12 +60,12 @@ public:
     }
 
 private:
-    const QString system_color = "#888888";
+    static constexpr const char system_color[] = "#888888";
     QString timestamp;
     QString message;
 };
 
-ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(new Ui::ChatRoom) {
+ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ChatRoom>()) {
     ui->setupUi(this);
 
     // set the item_model for player_view
@@ -148,7 +148,7 @@ void ChatRoom::OnChatReceive(const Network::ChatEntry& chat) {
                                    return member.nickname == chat.nickname;
                                });
         if (it == members.end()) {
-            LOG_INFO(Network, "Chat message received from unknown player. Ignoring it.");
+            NGLOG_INFO(Network, "Chat message received from unknown player. Ignoring it.");
             return;
         }
         auto player = std::distance(members.begin(), it);
@@ -175,7 +175,7 @@ void ChatRoom::OnSendChat() {
                                    return member.nickname == chat.nickname;
                                });
         if (it == members.end()) {
-            LOG_INFO(Network, "Chat message received from unknown player");
+            NGLOG_INFO(Network, "Cannot find self in the player list when sending a message.");
         }
         auto player = std::distance(members.begin(), it);
         ChatMessage m(chat);
diff --git a/src/citra_qt/multiplayer/chat_room.h b/src/citra_qt/multiplayer/chat_room.h
index c837c24e0..0683b7a69 100644
--- a/src/citra_qt/multiplayer/chat_room.h
+++ b/src/citra_qt/multiplayer/chat_room.h
@@ -49,7 +49,7 @@ private:
     void AppendChatMessage(const QString&);
     bool ValidateMessage(const std::string&);
     QStandardItemModel* player_list;
-    Ui::ChatRoom* ui;
+    std::unique_ptr<Ui::ChatRoom> ui;
 };
 
 Q_DECLARE_METATYPE(Network::ChatEntry);
diff --git a/src/citra_qt/multiplayer/client_room.cpp b/src/citra_qt/multiplayer/client_room.cpp
index b4737eb3b..243b8adef 100644
--- a/src/citra_qt/multiplayer/client_room.cpp
+++ b/src/citra_qt/multiplayer/client_room.cpp
@@ -19,7 +19,7 @@
 
 ClientRoomWindow::ClientRoomWindow(QWidget* parent)
     : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
-      ui(new Ui::ClientRoom) {
+      ui(std::make_unique<Ui::ClientRoom>()) {
     ui->setupUi(this);
 
     // setup the callbacks for network updates
@@ -49,39 +49,39 @@ void ClientRoomWindow::OnRoomUpdate(const Network::RoomInformation& info) {
 void ClientRoomWindow::OnStateChange(const Network::RoomMember::State& state) {
     switch (state) {
     case Network::RoomMember::State::Idle:
-        LOG_INFO(Network, "State: Idle");
+        NGLOG_INFO(Network, "State: Idle");
         break;
     case Network::RoomMember::State::Joining:
-        LOG_INFO(Network, "State: Joining");
+        NGLOG_INFO(Network, "State: Joining");
         break;
     case Network::RoomMember::State::Joined:
-        LOG_INFO(Network, "State: Joined");
+        NGLOG_INFO(Network, "State: Joined");
         ui->chat->Clear();
         ui->chat->AppendStatusMessage(tr("Connected"));
         break;
     case Network::RoomMember::State::LostConnection:
         NetworkMessage::ShowError(NetworkMessage::LOST_CONNECTION);
-        LOG_INFO(Network, "State: LostConnection");
+        NGLOG_INFO(Network, "State: LostConnection");
         break;
     case Network::RoomMember::State::CouldNotConnect:
         NetworkMessage::ShowError(NetworkMessage::UNABLE_TO_CONNECT);
-        LOG_INFO(Network, "State: CouldNotConnect");
+        NGLOG_INFO(Network, "State: CouldNotConnect");
         break;
     case Network::RoomMember::State::NameCollision:
         NetworkMessage::ShowError(NetworkMessage::USERNAME_IN_USE);
-        LOG_INFO(Network, "State: NameCollision");
+        NGLOG_INFO(Network, "State: NameCollision");
         break;
     case Network::RoomMember::State::MacCollision:
         NetworkMessage::ShowError(NetworkMessage::MAC_COLLISION);
-        LOG_INFO(Network, "State: MacCollision");
+        NGLOG_INFO(Network, "State: MacCollision");
         break;
     case Network::RoomMember::State::WrongPassword:
         NetworkMessage::ShowError(NetworkMessage::WRONG_PASSWORD);
-        LOG_INFO(Network, "State: WrongPassword");
+        NGLOG_INFO(Network, "State: WrongPassword");
         break;
     case Network::RoomMember::State::WrongVersion:
         NetworkMessage::ShowError(NetworkMessage::WRONG_VERSION);
-        LOG_INFO(Network, "State: WrongVersion");
+        NGLOG_INFO(Network, "State: WrongVersion");
         break;
     default:
         break;
diff --git a/src/citra_qt/multiplayer/client_room.h b/src/citra_qt/multiplayer/client_room.h
index 8d282b754..a09212810 100644
--- a/src/citra_qt/multiplayer/client_room.h
+++ b/src/citra_qt/multiplayer/client_room.h
@@ -34,5 +34,5 @@ private:
     void UpdateView();
 
     QStandardItemModel* player_list;
-    Ui::ClientRoom* ui;
+    std::unique_ptr<Ui::ClientRoom> ui;
 };
diff --git a/src/citra_qt/multiplayer/direct_connect.cpp b/src/citra_qt/multiplayer/direct_connect.cpp
index c21fe5d75..218916f68 100644
--- a/src/citra_qt/multiplayer/direct_connect.cpp
+++ b/src/citra_qt/multiplayer/direct_connect.cpp
@@ -23,7 +23,7 @@ enum class ConnectionType : u8 { TraversalServer, IP };
 
 DirectConnectWindow::DirectConnectWindow(QWidget* parent)
     : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
-      ui(new Ui::DirectConnect) {
+      ui(std::make_unique<Ui::DirectConnect>()) {
 
     ui->setupUi(this);
 
@@ -31,11 +31,11 @@ DirectConnectWindow::DirectConnectWindow(QWidget* parent)
     watcher = new QFutureWatcher<void>;
     connect(watcher, &QFutureWatcher<void>::finished, this, &DirectConnectWindow::OnConnection);
 
-    ui->nickname->setValidator(Validation::nickname);
+    ui->nickname->setValidator(Validation::get().nickname);
     ui->nickname->setText(UISettings::values.nickname);
-    ui->ip->setValidator(Validation::ip);
+    ui->ip->setValidator(Validation::get().ip);
     ui->ip->setText(UISettings::values.ip);
-    ui->port->setValidator(Validation::port);
+    ui->port->setValidator(Validation::get().port);
     ui->port->setText(UISettings::values.port);
 
     // TODO(jroweboy): Show or hide the connection options based on the current value of the combo
diff --git a/src/citra_qt/multiplayer/direct_connect.h b/src/citra_qt/multiplayer/direct_connect.h
index 026484394..c824cb557 100644
--- a/src/citra_qt/multiplayer/direct_connect.h
+++ b/src/citra_qt/multiplayer/direct_connect.h
@@ -34,5 +34,5 @@ private:
     void EndConnecting();
 
     QFutureWatcher<void>* watcher;
-    Ui::DirectConnect* ui;
+    std::unique_ptr<Ui::DirectConnect> ui;
 };
diff --git a/src/citra_qt/multiplayer/host_room.cpp b/src/citra_qt/multiplayer/host_room.cpp
index 09958e596..8a3cd3d9f 100644
--- a/src/citra_qt/multiplayer/host_room.cpp
+++ b/src/citra_qt/multiplayer/host_room.cpp
@@ -26,13 +26,13 @@
 HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
                                std::shared_ptr<Core::AnnounceMultiplayerSession> session)
     : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
-      ui(new Ui::HostRoom), announce_multiplayer_session(session), game_list(list) {
+      ui(std::make_unique<Ui::HostRoom>()), announce_multiplayer_session(session), game_list(list) {
     ui->setupUi(this);
 
     // set up validation for all of the fields
-    ui->room_name->setValidator(Validation::room_name);
-    ui->username->setValidator(Validation::nickname);
-    ui->port->setValidator(Validation::port);
+    ui->room_name->setValidator(Validation::get().room_name);
+    ui->username->setValidator(Validation::get().nickname);
+    ui->port->setValidator(Validation::get().port);
     ui->port->setPlaceholderText(QString::number(Network::DefaultRoomPort));
 
     // Create a proxy to the game list to display the list of preferred games
@@ -49,8 +49,8 @@ HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
     ui->room_name->setText(UISettings::values.room_name);
     ui->port->setText(UISettings::values.room_port);
     ui->max_player->setValue(UISettings::values.max_player);
-    int index = ui->host_type->findData(UISettings::values.host_type);
-    if (index != -1) {
+    int index = UISettings::values.host_type;
+    if (index < ui->host_type->count()) {
         ui->host_type->setCurrentIndex(index);
     }
     index = ui->game_list->findData(UISettings::values.game_id, GameListItemPath::ProgramIdRole);
@@ -94,7 +94,7 @@ void HostRoomWindow::Host() {
                                         ui->max_player->value(), game_name.toStdString(), game_id);
             if (!created) {
                 NetworkMessage::ShowError(NetworkMessage::COULD_NOT_CREATE_ROOM);
-                LOG_ERROR(Network, "Could not create room!");
+                NGLOG_ERROR(Network, "Could not create room!");
                 ui->host->setEnabled(true);
                 return;
             }
@@ -109,7 +109,7 @@ void HostRoomWindow::Host() {
             ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
         UISettings::values.max_player = ui->max_player->value();
 
-        UISettings::values.host_type = ui->host_type->currentText();
+        UISettings::values.host_type = ui->host_type->currentIndex();
         UISettings::values.room_port = (ui->port->isModified() && !ui->port->text().isEmpty())
                                            ? ui->port->text()
                                            : QString::number(Network::DefaultRoomPort);
@@ -136,7 +136,7 @@ void HostRoomWindow::OnConnection() {
                 if (auto session = announce_multiplayer_session.lock()) {
                     session->Start();
                 } else {
-                    LOG_ERROR(Network, "Starting announce session failed");
+                    NGLOG_ERROR(Network, "Starting announce session failed");
                 }
             }
             auto parent = static_cast<MultiplayerState*>(parentWidget());
diff --git a/src/citra_qt/multiplayer/host_room.h b/src/citra_qt/multiplayer/host_room.h
index 289dbb040..64e6c0ab8 100644
--- a/src/citra_qt/multiplayer/host_room.h
+++ b/src/citra_qt/multiplayer/host_room.h
@@ -52,7 +52,7 @@ private:
     std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
     QStandardItemModel* game_list;
     ComboBoxProxyModel* proxy;
-    Ui::HostRoom* ui;
+    std::unique_ptr<Ui::HostRoom> ui;
 };
 
 /**
diff --git a/src/citra_qt/multiplayer/lobby.cpp b/src/citra_qt/multiplayer/lobby.cpp
index b4e91d6ed..66632cdcc 100644
--- a/src/citra_qt/multiplayer/lobby.cpp
+++ b/src/citra_qt/multiplayer/lobby.cpp
@@ -22,7 +22,7 @@
 Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
              std::shared_ptr<Core::AnnounceMultiplayerSession> session)
     : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
-      ui(new Ui::Lobby), announce_multiplayer_session(session), game_list(list) {
+      ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session), game_list(list) {
     ui->setupUi(this);
 
     // setup the watcher for background connections
@@ -48,7 +48,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
     ui->room_list->setExpandsOnDoubleClick(false);
     ui->room_list->setContextMenuPolicy(Qt::CustomContextMenu);
 
-    ui->nickname->setValidator(Validation::nickname);
+    ui->nickname->setValidator(Validation::get().nickname);
     ui->nickname->setText(UISettings::values.nickname);
 
     // UI Buttons
@@ -74,7 +74,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
     RefreshLobby();
 }
 
-const QString Lobby::PasswordPrompt() {
+QString Lobby::PasswordPrompt() {
     bool ok;
     const QString text =
         QInputDialog::getText(this, tr("Password Required to Join"), tr("Password:"),
diff --git a/src/citra_qt/multiplayer/lobby.h b/src/citra_qt/multiplayer/lobby.h
index 4fbc56b9a..c02febf57 100644
--- a/src/citra_qt/multiplayer/lobby.h
+++ b/src/citra_qt/multiplayer/lobby.h
@@ -97,7 +97,7 @@ private:
      * Prompts for a password. Returns an empty QString if the user either did not provide a
      * password or if the user closed the window.
      */
-    const QString PasswordPrompt();
+    QString PasswordPrompt();
 
     QStandardItemModel* model;
     QStandardItemModel* game_list;
@@ -105,7 +105,7 @@ private:
 
     std::future<AnnounceMultiplayerRoom::RoomList> room_list_future;
     std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
-    Ui::Lobby* ui;
+    std::unique_ptr<Ui::Lobby> ui;
     QFutureWatcher<void>* watcher;
 };
 
diff --git a/src/citra_qt/multiplayer/message.cpp b/src/citra_qt/multiplayer/message.cpp
index f74a57025..28d62bb81 100644
--- a/src/citra_qt/multiplayer/message.cpp
+++ b/src/citra_qt/multiplayer/message.cpp
@@ -19,20 +19,22 @@ const ConnectionError PORT_NOT_VALID(QT_TR_NOOP("Port must be a number between 0
 const ConnectionError NO_INTERNET(
     QT_TR_NOOP("Unable to find an internet connection. Check your internet settings."));
 const ConnectionError UNABLE_TO_CONNECT(
-    QT_TR_NOOP("Unable to connect to the host. Verify that the connection settings are correct."));
+    QT_TR_NOOP("Unable to connect to the host. Verify that the connection settings are correct. If "
+               "you still cannot connect, contact the room host and verify that the host is "
+               "properly configured with the external port forwarded."));
 const ConnectionError COULD_NOT_CREATE_ROOM(
     QT_TR_NOOP("Creating a room failed. Please retry. Restarting Citra might be necessary."));
 const ConnectionError HOST_BANNED(
     QT_TR_NOOP("The host of the room has banned you. Speak with the host to unban you "
                "or try a different room."));
 const ConnectionError WRONG_VERSION(
-    QT_TR_NOOP("You are using a different version of Citra-Local-Wifi(tm) then the room "
-               "you are trying to connect to."));
-const ConnectionError WRONG_PASSWORD(QT_TR_NOOP("Wrong password."));
+    QT_TR_NOOP("Version mismatch! Please update to the latest version of citra. If the problem "
+               "persists, contact the room host and ask them to update the server."));
+const ConnectionError WRONG_PASSWORD(QT_TR_NOOP("Incorrect password."));
 const ConnectionError GENERIC_ERROR(QT_TR_NOOP("An error occured."));
 const ConnectionError LOST_CONNECTION(QT_TR_NOOP("Connection to room lost. Try to reconnect."));
 const ConnectionError MAC_COLLISION(
-    QT_TR_NOOP("MAC-Address is already in use. Please choose another."));
+    QT_TR_NOOP("MAC address is already in use. Please choose another."));
 
 static bool WarnMessage(const std::string& title, const std::string& text) {
     return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),
diff --git a/src/citra_qt/multiplayer/state.cpp b/src/citra_qt/multiplayer/state.cpp
index d90046c52..5339868fb 100644
--- a/src/citra_qt/multiplayer/state.cpp
+++ b/src/citra_qt/multiplayer/state.cpp
@@ -82,11 +82,14 @@ void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& s
 
 void MultiplayerState::OnAnnounceFailed(const Common::WebResult& result) {
     announce_multiplayer_session->Stop();
-    QMessageBox::warning(this, tr("Error"),
-                         tr("Failed to announce the room to the public lobby.\nThe room will not "
-                            "get listed publicly.\nError: ") +
-                             QString::fromStdString(result.result_string),
-                         QMessageBox::Ok);
+    QMessageBox::warning(
+        this, tr("Error"),
+        tr("Failed to announce the room to the public lobby. In order to host a room publicly, you "
+           "must have a valid Citra account configured in Emulation -> Configure -> Web. If you do "
+           "not want to publish a room in the public lobby, then select Unlisted instead.\n"
+           "Debug Message: ") +
+            QString::fromStdString(result.result_string),
+        QMessageBox::Ok);
 }
 
 static void BringWidgetToFront(QWidget* widget) {
diff --git a/src/citra_qt/multiplayer/validation.h b/src/citra_qt/multiplayer/validation.h
index fa6777beb..19c8fca75 100644
--- a/src/citra_qt/multiplayer/validation.h
+++ b/src/citra_qt/multiplayer/validation.h
@@ -7,22 +7,38 @@
 #include <QRegExp>
 #include <QValidator>
 
-namespace Validation {
-/// room name can be alphanumeric and " " "_" "." and "-"
-static const QRegExp room_name_regex("^[a-zA-Z0-9._- ]+$");
-static const QValidator* room_name = new QRegExpValidator(room_name_regex);
+class Validation {
+public:
+    static Validation get() {
+        static Validation validation;
+        return validation;
+    }
 
-/// nickname can be alphanumeric and " " "_" "." and "-"
-static const QRegExp nickname_regex("^[a-zA-Z0-9._- ]+$");
-static const QValidator* nickname = new QRegExpValidator(nickname_regex);
+    ~Validation() {
+        delete room_name;
+        delete nickname;
+        delete ip;
+        delete port;
+    }
 
-/// ipv4 address only
-// TODO remove this when we support hostnames in direct connect
-static const QRegExp ip_regex(
-    "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|"
-    "2[0-4][0-9]|25[0-5])");
-static const QValidator* ip = new QRegExpValidator(ip_regex);
+    /// room name can be alphanumeric and " " "_" "." and "-"
+    QRegExp room_name_regex = QRegExp("^[a-zA-Z0-9._- ]+$");
+    const QValidator* room_name = new QRegExpValidator(room_name_regex);
 
-/// port must be between 0 and 65535
-static const QValidator* port = new QIntValidator(0, 65535);
-}; // namespace Validation
+    /// nickname can be alphanumeric and " " "_" "." and "-"
+    QRegExp nickname_regex = QRegExp("^[a-zA-Z0-9._- ]+$");
+    const QValidator* nickname = new QRegExpValidator(nickname_regex);
+
+    /// ipv4 address only
+    // TODO remove this when we support hostnames in direct connect
+    QRegExp ip_regex = QRegExp(
+        "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|"
+        "2[0-4][0-9]|25[0-5])");
+    const QValidator* ip = new QRegExpValidator(ip_regex);
+
+    /// port must be between 0 and 65535
+    const QValidator* port = new QIntValidator(0, 65535);
+
+private:
+    Validation() = default;
+};
diff --git a/src/citra_qt/ui_settings.h b/src/citra_qt/ui_settings.h
index 895a24c1b..b102f560d 100644
--- a/src/citra_qt/ui_settings.h
+++ b/src/citra_qt/ui_settings.h
@@ -65,7 +65,7 @@ struct Values {
     QString room_name;
     quint32 max_player;
     QString room_port;
-    QString host_type;
+    uint host_type;
     qulonglong game_id;
 };