1/*
2 * Copyright 2019-2024, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5#include "LanguageMenuUtils.h"
6
7#include <algorithm>
8
9#include <string.h>
10
11#include <Application.h>
12#include <Collator.h>
13#include <MenuItem.h>
14#include <Messenger.h>
15
16#include "AppUtils.h"
17#include "HaikuDepotConstants.h"
18#include "LocaleUtils.h"
19#include "Logger.h"
20
21
22static const char* kLanguageIdKey = "id";
23
24
25/*! This method will add the supplied languages to the menu.  It will
26    add first the popular languages, followed by a separator and then
27    other less popular languages.
28*/
29
30/* static */ void
31LanguageMenuUtils::AddLanguagesToMenu(
32	const LanguageModel* languageModel, BMenu* menu)
33{
34	if (languageModel->CountSupportedLanguages() == 0)
35		HDINFO("there are no languages defined");
36
37	// collect all of the languages into a vector so that they can be sorted
38	// and used.
39
40	std::vector<LanguageRef> languages(languageModel->CountSupportedLanguages());
41
42	for (int32 i = 0; i < languageModel->CountSupportedLanguages(); i++) {
43		languages[i] = languageModel->SupportedLanguageAt(i);
44	}
45
46	std::sort(languages.begin(), languages.end(), _IsLanguagePresentationBefore);
47
48	// now add the sorted languages to the menu.
49
50	int32 addedPopular = LanguageMenuUtils::_AddLanguagesToMenu(languages, menu, true);
51
52	if (addedPopular > 0)
53		menu->AddSeparatorItem();
54
55	int32 addedNonPopular = LanguageMenuUtils::_AddLanguagesToMenu(languages, menu, false);
56
57	HDDEBUG("did add %" B_PRId32 " popular languages and %" B_PRId32
58		" non-popular languages to a menu", addedPopular,
59		addedNonPopular);
60}
61
62
63/* static */ void
64LanguageMenuUtils::MarkLanguageInMenu(
65	const BString& languageId, BMenu* menu) {
66	AppUtils::MarkItemWithKeyValueInMenuOrFirst(menu, kLanguageIdKey, languageId);
67}
68
69
70/* static */ void
71LanguageMenuUtils::_AddLanguageToMenu(
72	const BString& id, const BString& name, BMenu* menu)
73{
74	BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED);
75	message->AddString(kLanguageIdKey, id);
76	BMenuItem* item = new BMenuItem(name, message);
77	menu->AddItem(item);
78}
79
80
81/* static */ void
82LanguageMenuUtils::_AddLanguageToMenu(
83	const LanguageRef& language, BMenu* menu)
84{
85	BString name;
86	if (language->GetName(name) != B_OK || name.IsEmpty())
87		name.SetTo("???");
88	LanguageMenuUtils::_AddLanguageToMenu(language->ID(), name, menu);
89}
90
91
92/* static */ int32
93LanguageMenuUtils::_AddLanguagesToMenu(const std::vector<LanguageRef>& languages,
94	BMenu* menu, bool isPopular)
95{
96	int32 count = 0;
97
98	for (uint32 i = 0; i < languages.size(); i++) {
99		const LanguageRef language = languages[i];
100
101		if (languages[i]->IsPopular() == isPopular) {
102			LanguageMenuUtils::_AddLanguageToMenu(languages[i], menu);
103			count++;
104		}
105	}
106
107	return count;
108}
109
110
111/*static*/ int
112LanguageMenuUtils::_LanguagesPresentationCompareFn(const LanguageRef& l1, const LanguageRef& l2)
113{
114	BCollator* collator = LocaleUtils::GetSharedCollator();
115	BString name1;
116	BString name2;
117	int32 result = 0;
118
119	if (l1->GetName(name1) == B_OK && l2->GetName(name2) == B_OK)
120		result = collator->Compare(name1.String(), name2.String());
121	if (0 == result)
122		result = strcmp(l1->ID(), l2->ID());
123
124	return result;
125}
126
127
128/*static*/ bool
129LanguageMenuUtils::_IsLanguagePresentationBefore(const LanguageRef& l1, const LanguageRef& l2)
130{
131	return _LanguagesPresentationCompareFn(l1, l2) < 0;
132}