From d618ec9135cf4be7b5b19b7f60743e4fc5bee6f2 Mon Sep 17 00:00:00 2001 From: zeph <35661622+ZephyrCodesStuff@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:11:22 +0100 Subject: [PATCH] Clans: Qt GUI configuration impl Signed-off-by: zeph <35661622+ZephyrCodesStuff@users.noreply.github.com> --- rpcs3/Emu/CMakeLists.txt | 3 +- rpcs3/Emu/Cell/Modules/sceNpClans.cpp | 4 +- .../NP/{clan_client.cpp => clans_client.cpp} | 62 +++---- .../Emu/NP/{clan_client.h => clans_client.h} | 8 +- rpcs3/Emu/NP/clans_config.cpp | 140 ++++++++++++++ rpcs3/Emu/NP/clans_config.h | 26 +++ rpcs3/rpcs3qt/CMakeLists.txt | 1 + rpcs3/rpcs3qt/clans_settings_dialog.cpp | 172 ++++++++++++++++++ rpcs3/rpcs3qt/clans_settings_dialog.h | 29 +++ rpcs3/rpcs3qt/main_window.cpp | 7 + rpcs3/rpcs3qt/main_window.ui | 9 + 11 files changed, 423 insertions(+), 38 deletions(-) rename rpcs3/Emu/NP/{clan_client.cpp => clans_client.cpp} (90%) rename rpcs3/Emu/NP/{clan_client.h => clans_client.h} (98%) create mode 100644 rpcs3/Emu/NP/clans_config.cpp create mode 100644 rpcs3/Emu/NP/clans_config.h create mode 100644 rpcs3/rpcs3qt/clans_settings_dialog.cpp create mode 100644 rpcs3/rpcs3qt/clans_settings_dialog.h diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 44210909d8..5feef8f8ca 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -441,7 +441,8 @@ target_sources(rpcs3_emu PRIVATE NP/np_requests.cpp NP/signaling_handler.cpp NP/np_structs_extra.cpp - NP/clan_client.cpp + NP/clans_client.cpp + NP/clans_config.cpp NP/rpcn_client.cpp NP/rpcn_config.cpp NP/rpcn_countries.cpp diff --git a/rpcs3/Emu/Cell/Modules/sceNpClans.cpp b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp index 29f26d9e2b..51960f58bd 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpClans.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp @@ -2,7 +2,7 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "Emu/NP/np_handler.h" -#include "Emu/NP/clan_client.h" +#include "Emu/NP/clans_client.h" #include "sceNp.h" #include "sceNpClans.h" @@ -97,7 +97,7 @@ error_code sceNpClansInit(vm::cptr commId, vm::cptr -#include +#include #include #include @@ -118,7 +118,7 @@ namespace clan size_t size; }; - size_t clan_client::curlWriteCallback(void* data, size_t size, size_t nmemb, void* clientp) + size_t clans_client::curlWriteCallback(void* data, size_t size, size_t nmemb, void* clientp) { size_t realsize = size * nmemb; std::vector* mem = static_cast*>(clientp); @@ -130,17 +130,17 @@ namespace clan return realsize; } - clan_client::clan_client() + clans_client::clans_client() { createRequest(); } - clan_client::~clan_client() + clans_client::~clans_client() { destroyRequest(); } - SceNpClansError clan_client::createRequest() + SceNpClansError clans_client::createRequest() { if (curl) return SceNpClansError::SCE_NP_CLANS_ERROR_ALREADY_INITIALIZED; @@ -156,7 +156,7 @@ namespace clan return SceNpClansError::SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::destroyRequest() + SceNpClansError clans_client::destroyRequest() { if (curl) { @@ -167,7 +167,7 @@ namespace clan return SceNpClansError::SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::sendRequest(ClanRequestAction action, ClanManagerOperationType opType, pugi::xml_document* xmlBody, pugi::xml_document* outResponse) + SceNpClansError clans_client::sendRequest(ClanRequestAction action, ClanManagerOperationType opType, pugi::xml_document* xmlBody, pugi::xml_document* outResponse) { if (!curl) return SCE_NP_CLANS_ERROR_NOT_INITIALIZED; @@ -237,7 +237,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - std::string clan_client::getClanTicket(np::np_handler& nph) + std::string clans_client::getClanTicket(np::np_handler& nph) { if (nph.get_ticket().size() > 0) { std::vector ticket_bytes(1024); @@ -287,7 +287,7 @@ namespace clan } #pragma region Outgoing API Requests - SceNpClansError clan_client::getClanList(np::np_handler& nph, SceNpClansPagingRequest* paging, SceNpClansEntry* clanList, SceNpClansPagingResult* pageResult) + SceNpClansError clans_client::getClanList(np::np_handler& nph, SceNpClansPagingRequest* paging, SceNpClansEntry* clanList, SceNpClansPagingResult* pageResult) { pugi::xml_document doc = pugi::xml_document(); pugi::xml_node clan = doc.append_child("clan"); @@ -361,7 +361,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::getClanInfo(SceNpClanId clanId, SceNpClansClanInfo* clanInfo) + SceNpClansError clans_client::getClanInfo(SceNpClanId clanId, SceNpClansClanInfo* clanInfo) { pugi::xml_document doc = pugi::xml_document(); pugi::xml_node clan = doc.append_child("clan"); @@ -400,7 +400,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::getMemberInfo(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMemberEntry* memInfo) + SceNpClansError clans_client::getMemberInfo(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMemberEntry* memInfo) { std::string ticket = getClanTicket(nph); @@ -468,7 +468,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::getMemberList(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansMemberStatus /*status*/, SceNpClansMemberEntry* memList, SceNpClansPagingResult* pageResult) + SceNpClansError clans_client::getMemberList(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansMemberStatus /*status*/, SceNpClansMemberEntry* memList, SceNpClansPagingResult* pageResult) { std::string ticket = getClanTicket(nph); @@ -544,7 +544,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::getBlacklist(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansBlacklistEntry* bl, SceNpClansPagingResult* pageResult) + SceNpClansError clans_client::getBlacklist(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansBlacklistEntry* bl, SceNpClansPagingResult* pageResult) { std::string ticket = getClanTicket(nph); @@ -608,7 +608,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::addBlacklistEntry(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) + SceNpClansError clans_client::addBlacklistEntry(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) { std::string ticket = getClanTicket(nph); @@ -624,7 +624,7 @@ namespace clan return sendRequest(ClanRequestAction::RecordBlacklistEntry, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::removeBlacklistEntry(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) + SceNpClansError clans_client::removeBlacklistEntry(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) { std::string ticket = getClanTicket(nph); @@ -640,7 +640,7 @@ namespace clan return sendRequest(ClanRequestAction::DeleteBlacklistEntry, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::clanSearch(SceNpClansPagingRequest* paging, SceNpClansSearchableName* search, SceNpClansClanBasicInfo* clanList, SceNpClansPagingResult* pageResult) + SceNpClansError clans_client::clanSearch(SceNpClansPagingRequest* paging, SceNpClansSearchableName* search, SceNpClansClanBasicInfo* clanList, SceNpClansPagingResult* pageResult) { pugi::xml_document doc = pugi::xml_document(); pugi::xml_node clan = doc.append_child("clan"); @@ -702,7 +702,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::requestMembership(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* /*message*/) + SceNpClansError clans_client::requestMembership(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* /*message*/) { std::string ticket = getClanTicket(nph); @@ -715,7 +715,7 @@ namespace clan return sendRequest(ClanRequestAction::RequestMembership, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::cancelRequestMembership(np::np_handler& nph, SceNpClanId clanId) + SceNpClansError clans_client::cancelRequestMembership(np::np_handler& nph, SceNpClanId clanId) { std::string ticket = getClanTicket(nph); @@ -728,7 +728,7 @@ namespace clan return sendRequest(ClanRequestAction::CancelRequestMembership, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::sendMembershipResponse(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/, b8 allow) + SceNpClansError clans_client::sendMembershipResponse(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/, b8 allow) { std::string ticket = getClanTicket(nph); @@ -744,7 +744,7 @@ namespace clan return sendRequest(allow ? ClanRequestAction::AcceptMembershipRequest : ClanRequestAction::DeclineMembershipRequest, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::sendInvitation(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/) + SceNpClansError clans_client::sendInvitation(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/) { std::string ticket = getClanTicket(nph); @@ -760,7 +760,7 @@ namespace clan return sendRequest(ClanRequestAction::SendInvitation, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::cancelInvitation(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) + SceNpClansError clans_client::cancelInvitation(np::np_handler& nph, SceNpClanId clanId, SceNpId npId) { std::string ticket = getClanTicket(nph); @@ -776,7 +776,7 @@ namespace clan return sendRequest(ClanRequestAction::CancelInvitation, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::sendInvitationResponse(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* /*message*/, b8 accept) + SceNpClansError clans_client::sendInvitationResponse(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* /*message*/, b8 accept) { std::string ticket = getClanTicket(nph); @@ -789,7 +789,7 @@ namespace clan return sendRequest(accept ? ClanRequestAction::AcceptInvitation : ClanRequestAction::DeclineInvitation, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::updateMemberInfo(np::np_handler& nph, SceNpClanId clanId, SceNpClansUpdatableMemberInfo* info) + SceNpClansError clans_client::updateMemberInfo(np::np_handler& nph, SceNpClanId clanId, SceNpClansUpdatableMemberInfo* info) { std::string ticket = getClanTicket(nph); @@ -826,7 +826,7 @@ namespace clan return sendRequest(ClanRequestAction::UpdateMemberInfo, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::updateClanInfo(np::np_handler& nph, SceNpClanId clanId, SceNpClansUpdatableClanInfo* info) + SceNpClansError clans_client::updateClanInfo(np::np_handler& nph, SceNpClanId clanId, SceNpClansUpdatableClanInfo* info) { std::string ticket = getClanTicket(nph); @@ -844,7 +844,7 @@ namespace clan return sendRequest(ClanRequestAction::UpdateClanInfo, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::joinClan(np::np_handler& nph, SceNpClanId clanId) + SceNpClansError clans_client::joinClan(np::np_handler& nph, SceNpClanId clanId) { std::string ticket = getClanTicket(nph); @@ -857,7 +857,7 @@ namespace clan return sendRequest(ClanRequestAction::JoinClan, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::leaveClan(np::np_handler& nph, SceNpClanId clanId) + SceNpClansError clans_client::leaveClan(np::np_handler& nph, SceNpClanId clanId) { std::string ticket = getClanTicket(nph); @@ -870,7 +870,7 @@ namespace clan return sendRequest(ClanRequestAction::LeaveClan, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::kickMember(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/) + SceNpClansError clans_client::kickMember(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMessage* /*message*/) { std::string ticket = getClanTicket(nph); @@ -886,7 +886,7 @@ namespace clan return sendRequest(ClanRequestAction::KickMember, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::changeMemberRole(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMemberRole role) + SceNpClansError clans_client::changeMemberRole(np::np_handler& nph, SceNpClanId clanId, SceNpId npId, SceNpClansMemberRole role) { std::string ticket = getClanTicket(nph); @@ -905,7 +905,7 @@ namespace clan return sendRequest(ClanRequestAction::ChangeMemberRole, ClanManagerOperationType::UPDATE, &doc, &response); } - SceNpClansError clan_client::retrieveAnnouncements(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansMessageEntry* announcements, SceNpClansPagingResult* pageResult) + SceNpClansError clans_client::retrieveAnnouncements(np::np_handler& nph, SceNpClanId clanId, SceNpClansPagingRequest* paging, SceNpClansMessageEntry* announcements, SceNpClansPagingResult* pageResult) { std::string ticket = getClanTicket(nph); @@ -987,7 +987,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::postAnnouncement(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* announcement, SceNpClansMessageData* /*data*/, u32 duration, SceNpClansMessageId* msgId) + SceNpClansError clans_client::postAnnouncement(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessage* announcement, SceNpClansMessageData* /*data*/, u32 duration, SceNpClansMessageId* msgId) { std::string ticket = getClanTicket(nph); @@ -1018,7 +1018,7 @@ namespace clan return SCE_NP_CLANS_SUCCESS; } - SceNpClansError clan_client::deleteAnnouncement(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessageId announcementId) + SceNpClansError clans_client::deleteAnnouncement(np::np_handler& nph, SceNpClanId clanId, SceNpClansMessageId announcementId) { std::string ticket = getClanTicket(nph); diff --git a/rpcs3/Emu/NP/clan_client.h b/rpcs3/Emu/NP/clans_client.h similarity index 98% rename from rpcs3/Emu/NP/clan_client.h rename to rpcs3/Emu/NP/clans_client.h index 1703c59c78..c488f6be8a 100644 --- a/rpcs3/Emu/NP/clan_client.h +++ b/rpcs3/Emu/NP/clans_client.h @@ -59,7 +59,7 @@ namespace clan DeleteAnnouncement }; - class clan_client + class clans_client { private: CURL* curl = nullptr; @@ -72,8 +72,8 @@ namespace clan std::string getClanTicket(np::np_handler& nph); public: - clan_client(); - ~clan_client(); + clans_client(); + ~clans_client(); SceNpClansError createRequest(); SceNpClansError destroyRequest(); @@ -116,5 +116,5 @@ namespace clan struct sce_np_clans_manager { atomic_t is_initialized = false; - clan::clan_client* client; + clan::clans_client* client; }; \ No newline at end of file diff --git a/rpcs3/Emu/NP/clans_config.cpp b/rpcs3/Emu/NP/clans_config.cpp new file mode 100644 index 0000000000..86b062fa5f --- /dev/null +++ b/rpcs3/Emu/NP/clans_config.cpp @@ -0,0 +1,140 @@ +#include "stdafx.h" +#include "clans_config.h" +#include "Utilities/File.h" + +cfg_clans g_cfg_clans; + +LOG_CHANNEL(clans_config_log, "clans_config"); + +void cfg_clans::load() +{ + const std::string path = cfg_clans::get_path(); + + fs::file cfg_file(path, fs::read); + if (cfg_file) + { + clans_config_log.notice("Loading Clans config. Path: %s", path); + from_string(cfg_file.to_string()); + } + else + { + clans_config_log.notice("Clans config missing. Using default settings. Path: %s", path); + from_default(); + } +} + +void cfg_clans::save() const +{ +#ifdef _WIN32 + const std::string path_to_cfg = fs::get_config_dir(true); + if (!fs::create_path(path_to_cfg)) + { + clans_config_log.error("Could not create path: %s", path_to_cfg); + } +#endif + + const std::string path = cfg_clans::get_path(); + + if (!cfg::node::save(path)) + { + clans_config_log.error("Could not save config: %s (error=%s)", path, fs::g_tls_error); + } +} + +std::string cfg_clans::get_path() +{ + return fs::get_config_dir(true) + "clans.yml"; +} + +std::string cfg_clans::get_host() const +{ + return host.to_string(); +} + +std::vector> cfg_clans::get_hosts() +{ + std::vector> vec_hosts; + auto hosts_list = fmt::split(hosts.to_string(), {"|||"}); + + for (const auto& cur_host : hosts_list) + { + auto desc_and_host = fmt::split(cur_host, {"|"}); + if (desc_and_host.size() != 2) + { + clans_config_log.error("Invalid host in the list of hosts: %s", cur_host); + continue; + } + vec_hosts.push_back(std::make_pair(std::move(desc_and_host[0]), std::move(desc_and_host[1]))); + } + + if (vec_hosts.empty()) + { + hosts.from_default(); + save(); + return get_hosts(); + } + + return vec_hosts; +} + +void cfg_clans::set_host(std::string_view host) +{ + this->host.from_string(host); +} + +void cfg_clans::set_hosts(const std::vector>& vec_hosts) +{ + std::string final_string; + for (const auto& [cur_desc, cur_host] : vec_hosts) + { + fmt::append(final_string, "%s|%s|||", cur_desc, cur_host); + } + + if (final_string.empty()) + { + hosts.from_default(); + return; + } + + final_string.resize(final_string.size() - 3); + hosts.from_string(final_string); +} + +bool cfg_clans::add_host(std::string_view new_description, std::string_view new_host) +{ + auto cur_hosts = get_hosts(); + + for (const auto& [cur_desc, cur_host] : cur_hosts) + { + if (cur_desc == new_description && cur_host == new_host) + return false; + } + + cur_hosts.push_back(std::make_pair(std::string(new_description), std::string(new_host))); + set_hosts(cur_hosts); + + return true; +} + +bool cfg_clans::del_host(std::string_view del_description, std::string_view del_host) +{ + // Do not delete default servers + if (del_description == "Official Clans Server" && del_host == "clans.rpcs3.net") + { + return true; + } + + auto cur_hosts = get_hosts(); + + for (auto it = cur_hosts.begin(); it != cur_hosts.end(); it++) + { + if (it->first == del_description && it->second == del_host) + { + cur_hosts.erase(it); + set_hosts(cur_hosts); + return true; + } + } + + return false; +} diff --git a/rpcs3/Emu/NP/clans_config.h b/rpcs3/Emu/NP/clans_config.h new file mode 100644 index 0000000000..4a9f09d06b --- /dev/null +++ b/rpcs3/Emu/NP/clans_config.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Utilities/Config.h" + +struct cfg_clans : cfg::node +{ + cfg::uint32 version{this, "Version", 1}; + cfg::string host{this, "Host", "clans.rpcs3.net"}; + cfg::string hosts{this, "Hosts", "Official Clans Server|clans.rpcs3.net"}; + + void load(); + void save() const; + + std::string get_host() const; + std::vector> get_hosts(); + + void set_host(std::string_view host); + bool add_host(std::string_view description, std::string_view host); + bool del_host(std::string_view description, std::string_view host); + +private: + static std::string get_path(); + void set_hosts(const std::vector>& vec_hosts); +}; + +extern cfg_clans g_cfg_clans; diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 43c0024905..98be856a25 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(rpcs3_ui STATIC camera_settings_dialog.cpp cg_disasm_window.cpp cheat_manager.cpp + clans_settings_dialog.cpp config_adapter.cpp config_checker.cpp curl_handle.cpp diff --git a/rpcs3/rpcs3qt/clans_settings_dialog.cpp b/rpcs3/rpcs3qt/clans_settings_dialog.cpp new file mode 100644 index 0000000000..ff2113297f --- /dev/null +++ b/rpcs3/rpcs3qt/clans_settings_dialog.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "clans_settings_dialog.h" +#include "Emu/NP/clans_config.h" + +clans_settings_dialog::clans_settings_dialog(QWidget* parent) + : QDialog(parent) +{ + g_cfg_clans.load(); + + setWindowTitle(tr("Clans Configuration")); + setObjectName("clans_settings_dialog"); + + QVBoxLayout* vbox_global = new QVBoxLayout(); + + QGroupBox* grp_server = new QGroupBox(tr("Server:")); + QVBoxLayout* vbox_server = new QVBoxLayout(); + + QHBoxLayout* hbox_lbl_combo = new QHBoxLayout(); + QLabel* lbl_server = new QLabel(tr("Server:")); + cbx_servers = new QComboBox(); + + refresh_combobox(); + + hbox_lbl_combo->addWidget(lbl_server); + hbox_lbl_combo->addWidget(cbx_servers); + + QHBoxLayout* hbox_buttons = new QHBoxLayout(); + QPushButton* btn_add_server = new QPushButton(tr("Add")); + QPushButton* btn_del_server = new QPushButton(tr("Del")); + hbox_buttons->addStretch(); + hbox_buttons->addWidget(btn_add_server); + hbox_buttons->addWidget(btn_del_server); + + vbox_server->addLayout(hbox_lbl_combo); + vbox_server->addLayout(hbox_buttons); + + grp_server->setLayout(vbox_server); + vbox_global->addWidget(grp_server); + + setLayout(vbox_global); + + connect(cbx_servers, &QComboBox::currentIndexChanged, this, [this](int index) + { + if (index < 0) + return; + + QVariant host = cbx_servers->itemData(index); + + if (!host.isValid() || !host.canConvert()) + return; + + g_cfg_clans.set_host(host.toString().toStdString()); + g_cfg_clans.save(); + }); + + connect(btn_add_server, &QAbstractButton::clicked, this, [this]() + { + clans_add_server_dialog dlg(this); + dlg.exec(); + const auto& new_server = dlg.get_new_server(); + if (new_server) + { + if (!g_cfg_clans.add_host(new_server->first, new_server->second)) + { + QMessageBox::critical(this, tr("Existing Server"), tr("You already have a server with this description & hostname in the list."), QMessageBox::Ok); + return; + } + + g_cfg_clans.save(); + refresh_combobox(); + } + }); + + connect(btn_del_server, &QAbstractButton::clicked, this, [this]() + { + const int index = cbx_servers->currentIndex(); + + if (index < 0) + return; + + const std::string desc = cbx_servers->itemText(index).toStdString(); + const std::string host = cbx_servers->itemData(index).toString().toStdString(); + + if (g_cfg_clans.del_host(desc, host)) + { + g_cfg_clans.save(); + refresh_combobox(); + } + else + { + QMessageBox::warning(this, tr("Cannot Delete"), tr("This server cannot be deleted."), QMessageBox::Ok); + } + }); +} + +void clans_settings_dialog::refresh_combobox() +{ + g_cfg_clans.load(); + const auto vec_hosts = g_cfg_clans.get_hosts(); + const auto cur_host = g_cfg_clans.get_host(); + int i = 0, index = 0; + + cbx_servers->clear(); + + for (const auto& [desc, host] : vec_hosts) + { + cbx_servers->addItem(QString::fromStdString(desc), QString::fromStdString(host)); + if (cur_host == host) + index = i; + + i++; + } + + cbx_servers->setCurrentIndex(index); +} + +clans_add_server_dialog::clans_add_server_dialog(QWidget* parent) + : QDialog(parent) +{ + setWindowTitle(tr("Clans: Add Server")); + setObjectName("clans_add_server_dialog"); + setMinimumSize(QSize(400, 200)); + + QVBoxLayout* vbox_global = new QVBoxLayout(); + + QLabel* lbl_description = new QLabel(tr("Description:")); + QLineEdit* edt_description = new QLineEdit(); + QLabel* lbl_host = new QLabel(tr("Host:")); + QLineEdit* edt_host = new QLineEdit(); + QDialogButtonBox* btn_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + vbox_global->addWidget(lbl_description); + vbox_global->addWidget(edt_description); + vbox_global->addWidget(lbl_host); + vbox_global->addWidget(edt_host); + vbox_global->addWidget(btn_box); + + setLayout(vbox_global); + + connect(btn_box, &QDialogButtonBox::accepted, this, [this, edt_description, edt_host]() + { + const QString description = edt_description->text(); + const QString host = edt_host->text(); + + if (description.isEmpty()) + { + QMessageBox::critical(this, tr("Missing Description!"), tr("You must enter a description!"), QMessageBox::Ok); + return; + } + if (host.isEmpty()) + { + QMessageBox::critical(this, tr("Missing Hostname!"), tr("You must enter a hostname for the server!"), QMessageBox::Ok); + return; + } + + m_new_server = std::make_pair(description.toStdString(), host.toStdString()); + QDialog::accept(); + }); + connect(btn_box, &QDialogButtonBox::rejected, this, &QDialog::reject); +} + +const std::optional>& clans_add_server_dialog::get_new_server() const +{ + return m_new_server; +} diff --git a/rpcs3/rpcs3qt/clans_settings_dialog.h b/rpcs3/rpcs3qt/clans_settings_dialog.h new file mode 100644 index 0000000000..7672dfaa14 --- /dev/null +++ b/rpcs3/rpcs3qt/clans_settings_dialog.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +class clans_settings_dialog : public QDialog +{ + Q_OBJECT +public: + clans_settings_dialog(QWidget* parent = nullptr); + +private: + void refresh_combobox(); + +private: + QComboBox* cbx_servers = nullptr; +}; + +class clans_add_server_dialog : public QDialog +{ + Q_OBJECT +public: + clans_add_server_dialog(QWidget* parent = nullptr); + const std::optional>& get_new_server() const; + +private: + std::optional> m_new_server; +}; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 80d71a44c2..aee3ce5ca2 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -12,6 +12,7 @@ #include "log_frame.h" #include "settings_dialog.h" #include "rpcn_settings_dialog.h" +#include "clans_settings_dialog.h" #include "auto_pause_settings_dialog.h" #include "cg_disasm_window.h" #include "log_viewer.h" @@ -2991,6 +2992,12 @@ void main_window::CreateConnects() dlg.exec(); }); + connect(ui->confClansAct, &QAction::triggered, this, [this]() + { + clans_settings_dialog dlg(this); + dlg.exec(); + }); + connect(ui->confIPCAct, &QAction::triggered, this, [this]() { ipc_settings_dialog dlg(this); diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index 72861a5d72..c9c8c0645d 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -282,6 +282,7 @@ + @@ -1252,6 +1253,14 @@ Configure RPCN + + + Clans + + + Configure Clans + + IPC