瀏覽代碼

UI: Update order of profiles and scene collections in their menus

The old method to update the profile menu iterated over the directory
entries of the profile directory in the order provided by the operating
system.

The system calls used for this explicitly state that the order of items
is "undefined" but seems to have followed a case-insensitive
alphabetical order on Windows, an order which users have come to expect.

The new code uses a std::map to store discovered profiles and scene
collections, which is ordered by key and with std::string used for keys
this means a lexicographical sorting of keys which is case-sensitive.

To restore the old behavior, profiles and scene collections need to be
added to their respective menus sorted by case-insensitive order, which
has to be done manually before adding the items.
PatTheMav 1 年之前
父節點
當前提交
918fe6171d
共有 2 個文件被更改,包括 85 次插入18 次删除
  1. 41 8
      UI/window-basic-main-profiles.cpp
  2. 44 10
      UI/window-basic-main-scene-collections.cpp

+ 41 - 8
UI/window-basic-main-profiles.cpp

@@ -43,6 +43,30 @@ extern void DuplicateCurrentCookieProfile(ConfigFile &config);
 extern void CheckExistingCookieId();
 extern void DeleteCookies();
 
+// MARK: - Anonymous Namespace
+namespace {
+QList<QString> sortedProfiles{};
+
+void updateSortedProfiles(const OBSProfileCache &profiles)
+{
+	const QLocale locale = QLocale::system();
+	QList<QString> newList{};
+
+	for (auto [profileName, _] : profiles) {
+		QString entry = QString::fromStdString(profileName);
+		newList.append(entry);
+	}
+
+	std::sort(newList.begin(), newList.end(), [&locale](const QString &lhs, const QString &rhs) -> bool {
+		int result = QString::localeAwareCompare(locale.toLower(lhs), locale.toLower(rhs));
+
+		return (result < 0);
+	});
+
+	sortedProfiles.swap(newList);
+}
+} // namespace
+
 // MARK: - Main Profile Management Functions
 
 void OBSBasic::SetupNewProfile(const std::string &profileName, bool useWizard)
@@ -277,18 +301,27 @@ void OBSBasic::RefreshProfiles(bool refreshCache)
 	if (refreshCache) {
 		RefreshProfileCache();
 	}
+	updateSortedProfiles(profiles);
 
 	size_t numAddedProfiles = 0;
-	for (auto &[profileName, profile] : profiles) {
-		QAction *action = new QAction(QString().fromStdString(profileName), this);
-		action->setProperty("file_name", QString().fromStdString(profile.directoryName));
-		connect(action, &QAction::triggered, this, &OBSBasic::ChangeProfile);
-		action->setCheckable(true);
-		action->setChecked(profileName == currentProfileName);
+	for (auto &name : sortedProfiles) {
+		const std::string profileName = name.toStdString();
+		try {
+			OBSProfile &profile = profiles.at(profileName);
 
-		ui->profileMenu->addAction(action);
+			QAction *action = new QAction(QString().fromStdString(profileName), this);
+			action->setProperty("file_name", QString().fromStdString(profile.directoryName));
+			connect(action, &QAction::triggered, this, &OBSBasic::ChangeProfile);
+			action->setCheckable(true);
+			action->setChecked(profileName == currentProfileName);
 
-		numAddedProfiles += 1;
+			ui->profileMenu->addAction(action);
+
+			numAddedProfiles += 1;
+		} catch (const std::out_of_range &error) {
+			blog(LOG_ERROR, "No profile with name %s found in profile cache.\n%s", profileName.c_str(),
+			     error.what());
+		}
 	}
 
 	ui->actionRemoveProfile->setEnabled(numAddedProfiles > 1);

+ 44 - 10
UI/window-basic-main-scene-collections.cpp

@@ -34,6 +34,30 @@
 
 constexpr std::string_view OBSSceneCollectionPath = "/obs-studio/basic/scenes/";
 
+// MARK: - Anonymous Namespace
+namespace {
+QList<QString> sortedSceneCollections{};
+
+void updateSortedSceneCollections(const OBSSceneCollectionCache &collections)
+{
+	const QLocale locale = QLocale::system();
+	QList<QString> newList{};
+
+	for (auto [collectionName, _] : collections) {
+		QString entry = QString::fromStdString(collectionName);
+		newList.append(entry);
+	}
+
+	std::sort(newList.begin(), newList.end(), [&locale](const QString &lhs, const QString &rhs) -> bool {
+		int result = QString::localeAwareCompare(locale.toLower(lhs), locale.toLower(rhs));
+
+		return (result < 0);
+	});
+
+	sortedSceneCollections.swap(newList);
+}
+} // namespace
+
 // MARK: - Main Scene Collection Management Functions
 
 void OBSBasic::SetupNewSceneCollection(const std::string &collectionName)
@@ -280,17 +304,27 @@ void OBSBasic::RefreshSceneCollections(bool refreshCache)
 		RefreshSceneCollectionCache();
 	}
 
-	size_t numAddedCollections = 0;
-	for (auto &[collectionName, collection] : collections) {
-		QAction *action = new QAction(QString().fromStdString(collectionName), this);
-		action->setProperty("file_name", QString().fromStdString(collection.fileName));
-		connect(action, &QAction::triggered, this, &OBSBasic::ChangeSceneCollection);
-		action->setCheckable(true);
-		action->setChecked(collectionName == currentCollectionName);
-
-		ui->sceneCollectionMenu->addAction(action);
+	updateSortedSceneCollections(collections);
 
-		numAddedCollections += 1;
+	size_t numAddedCollections = 0;
+	for (auto &name : sortedSceneCollections) {
+		const std::string collectionName = name.toStdString();
+		try {
+			OBSSceneCollection &collection = collections.at(collectionName);
+
+			QAction *action = new QAction(QString().fromStdString(collectionName), this);
+			action->setProperty("file_name", QString().fromStdString(collection.fileName));
+			connect(action, &QAction::triggered, this, &OBSBasic::ChangeSceneCollection);
+			action->setCheckable(true);
+			action->setChecked(collectionName == currentCollectionName);
+
+			ui->sceneCollectionMenu->addAction(action);
+
+			numAddedCollections += 1;
+		} catch (const std::out_of_range &error) {
+			blog(LOG_ERROR, "No scene collection with name %s found in scene collection cache.\n%s",
+			     collectionName.c_str(), error.what());
+		}
 	}
 
 	ui->actionRemoveSceneCollection->setEnabled(numAddedCollections > 1);