mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 22:11:26 +12:00
cli: set user-id per command line
This commit is contained in:
parent
98687d474b
commit
9c7230e79f
11 changed files with 165 additions and 119 deletions
|
@ -503,24 +503,31 @@ namespace
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Emulator::SetUsr(const std::string& user)
|
u32 Emulator::CheckUsr(const std::string& user)
|
||||||
{
|
{
|
||||||
if (user.empty())
|
u32 id = 0;
|
||||||
|
|
||||||
|
if (user.size() == 8)
|
||||||
{
|
{
|
||||||
return false;
|
std::from_chars(&user.front(), &user.back() + 1, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 id = 0;
|
return id;
|
||||||
std::from_chars(&user.front(), &user.back() + 1, id);
|
}
|
||||||
|
|
||||||
|
void Emulator::SetUsr(const std::string& user)
|
||||||
|
{
|
||||||
|
sys_log.notice("Setting user ID '%s'", user);
|
||||||
|
|
||||||
|
const u32 id = CheckUsr(user);
|
||||||
|
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
{
|
{
|
||||||
return false;
|
fmt::throw_exception("Failed to set user ID '%s'", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_usrid = id;
|
m_usrid = id;
|
||||||
m_usr = user;
|
m_usr = user;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Emulator::GetBackgroundPicturePath() const
|
std::string Emulator::GetBackgroundPicturePath() const
|
||||||
|
@ -2015,7 +2022,14 @@ bool Emulator::Quit(bool force_quit)
|
||||||
{
|
{
|
||||||
Emu.CleanUp();
|
Emu.CleanUp();
|
||||||
};
|
};
|
||||||
return GetCallbacks().try_to_quit(force_quit, on_exit);
|
|
||||||
|
if (GetCallbacks().try_to_quit)
|
||||||
|
{
|
||||||
|
return GetCallbacks().try_to_quit(force_quit, on_exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
on_exit();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::CleanUp()
|
void Emulator::CleanUp()
|
||||||
|
|
|
@ -196,7 +196,9 @@ public:
|
||||||
return m_usrid;
|
return m_usrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetUsr(const std::string& user);
|
static u32 CheckUsr(const std::string& user);
|
||||||
|
|
||||||
|
void SetUsr(const std::string& user);
|
||||||
|
|
||||||
std::string GetBackgroundPicturePath() const;
|
std::string GetBackgroundPicturePath() const;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ headless_application::headless_application(int& argc, char** argv) : QCoreApplic
|
||||||
bool headless_application::Init()
|
bool headless_application::Init()
|
||||||
{
|
{
|
||||||
// Force init the emulator
|
// Force init the emulator
|
||||||
InitializeEmulator("00000001", true, false); // TODO: get user from cli args if possible
|
InitializeEmulator(m_active_user.empty() ? "00000001" : m_active_user, false);
|
||||||
|
|
||||||
// Create callbacks from the emulator, which reference the handlers.
|
// Create callbacks from the emulator, which reference the handlers.
|
||||||
InitializeCallbacks();
|
InitializeCallbacks();
|
||||||
|
@ -24,7 +24,7 @@ bool headless_application::Init()
|
||||||
// Create connects to propagate events throughout Gui.
|
// Create connects to propagate events throughout Gui.
|
||||||
InitializeConnects();
|
InitializeConnects();
|
||||||
|
|
||||||
// As per QT recommendations to avoid conflicts for POSIX functions
|
// As per Qt recommendations to avoid conflicts for POSIX functions
|
||||||
std::setlocale(LC_NUMERIC, "C");
|
std::setlocale(LC_NUMERIC, "C");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -208,6 +208,7 @@ constexpr auto arg_config = "config";
|
||||||
constexpr auto arg_q_debug = "qDebug";
|
constexpr auto arg_q_debug = "qDebug";
|
||||||
constexpr auto arg_error = "error";
|
constexpr auto arg_error = "error";
|
||||||
constexpr auto arg_updating = "updating";
|
constexpr auto arg_updating = "updating";
|
||||||
|
constexpr auto arg_user_id = "user-id";
|
||||||
constexpr auto arg_installfw = "installfw";
|
constexpr auto arg_installfw = "installfw";
|
||||||
constexpr auto arg_installpkg = "installpkg";
|
constexpr auto arg_installpkg = "installpkg";
|
||||||
constexpr auto arg_commit_db = "get-commit-db";
|
constexpr auto arg_commit_db = "get-commit-db";
|
||||||
|
@ -521,6 +522,8 @@ int main(int argc, char** argv)
|
||||||
parser.addOption(installfw_option);
|
parser.addOption(installfw_option);
|
||||||
const QCommandLineOption installpkg_option(arg_installpkg, "Forces the emulator to install this pkg file.", "path", "");
|
const QCommandLineOption installpkg_option(arg_installpkg, "Forces the emulator to install this pkg file.", "path", "");
|
||||||
parser.addOption(installpkg_option);
|
parser.addOption(installpkg_option);
|
||||||
|
const QCommandLineOption user_id_option(arg_user_id, "Start RPCS3 as this user.", "user id", "");
|
||||||
|
parser.addOption(user_id_option);
|
||||||
parser.addOption(QCommandLineOption(arg_q_debug, "Log qDebug to RPCS3.log."));
|
parser.addOption(QCommandLineOption(arg_q_debug, "Log qDebug to RPCS3.log."));
|
||||||
parser.addOption(QCommandLineOption(arg_error, "For internal usage."));
|
parser.addOption(QCommandLineOption(arg_error, "For internal usage."));
|
||||||
parser.addOption(QCommandLineOption(arg_updating, "For internal usage."));
|
parser.addOption(QCommandLineOption(arg_updating, "For internal usage."));
|
||||||
|
@ -716,6 +719,19 @@ int main(int argc, char** argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string active_user;
|
||||||
|
|
||||||
|
if (parser.isSet(arg_user_id))
|
||||||
|
{
|
||||||
|
active_user = parser.value(arg_user_id).toStdString();
|
||||||
|
|
||||||
|
if (Emulator::CheckUsr(active_user) == 0)
|
||||||
|
{
|
||||||
|
report_fatal_error(fmt::format("Failed to set user ID '%s'.\nThe user ID must consist of 8 digits and cannot be 00000000.", active_user));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s_no_gui = parser.isSet(arg_no_gui);
|
s_no_gui = parser.isSet(arg_no_gui);
|
||||||
|
|
||||||
if (auto gui_app = qobject_cast<gui_application*>(app.data()))
|
if (auto gui_app = qobject_cast<gui_application*>(app.data()))
|
||||||
|
@ -727,6 +743,7 @@ int main(int argc, char** argv)
|
||||||
gui_app->SetShowGui(!s_no_gui);
|
gui_app->SetShowGui(!s_no_gui);
|
||||||
gui_app->SetUseCliStyle(use_cli_style);
|
gui_app->SetUseCliStyle(use_cli_style);
|
||||||
gui_app->SetWithCliBoot(parser.isSet(arg_installfw) || parser.isSet(arg_installpkg) || !parser.positionalArguments().isEmpty());
|
gui_app->SetWithCliBoot(parser.isSet(arg_installfw) || parser.isSet(arg_installpkg) || !parser.positionalArguments().isEmpty());
|
||||||
|
gui_app->SetActiveUser(active_user);
|
||||||
|
|
||||||
if (!gui_app->Init())
|
if (!gui_app->Init())
|
||||||
{
|
{
|
||||||
|
@ -738,6 +755,8 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
s_headless = true;
|
s_headless = true;
|
||||||
|
|
||||||
|
headless_app->SetActiveUser(active_user);
|
||||||
|
|
||||||
if (!headless_app->Init())
|
if (!headless_app->Init())
|
||||||
{
|
{
|
||||||
Emu.Quit(true);
|
Emu.Quit(true);
|
||||||
|
@ -774,7 +793,7 @@ int main(int argc, char** argv)
|
||||||
if (!fs::is_file(config_override_path))
|
if (!fs::is_file(config_override_path))
|
||||||
{
|
{
|
||||||
report_fatal_error(fmt::format("No config file found: %s", config_override_path));
|
report_fatal_error(fmt::format("No config file found: %s", config_override_path));
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu.SetConfigOverride(config_override_path);
|
Emu.SetConfigOverride(config_override_path);
|
||||||
|
|
|
@ -33,21 +33,12 @@
|
||||||
|
|
||||||
LOG_CHANNEL(sys_log, "SYS");
|
LOG_CHANNEL(sys_log, "SYS");
|
||||||
|
|
||||||
/** Emu.Init() wrapper for user manager */
|
/** Emu.Init() wrapper for user management */
|
||||||
bool main_application::InitializeEmulator(const std::string& user, bool force_init, bool show_gui)
|
void main_application::InitializeEmulator(const std::string& user, bool show_gui)
|
||||||
{
|
{
|
||||||
Emu.SetHasGui(show_gui);
|
Emu.SetHasGui(show_gui);
|
||||||
|
Emu.SetUsr(user);
|
||||||
// try to set a new user
|
Emu.Init();
|
||||||
const bool user_was_set = Emu.SetUsr(user);
|
|
||||||
|
|
||||||
// only init the emulation if forced or a user was set
|
|
||||||
if (user_was_set || force_init)
|
|
||||||
{
|
|
||||||
Emu.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
return user_was_set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */
|
/** RPCS3 emulator has functions it desires to call from the GUI at times. Initialize them in here. */
|
||||||
|
|
|
@ -10,12 +10,18 @@ class main_application
|
||||||
public:
|
public:
|
||||||
virtual bool Init() = 0;
|
virtual bool Init() = 0;
|
||||||
|
|
||||||
static bool InitializeEmulator(const std::string& user, bool force_init, bool show_gui);
|
static void InitializeEmulator(const std::string& user, bool show_gui);
|
||||||
|
|
||||||
|
void SetActiveUser(std::string user)
|
||||||
|
{
|
||||||
|
m_active_user = user;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QThread* get_thread() = 0;
|
virtual QThread* get_thread() = 0;
|
||||||
|
|
||||||
EmuCallbacks CreateCallbacks();
|
EmuCallbacks CreateCallbacks();
|
||||||
|
|
||||||
|
std::string m_active_user;
|
||||||
QWindow* m_game_window = nullptr; // (Currently) only needed so that pad handlers have a valid target for event filtering.
|
QWindow* m_game_window = nullptr; // (Currently) only needed so that pad handlers have a valid target for event filtering.
|
||||||
};
|
};
|
||||||
|
|
|
@ -63,14 +63,18 @@ bool gui_application::Init()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get deprecated active user (before August 2nd 2020)
|
// The user might be set by cli arg. If not, set another user.
|
||||||
QString active_user = m_gui_settings->GetValue(gui::um_active_user).toString();
|
if (m_active_user.empty())
|
||||||
|
{
|
||||||
|
// Get deprecated active user (before August 2nd 2020)
|
||||||
|
const QString active_user = m_gui_settings->GetValue(gui::um_active_user).toString();
|
||||||
|
|
||||||
// Get active user with deprecated active user as fallback
|
// Get active user with deprecated active user as fallback
|
||||||
active_user = m_persistent_settings->GetCurrentUser(active_user.isEmpty() ? "00000001" : active_user);
|
m_active_user = m_persistent_settings->GetCurrentUser(active_user.isEmpty() ? "00000001" : active_user).toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
// Force init the emulator
|
// Force init the emulator
|
||||||
InitializeEmulator(active_user.toStdString(), true, m_show_gui);
|
InitializeEmulator(m_active_user, m_show_gui);
|
||||||
|
|
||||||
// Create the main window
|
// Create the main window
|
||||||
if (m_show_gui)
|
if (m_show_gui)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
LOG_CHANNEL(gui_log, "GUI");
|
LOG_CHANNEL(gui_log, "GUI");
|
||||||
|
|
||||||
UserAccount::UserAccount(const std::string& user_id)
|
user_account::user_account(const std::string& user_id)
|
||||||
{
|
{
|
||||||
// Setting userId.
|
// Setting userId.
|
||||||
m_user_id = user_id;
|
m_user_id = user_id;
|
||||||
|
@ -16,8 +16,7 @@ UserAccount::UserAccount(const std::string& user_id)
|
||||||
m_user_dir = Emulator::GetHddDir() + "home/" + m_user_id + "/";
|
m_user_dir = Emulator::GetHddDir() + "home/" + m_user_id + "/";
|
||||||
|
|
||||||
// Setting userName.
|
// Setting userName.
|
||||||
fs::file file;
|
if (fs::file file; file.open(m_user_dir + "localusername", fs::read))
|
||||||
if (file.open(m_user_dir + "localusername", fs::read))
|
|
||||||
{
|
{
|
||||||
m_username = file.to_string();
|
m_username = file.to_string();
|
||||||
file.close();
|
file.close();
|
||||||
|
@ -25,15 +24,48 @@ UserAccount::UserAccount(const std::string& user_id)
|
||||||
if (m_username.length() > 16) // max of 16 chars on real PS3
|
if (m_username.length() > 16) // max of 16 chars on real PS3
|
||||||
{
|
{
|
||||||
m_username = m_username.substr(0, 16);
|
m_username = m_username.substr(0, 16);
|
||||||
gui_log.warning("UserAccount: localusername of userId=%s was too long, cropped to: %s", m_user_id, m_username);
|
gui_log.warning("user_account: localusername of userId=%s was too long, cropped to: %s", m_user_id, m_username);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gui_log.error("UserAccount: localusername file read error (userId=%s, userDir=%s).", m_user_id, m_user_dir);
|
gui_log.error("user_account: localusername file read error (userId=%s, userDir=%s).", m_user_id, m_user_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAccount::~UserAccount()
|
user_account::~user_account()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<u32, user_account> user_account::GetUserAccounts(const std::string& base_dir)
|
||||||
|
{
|
||||||
|
std::map<u32, user_account> user_list;
|
||||||
|
|
||||||
|
// I believe this gets the folder list sorted alphabetically by default,
|
||||||
|
// but I can't find proof of this always being true.
|
||||||
|
for (const auto& user_folder : fs::dir(base_dir))
|
||||||
|
{
|
||||||
|
if (!user_folder.is_directory)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the folder name exactly 8 all-numerical characters long?
|
||||||
|
const u32 key = Emulator::CheckUsr(user_folder.name);
|
||||||
|
|
||||||
|
if (key == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the localusername file exist?
|
||||||
|
if (!fs::is_file(base_dir + "/" + user_folder.name + "/localusername"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
user_list.emplace(key, user_account(user_folder.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return user_list;
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/types.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// Do not confuse this with the "user" in Emu/System.h.
|
// Do not confuse this with the "user" in Emu/System.h.
|
||||||
// That user is read from config.yml, and it only represents the currently "logged in" user.
|
// That user is read from config.yml, and it only represents the currently "logged in" user.
|
||||||
// The UserAccount class will represent all users in the home directory for the User Manager dialog.
|
// The user_account class will represent all users in the home directory for the User Manager dialog.
|
||||||
// Selecting a user account in this dialog and saving writes it to config.yml.
|
// Selecting a user account in this dialog and saving writes it to config.yml.
|
||||||
class UserAccount
|
class user_account
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit UserAccount(const std::string& user_id = "00000001");
|
explicit user_account(const std::string& user_id = "00000001");
|
||||||
|
|
||||||
std::string GetUserId() { return m_user_id; }
|
std::string GetUserId() const { return m_user_id; }
|
||||||
std::string GetUserDir() { return m_user_dir; }
|
std::string GetUserDir() const { return m_user_dir; }
|
||||||
std::string GetUsername() { return m_username; }
|
std::string GetUsername() const { return m_username; }
|
||||||
~UserAccount();
|
~user_account();
|
||||||
|
|
||||||
|
static std::map<u32, user_account> GetUserAccounts(const std::string& base_dir);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_user_id;
|
std::string m_user_id;
|
||||||
|
|
|
@ -28,43 +28,6 @@ constexpr auto qstr = QString::fromStdString;
|
||||||
|
|
||||||
LOG_CHANNEL(gui_log, "GUI");
|
LOG_CHANNEL(gui_log, "GUI");
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
std::map<u32, UserAccount> GetUserAccounts(const std::string& base_dir)
|
|
||||||
{
|
|
||||||
std::map<u32, UserAccount> user_list;
|
|
||||||
|
|
||||||
// I believe this gets the folder list sorted alphabetically by default,
|
|
||||||
// but I can't find proof of this always being true.
|
|
||||||
for (const auto& user_folder : fs::dir(base_dir))
|
|
||||||
{
|
|
||||||
if (!user_folder.is_directory)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the folder name exactly 8 all-numerical characters long?
|
|
||||||
// We use strtoul to find any non-numeric characters in folder name.
|
|
||||||
char* non_numeric_char;
|
|
||||||
const u32 key = static_cast<u32>(std::strtoul(user_folder.name.c_str(), &non_numeric_char, 10));
|
|
||||||
|
|
||||||
if (key == 0 || user_folder.name.length() != 8 || *non_numeric_char != '\0')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does the localusername file exist?
|
|
||||||
if (!fs::is_file(base_dir + "/" + user_folder.name + "/localusername"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
user_list.emplace(key, UserAccount(user_folder.name));
|
|
||||||
}
|
|
||||||
return user_list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user_manager_dialog::user_manager_dialog(std::shared_ptr<gui_settings> gui_settings, std::shared_ptr<persistent_settings> persistent_settings, QWidget* parent)
|
user_manager_dialog::user_manager_dialog(std::shared_ptr<gui_settings> gui_settings, std::shared_ptr<persistent_settings> persistent_settings, QWidget* parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_gui_settings(gui_settings)
|
, m_gui_settings(gui_settings)
|
||||||
|
@ -94,16 +57,16 @@ void user_manager_dialog::Init()
|
||||||
m_table->horizontalHeader()->setDefaultSectionSize(150);
|
m_table->horizontalHeader()->setDefaultSectionSize(150);
|
||||||
m_table->installEventFilter(this);
|
m_table->installEventFilter(this);
|
||||||
|
|
||||||
QPushButton* push_remove_user = new QPushButton(tr("Delete User"), this);
|
QPushButton* push_remove_user = new QPushButton(tr("&Delete User"), this);
|
||||||
push_remove_user->setAutoDefault(false);
|
push_remove_user->setAutoDefault(false);
|
||||||
|
|
||||||
QPushButton* push_create_user = new QPushButton(tr("Create User"), this);
|
QPushButton* push_create_user = new QPushButton(tr("&Create User"), this);
|
||||||
push_create_user->setAutoDefault(false);
|
push_create_user->setAutoDefault(false);
|
||||||
|
|
||||||
QPushButton* push_login_user = new QPushButton(tr("Log In User"), this);
|
QPushButton* push_login_user = new QPushButton(tr("&Log In User"), this);
|
||||||
push_login_user->setAutoDefault(false);
|
push_login_user->setAutoDefault(false);
|
||||||
|
|
||||||
QPushButton* push_rename_user = new QPushButton(tr("Rename User"), this);
|
QPushButton* push_rename_user = new QPushButton(tr("&Rename User"), this);
|
||||||
push_rename_user->setAutoDefault(false);
|
push_rename_user->setAutoDefault(false);
|
||||||
|
|
||||||
QPushButton* push_close = new QPushButton(tr("&Close"), this);
|
QPushButton* push_close = new QPushButton(tr("&Close"), this);
|
||||||
|
@ -139,12 +102,18 @@ void user_manager_dialog::Init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the real active user (might differ, set by cli)
|
||||||
|
if (m_active_user != Emu.GetUsr())
|
||||||
|
{
|
||||||
|
m_active_user = Emu.GetUsr();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateTable();
|
UpdateTable();
|
||||||
|
|
||||||
restoreGeometry(m_gui_settings->GetValue(gui::um_geometry).toByteArray());
|
restoreGeometry(m_gui_settings->GetValue(gui::um_geometry).toByteArray());
|
||||||
|
|
||||||
// Use this in multiple connects to protect the current user from deletion/rename.
|
// Use this in multiple connects to protect the current user from deletion/rename.
|
||||||
auto enableButtons = [=, this]()
|
const auto enable_buttons = [=, this]()
|
||||||
{
|
{
|
||||||
const u32 key = GetUserKey();
|
const u32 key = GetUserKey();
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
|
@ -162,7 +131,7 @@ void user_manager_dialog::Init()
|
||||||
push_remove_user->setEnabled(enable);
|
push_remove_user->setEnabled(enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
enableButtons();
|
enable_buttons();
|
||||||
|
|
||||||
// Connects and events
|
// Connects and events
|
||||||
connect(push_close, &QAbstractButton::clicked, this, &user_manager_dialog::close);
|
connect(push_close, &QAbstractButton::clicked, this, &user_manager_dialog::close);
|
||||||
|
@ -170,11 +139,11 @@ void user_manager_dialog::Init()
|
||||||
connect(push_rename_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserRename);
|
connect(push_rename_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserRename);
|
||||||
connect(push_create_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserCreate);
|
connect(push_create_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserCreate);
|
||||||
connect(push_login_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserLogin);
|
connect(push_login_user, &QAbstractButton::clicked, this, &user_manager_dialog::OnUserLogin);
|
||||||
connect(this, &user_manager_dialog::OnUserLoginSuccess, this, enableButtons);
|
connect(this, &user_manager_dialog::OnUserLoginSuccess, this, enable_buttons);
|
||||||
connect(m_table->horizontalHeader(), &QHeaderView::sectionClicked, this, &user_manager_dialog::OnSort);
|
connect(m_table->horizontalHeader(), &QHeaderView::sectionClicked, this, &user_manager_dialog::OnSort);
|
||||||
connect(m_table, &QTableWidget::customContextMenuRequested, this, &user_manager_dialog::ShowContextMenu);
|
connect(m_table, &QTableWidget::customContextMenuRequested, this, &user_manager_dialog::ShowContextMenu);
|
||||||
connect(m_table, &QTableWidget::itemDoubleClicked, this, &user_manager_dialog::OnUserLogin);
|
connect(m_table, &QTableWidget::itemDoubleClicked, this, &user_manager_dialog::OnUserLogin);
|
||||||
connect(m_table, &QTableWidget::itemSelectionChanged, this, enableButtons);
|
connect(m_table, &QTableWidget::itemSelectionChanged, this, enable_buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
void user_manager_dialog::UpdateTable(bool mark_only)
|
void user_manager_dialog::UpdateTable(bool mark_only)
|
||||||
|
@ -185,7 +154,7 @@ void user_manager_dialog::UpdateTable(bool mark_only)
|
||||||
|
|
||||||
if (mark_only)
|
if (mark_only)
|
||||||
{
|
{
|
||||||
QString active_user = qstr(m_active_user);
|
const QString active_user = qstr(m_active_user);
|
||||||
|
|
||||||
for (int i = 0; i < m_table->rowCount(); i++)
|
for (int i = 0; i < m_table->rowCount(); i++)
|
||||||
{
|
{
|
||||||
|
@ -209,26 +178,26 @@ void user_manager_dialog::UpdateTable(bool mark_only)
|
||||||
|
|
||||||
// Get the user folders in the home directory and the currently logged in user.
|
// Get the user folders in the home directory and the currently logged in user.
|
||||||
m_user_list.clear();
|
m_user_list.clear();
|
||||||
m_user_list = GetUserAccounts(Emulator::GetHddDir() + "home");
|
m_user_list = user_account::GetUserAccounts(Emulator::GetHddDir() + "home");
|
||||||
|
|
||||||
// Clear and then repopulate the table with the list gathered above.
|
// Clear and then repopulate the table with the list gathered above.
|
||||||
m_table->setRowCount(static_cast<int>(m_user_list.size()));
|
m_table->setRowCount(static_cast<int>(m_user_list.size()));
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
for (auto& user : m_user_list)
|
for (auto& [id, account] : m_user_list)
|
||||||
{
|
{
|
||||||
QTableWidgetItem* user_id_item = new QTableWidgetItem(qstr(user.second.GetUserId()));
|
QTableWidgetItem* user_id_item = new QTableWidgetItem(qstr(account.GetUserId()));
|
||||||
user_id_item->setData(Qt::UserRole, user.first); // For sorting to work properly
|
user_id_item->setData(Qt::UserRole, id); // For sorting to work properly
|
||||||
user_id_item->setFlags(user_id_item->flags() & ~Qt::ItemIsEditable);
|
user_id_item->setFlags(user_id_item->flags() & ~Qt::ItemIsEditable);
|
||||||
m_table->setItem(row, 0, user_id_item);
|
m_table->setItem(row, 0, user_id_item);
|
||||||
|
|
||||||
QTableWidgetItem* username_item = new QTableWidgetItem(qstr(user.second.GetUsername()));
|
QTableWidgetItem* username_item = new QTableWidgetItem(qstr(account.GetUsername()));
|
||||||
username_item->setData(Qt::UserRole, user.first); // For sorting to work properly
|
username_item->setData(Qt::UserRole, id); // For sorting to work properly
|
||||||
username_item->setFlags(username_item->flags() & ~Qt::ItemIsEditable);
|
username_item->setFlags(username_item->flags() & ~Qt::ItemIsEditable);
|
||||||
m_table->setItem(row, 1, username_item);
|
m_table->setItem(row, 1, username_item);
|
||||||
|
|
||||||
// Compare current config value with the one in this user (only 8 digits in userId)
|
// Compare current config value with the one in this user (only 8 digits in userId)
|
||||||
if (m_active_user.starts_with(user.second.GetUserId()))
|
if (m_active_user.starts_with(account.GetUserId()))
|
||||||
{
|
{
|
||||||
user_id_item->setFont(bold_font);
|
user_id_item->setFont(bold_font);
|
||||||
username_item->setFont(bold_font);
|
username_item->setFont(bold_font);
|
||||||
|
@ -240,12 +209,12 @@ void user_manager_dialog::UpdateTable(bool mark_only)
|
||||||
m_table->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
|
m_table->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
|
||||||
m_table->verticalHeader()->resizeSections(QHeaderView::ResizeToContents);
|
m_table->verticalHeader()->resizeSections(QHeaderView::ResizeToContents);
|
||||||
|
|
||||||
QSize table_size = QSize(
|
const QSize table_size(
|
||||||
m_table->verticalHeader()->width() + m_table->horizontalHeader()->length() + m_table->frameWidth() * 2,
|
m_table->verticalHeader()->width() + m_table->horizontalHeader()->length() + m_table->frameWidth() * 2,
|
||||||
m_table->horizontalHeader()->height() + m_table->verticalHeader()->length() + m_table->frameWidth() * 2);
|
m_table->horizontalHeader()->height() + m_table->verticalHeader()->length() + m_table->frameWidth() * 2);
|
||||||
|
|
||||||
QSize preferred_size = minimumSize().expandedTo(sizeHint() - m_table->sizeHint() + table_size).expandedTo(size());
|
const QSize preferred_size = minimumSize().expandedTo(sizeHint() - m_table->sizeHint() + table_size).expandedTo(size());
|
||||||
QSize max_size = QSize(preferred_size.width(), static_cast<int>(QGuiApplication::primaryScreen()->size().height() * 0.6));
|
const QSize max_size(preferred_size.width(), static_cast<int>(QGuiApplication::primaryScreen()->size().height() * 0.6));
|
||||||
|
|
||||||
resize(preferred_size.boundedTo(max_size));
|
resize(preferred_size.boundedTo(max_size));
|
||||||
}
|
}
|
||||||
|
@ -253,7 +222,7 @@ void user_manager_dialog::UpdateTable(bool mark_only)
|
||||||
// Remove a user folder, needs to be confirmed.
|
// Remove a user folder, needs to be confirmed.
|
||||||
void user_manager_dialog::OnUserRemove()
|
void user_manager_dialog::OnUserRemove()
|
||||||
{
|
{
|
||||||
u32 key = GetUserKey();
|
const u32 key = GetUserKey();
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -274,6 +243,8 @@ void user_manager_dialog::OnUserRemove()
|
||||||
|
|
||||||
void user_manager_dialog::GenerateUser(const std::string& user_id, const std::string& username)
|
void user_manager_dialog::GenerateUser(const std::string& user_id, const std::string& username)
|
||||||
{
|
{
|
||||||
|
ensure(Emulator::CheckUsr(user_id) > 0);
|
||||||
|
|
||||||
// Create user folders and such.
|
// Create user folders and such.
|
||||||
const std::string home_dir = Emulator::GetHddDir() + "home/";
|
const std::string home_dir = Emulator::GetHddDir() + "home/";
|
||||||
const std::string user_dir = home_dir + user_id;
|
const std::string user_dir = home_dir + user_id;
|
||||||
|
@ -298,7 +269,7 @@ bool user_manager_dialog::ValidateUsername(const QString& text_to_validate)
|
||||||
|
|
||||||
void user_manager_dialog::OnUserRename()
|
void user_manager_dialog::OnUserRename()
|
||||||
{
|
{
|
||||||
u32 key = GetUserKey();
|
const u32 key = GetUserKey();
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -318,7 +289,7 @@ void user_manager_dialog::OnUserRename()
|
||||||
{
|
{
|
||||||
dialog->resize(200, 100);
|
dialog->resize(200, 100);
|
||||||
|
|
||||||
QString text_to_validate = dialog->textValue();
|
const QString text_to_validate = dialog->textValue();
|
||||||
if (!ValidateUsername(text_to_validate))
|
if (!ValidateUsername(text_to_validate))
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, tr("Error"), tr("Name must be between 3 and 16 characters and only consist of letters, numbers, underscores, and hyphens."));
|
QMessageBox::warning(this, tr("Error"), tr("Name must be between 3 and 16 characters and only consist of letters, numbers, underscores, and hyphens."));
|
||||||
|
@ -359,7 +330,14 @@ void user_manager_dialog::OnUserCreate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (smallest >= 100000000) // Only 8 digits allowed
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Error"), tr("Cannot add more users."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string next_user_id = fmt::format("%08d", smallest);
|
const std::string next_user_id = fmt::format("%08d", smallest);
|
||||||
|
ensure(Emulator::CheckUsr(next_user_id) > 0);
|
||||||
|
|
||||||
QInputDialog* dialog = new QInputDialog(this);
|
QInputDialog* dialog = new QInputDialog(this);
|
||||||
dialog->setWindowTitle(tr("New User"));
|
dialog->setWindowTitle(tr("New User"));
|
||||||
|
@ -397,11 +375,7 @@ void user_manager_dialog::OnUserLogin()
|
||||||
const u32 key = GetUserKey();
|
const u32 key = GetUserKey();
|
||||||
const std::string new_user = m_user_list[key].GetUserId();
|
const std::string new_user = m_user_list[key].GetUserId();
|
||||||
|
|
||||||
if (!main_application::InitializeEmulator(new_user, false, Emu.HasGui()))
|
main_application::InitializeEmulator(new_user, Emu.HasGui());
|
||||||
{
|
|
||||||
gui_log.fatal("Failed to login user! username=%s key=%d", new_user, key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_active_user = new_user;
|
m_active_user = new_user;
|
||||||
m_persistent_settings->SetValue(gui::persistent::active_user, qstr(m_active_user));
|
m_persistent_settings->SetValue(gui::persistent::active_user, qstr(m_active_user));
|
||||||
|
@ -429,7 +403,7 @@ void user_manager_dialog::OnSort(int logicalIndex)
|
||||||
|
|
||||||
void user_manager_dialog::ShowContextMenu(const QPoint &pos)
|
void user_manager_dialog::ShowContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
u32 key = GetUserKey();
|
const u32 key = GetUserKey();
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -448,8 +422,7 @@ void user_manager_dialog::ShowContextMenu(const QPoint &pos)
|
||||||
QAction* show_dir_act = menu->addAction(tr("&Open User Directory"));
|
QAction* show_dir_act = menu->addAction(tr("&Open User Directory"));
|
||||||
|
|
||||||
// Only enable actions if selected user is not logged in user.
|
// Only enable actions if selected user is not logged in user.
|
||||||
std::string idx_user = m_user_list[key].GetUserId();
|
const bool enable = m_user_list[key].GetUserId() != m_active_user;
|
||||||
bool enable = idx_user != m_active_user;
|
|
||||||
|
|
||||||
remove_act->setEnabled(enable);
|
remove_act->setEnabled(enable);
|
||||||
rename_act->setEnabled(enable);
|
rename_act->setEnabled(enable);
|
||||||
|
@ -458,14 +431,14 @@ void user_manager_dialog::ShowContextMenu(const QPoint &pos)
|
||||||
connect(remove_act, &QAction::triggered, this, &user_manager_dialog::OnUserRemove);
|
connect(remove_act, &QAction::triggered, this, &user_manager_dialog::OnUserRemove);
|
||||||
connect(rename_act, &QAction::triggered, this, &user_manager_dialog::OnUserRename);
|
connect(rename_act, &QAction::triggered, this, &user_manager_dialog::OnUserRename);
|
||||||
connect(login_act, &QAction::triggered, this, &user_manager_dialog::OnUserLogin);
|
connect(login_act, &QAction::triggered, this, &user_manager_dialog::OnUserLogin);
|
||||||
connect(show_dir_act, &QAction::triggered, [=, this]()
|
connect(show_dir_act, &QAction::triggered, this, [this, key]()
|
||||||
{
|
{
|
||||||
QString path = qstr(m_user_list[key].GetUserDir());
|
const QString path = qstr(m_user_list[key].GetUserDir());
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(user_id_act, &QAction::triggered, this, [=, this] {OnSort(0); });
|
connect(user_id_act, &QAction::triggered, this, [this] {OnSort(0); });
|
||||||
connect(username_act, &QAction::triggered, this, [=, this] {OnSort(1); });
|
connect(username_act, &QAction::triggered, this, [this] {OnSort(1); });
|
||||||
|
|
||||||
menu->exec(m_table->viewport()->mapToGlobal(pos));
|
menu->exec(m_table->viewport()->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
@ -473,20 +446,20 @@ void user_manager_dialog::ShowContextMenu(const QPoint &pos)
|
||||||
// Returns the current user's key > 0. if no user is selected, return 0
|
// Returns the current user's key > 0. if no user is selected, return 0
|
||||||
u32 user_manager_dialog::GetUserKey()
|
u32 user_manager_dialog::GetUserKey()
|
||||||
{
|
{
|
||||||
int idx = m_table->currentRow();
|
const int idx = m_table->currentRow();
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTableWidgetItem* item = m_table->item(idx, 0);
|
const QTableWidgetItem* item = m_table->item(idx, 0);
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 idx_real = item->data(Qt::UserRole).toUInt();
|
const u32 idx_real = item->data(Qt::UserRole).toUInt();
|
||||||
if (m_user_list.find(idx_real) == m_user_list.end())
|
if (!m_user_list.contains(idx_real))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ private:
|
||||||
|
|
||||||
QTableWidget* m_table;
|
QTableWidget* m_table;
|
||||||
std::string m_active_user;
|
std::string m_active_user;
|
||||||
std::map<u32, UserAccount> m_user_list;
|
std::map<u32, user_account> m_user_list;
|
||||||
|
|
||||||
std::shared_ptr<gui_settings> m_gui_settings;
|
std::shared_ptr<gui_settings> m_gui_settings;
|
||||||
std::shared_ptr<persistent_settings> m_persistent_settings;
|
std::shared_ptr<persistent_settings> m_persistent_settings;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue