From 88cc691afa9d1d61a1830ff7e3896b550ea18208 Mon Sep 17 00:00:00 2001 From: SCG82 Date: Wed, 14 Apr 2021 08:26:54 -0700 Subject: [PATCH] UI: Add obs-frontend-api functions to create/delete profiles --- UI/api-interface.cpp | 18 +++ UI/obs-frontend-api/obs-frontend-api.cpp | 18 +++ UI/obs-frontend-api/obs-frontend-api.h | 3 + UI/obs-frontend-api/obs-frontend-internal.hpp | 3 + UI/window-basic-main-profiles.cpp | 123 ++++++++++++++---- UI/window-basic-main.hpp | 8 +- docs/sphinx/reference-frontend-api.rst | 18 +++ 7 files changed, 163 insertions(+), 28 deletions(-) diff --git a/UI/api-interface.cpp b/UI/api-interface.cpp index 50a144fcd..3a5413a05 100644 --- a/UI/api-interface.cpp +++ b/UI/api-interface.cpp @@ -266,6 +266,24 @@ struct OBSStudioAPI : obs_frontend_callbacks { } } + void obs_frontend_create_profile(const char *name) override + { + QMetaObject::invokeMethod(main, "NewProfile", + Q_ARG(QString, name)); + } + + void obs_frontend_duplicate_profile(const char *name) override + { + QMetaObject::invokeMethod(main, "DuplicateProfile", + Q_ARG(QString, name)); + } + + void obs_frontend_delete_profile(const char *profile) override + { + QMetaObject::invokeMethod(main, "DeleteProfile", + Q_ARG(QString, profile)); + } + void obs_frontend_streaming_start(void) override { QMetaObject::invokeMethod(main, "StartStreaming"); diff --git a/UI/obs-frontend-api/obs-frontend-api.cpp b/UI/obs-frontend-api/obs-frontend-api.cpp index a4bc770bc..f69b24ff9 100644 --- a/UI/obs-frontend-api/obs-frontend-api.cpp +++ b/UI/obs-frontend-api/obs-frontend-api.cpp @@ -216,6 +216,24 @@ void obs_frontend_set_current_profile(const char *profile) c->obs_frontend_set_current_profile(profile); } +void obs_frontend_create_profile(const char *name) +{ + if (callbacks_valid()) + c->obs_frontend_create_profile(name); +} + +void obs_frontend_duplicate_profile(const char *name) +{ + if (callbacks_valid()) + c->obs_frontend_duplicate_profile(name); +} + +void obs_frontend_delete_profile(const char *profile) +{ + if (callbacks_valid()) + c->obs_frontend_delete_profile(profile); +} + void obs_frontend_streaming_start(void) { if (callbacks_valid()) diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h index 0638dbd1c..0f40a8cd8 100644 --- a/UI/obs-frontend-api/obs-frontend-api.h +++ b/UI/obs-frontend-api/obs-frontend-api.h @@ -119,6 +119,9 @@ EXPORT char **obs_frontend_get_profiles(void); EXPORT char *obs_frontend_get_current_profile(void); EXPORT char *obs_frontend_get_current_profile_path(void); EXPORT void obs_frontend_set_current_profile(const char *profile); +EXPORT void obs_frontend_create_profile(const char *name); +EXPORT void obs_frontend_duplicate_profile(const char *name); +EXPORT void obs_frontend_delete_profile(const char *profile); typedef void (*obs_frontend_cb)(void *private_data); diff --git a/UI/obs-frontend-api/obs-frontend-internal.hpp b/UI/obs-frontend-api/obs-frontend-internal.hpp index c925b8089..fec522854 100644 --- a/UI/obs-frontend-api/obs-frontend-internal.hpp +++ b/UI/obs-frontend-api/obs-frontend-internal.hpp @@ -39,6 +39,9 @@ struct obs_frontend_callbacks { virtual char *obs_frontend_get_current_profile(void) = 0; virtual char *obs_frontend_get_current_profile_path(void) = 0; virtual void obs_frontend_set_current_profile(const char *profile) = 0; + virtual void obs_frontend_create_profile(const char *name) = 0; + virtual void obs_frontend_duplicate_profile(const char *name) = 0; + virtual void obs_frontend_delete_profile(const char *profile) = 0; virtual void obs_frontend_streaming_start(void) = 0; virtual void obs_frontend_streaming_stop(void) = 0; diff --git a/UI/window-basic-main-profiles.cpp b/UI/window-basic-main-profiles.cpp index 86e9631d3..11e3d9f1c 100644 --- a/UI/window-basic-main-profiles.cpp +++ b/UI/window-basic-main-profiles.cpp @@ -77,12 +77,13 @@ void EnumProfiles(std::function &&cb) os_globfree(glob); } -static bool ProfileExists(const char *findName) +static bool GetProfileDir(const char *findName, const char *&profileDir) { bool found = false; - auto func = [&](const char *name, const char *) { + auto func = [&](const char *name, const char *path) { if (strcmp(name, findName) == 0) { found = true; + profileDir = strrchr(path, '/') + 1; return false; } return true; @@ -92,14 +93,17 @@ static bool ProfileExists(const char *findName) return found; } -static bool GetProfileName(QWidget *parent, std::string &name, - std::string &file, const char *title, - const char *text, const bool showWizard, - bool &wizardChecked, const char *oldName = nullptr) +static bool ProfileExists(const char *findName) { - char path[512]; - int ret; + const char *profileDir = nullptr; + return GetProfileDir(findName, profileDir); +} +static bool AskForProfileName(QWidget *parent, std::string &name, + const char *title, const char *text, + const bool showWizard, bool &wizardChecked, + const char *oldName = nullptr) +{ for (;;) { bool success = false; @@ -130,10 +134,23 @@ static bool GetProfileName(QWidget *parent, std::string &name, } break; } + return true; +} - if (!GetFileSafeName(name.c_str(), file)) { +static bool FindSafeProfileDirName(const std::string &profileName, + std::string &dirName) +{ + char path[512]; + int ret; + + if (ProfileExists(profileName.c_str())) { + blog(LOG_WARNING, "Profile '%s' exists", profileName.c_str()); + return false; + } + + if (!GetFileSafeName(profileName.c_str(), dirName)) { blog(LOG_WARNING, "Failed to create safe file name for '%s'", - name.c_str()); + profileName.c_str()); return false; } @@ -143,15 +160,15 @@ static bool GetProfileName(QWidget *parent, std::string &name, return false; } - file.insert(0, path); + dirName.insert(0, path); - if (!GetClosestUnusedFileName(file, nullptr)) { + if (!GetClosestUnusedFileName(dirName, nullptr)) { blog(LOG_WARNING, "Failed to get closest file name for %s", - file.c_str()); + dirName.c_str()); return false; } - file.erase(0, ret); + dirName.erase(0, ret); return true; } @@ -200,16 +217,26 @@ static bool CopyProfile(const char *fromPartial, const char *to) bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, const char *init_text, bool rename) { - std::string newName; - std::string newDir; - std::string newPath; - ConfigFile config; + std::string name; bool showWizardChecked = config_get_bool(App()->GlobalConfig(), "Basic", "ConfigOnNewProfile"); - if (!GetProfileName(this, newName, newDir, title, text, create_new, - showWizardChecked, init_text)) + if (!AskForProfileName(this, name, title, text, create_new, + showWizardChecked, init_text)) + return false; + + return CreateProfile(name, create_new, showWizardChecked, rename); +} + +bool OBSBasic::CreateProfile(const std::string &newName, bool create_new, + bool showWizardChecked, bool rename) +{ + std::string newDir; + std::string newPath; + ConfigFile config; + + if (!FindSafeProfileDirName(newName, newDir)) return false; if (create_new) { @@ -295,6 +322,16 @@ bool OBSBasic::AddProfile(bool create_new, const char *title, const char *text, return true; } +bool OBSBasic::NewProfile(const QString &name) +{ + return CreateProfile(name.toStdString(), true, false, false); +} + +bool OBSBasic::DuplicateProfile(const QString &name) +{ + return CreateProfile(name.toStdString(), false, false, false); +} + void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir) { char profilePath[512]; @@ -345,6 +382,36 @@ void OBSBasic::DeleteProfile(const char *profileName, const char *profileDir) blog(LOG_INFO, "------------------------------------------------"); } +void OBSBasic::DeleteProfile(const QString &profileName) +{ + std::string name = profileName.toStdString(); + const char *curName = + config_get_string(App()->GlobalConfig(), "Basic", "Profile"); + + if (strcmp(curName, name.c_str()) == 0) { + on_actionRemoveProfile_triggered(true); + return; + } + + const char *profileDir = nullptr; + if (!GetProfileDir(name.c_str(), profileDir)) { + blog(LOG_WARNING, "Profile '%s' not found", name.c_str()); + return; + } + + if (!profileDir) { + blog(LOG_WARNING, "Failed to get profile dir for profile '%s'", + name.c_str()); + return; + } + + DeleteProfile(name.c_str(), profileDir); + RefreshProfiles(); + config_save_safe(App()->GlobalConfig(), "tmp", nullptr); + if (api) + api->on_event(OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED); +} + void OBSBasic::RefreshProfiles() { QList menuActions = ui->profileMenu->actions(); @@ -435,7 +502,7 @@ void OBSBasic::on_actionRenameProfile_triggered() } } -void OBSBasic::on_actionRemoveProfile_triggered() +void OBSBasic::on_actionRemoveProfile_triggered(bool skipConfirmation) { std::string newName; std::string newPath; @@ -462,13 +529,15 @@ void OBSBasic::on_actionRemoveProfile_triggered() if (newPath.empty()) return; - QString text = QTStr("ConfirmRemove.Text"); - text.replace("$1", QT_UTF8(oldName.c_str())); + if (!skipConfirmation) { + QString text = QTStr("ConfirmRemove.Text"); + text.replace("$1", QT_UTF8(oldName.c_str())); - QMessageBox::StandardButton button = OBSMessageBox::question( - this, QTStr("ConfirmRemove.Title"), text); - if (button == QMessageBox::No) - return; + QMessageBox::StandardButton button = OBSMessageBox::question( + this, QTStr("ConfirmRemove.Title"), text); + if (button == QMessageBox::No) + return; + } size_t newPath_len = newPath.size(); newPath += "/basic.ini"; diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 88e78dfa9..28076da4d 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -380,6 +380,8 @@ private: void ResetProfileData(); bool AddProfile(bool create_new, const char *title, const char *text, const char *init_text = nullptr, bool rename = false); + bool CreateProfile(const std::string &newName, bool create_new, + bool showWizardChecked, bool rename = false); void DeleteProfile(const char *profile_name, const char *profile_dir); void RefreshProfiles(); void ChangeProfile(); @@ -609,6 +611,10 @@ public slots: bool AddSceneCollection(bool create_new, const QString &name = QString()); + bool NewProfile(const QString &name); + bool DuplicateProfile(const QString &name); + void DeleteProfile(const QString &profileName); + void UpdatePatronJson(const QString &text, const QString &error); void ShowContextBar(); @@ -973,7 +979,7 @@ private slots: void on_actionNewProfile_triggered(); void on_actionDupProfile_triggered(); void on_actionRenameProfile_triggered(); - void on_actionRemoveProfile_triggered(); + void on_actionRemoveProfile_triggered(bool skipConfirmation = false); void on_actionImportProfile_triggered(); void on_actionExportProfile_triggered(); diff --git a/docs/sphinx/reference-frontend-api.rst b/docs/sphinx/reference-frontend-api.rst index a3a36ba28..71cecd6b5 100644 --- a/docs/sphinx/reference-frontend-api.rst +++ b/docs/sphinx/reference-frontend-api.rst @@ -327,6 +327,24 @@ Functions --------------------------------------- +.. function:: bool obs_frontend_create_profile(const char *name) + + :param name: Name of the new profile to create (must be unique). + +--------------------------------------- + +.. function:: bool obs_frontend_duplicate_profile(const char *name) + + :param name: Name of the duplicate profile to create (must be unique). + +--------------------------------------- + +.. function:: void obs_frontend_delete_profile(const char *profile) + + :param profile: Name of the profile to delete. + +--------------------------------------- + .. function:: void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) Adds a callback that will be called when a frontend event occurs.