diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index 8e69fdfa76..70328c207d 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -173,6 +173,7 @@ local applicationSources = AppUtils.cpp DataIOUtils.cpp LanguageMenuUtils.cpp + LocaleUtils.cpp RepositoryUrlUtils.cpp StorageUtils.cpp ToFileUrlProtocolListener.cpp diff --git a/src/apps/haikudepot/model/LanguageModel.cpp b/src/apps/haikudepot/model/LanguageModel.cpp index 8c602bdc49..c74cea639a 100644 --- a/src/apps/haikudepot/model/LanguageModel.cpp +++ b/src/apps/haikudepot/model/LanguageModel.cpp @@ -10,25 +10,23 @@ #include "HaikuDepotConstants.h" #include "Logger.h" +#include "LocaleUtils.h" static int32 LanguagesCompareFn(const LanguageRef& l1, const LanguageRef& l2) { - const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale(); - BCollator collator; - - if (B_OK != locale->GetCollator(&collator)) { - debugger("unable to get the locale's collator"); - } - + BCollator* collator = LocaleUtils::GetSharedCollator(); BString name1; BString name2; + int32 result = 0; if (l1->GetName(name1) == B_OK && l2->GetName(name2) == B_OK) - return collator.Compare(name1.String(), name2.String()); + result = collator->Compare(name1.String(), name2.String()); + if (0 == result) + result = strcmp(l1->Code(), l2->Code()); - return collator.Compare(l1->Code(), l2->Code()); + return result; } diff --git a/src/apps/haikudepot/model/Model.cpp b/src/apps/haikudepot/model/Model.cpp index 7f583f6348..d9758ee0cf 100644 --- a/src/apps/haikudepot/model/Model.cpp +++ b/src/apps/haikudepot/model/Model.cpp @@ -14,15 +14,18 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include "Logger.h" +#include "LocaleUtils.h" #include "StorageUtils.h" #include "RepositoryUrlUtils.h" @@ -103,7 +106,7 @@ public: const CategoryRef& category = categories.ItemAtFast(i); if (category.Get() == NULL) continue; - if (category->Name() == fCategory) + if (category->Code() == fCategory) return true; } return false; @@ -311,44 +314,22 @@ is_develop_package(const PackageInfoRef& package) // #pragma mark - Model +static int32 +PackageCategoryCompareFn(const CategoryRef& c1, const CategoryRef& c2) +{ + BCollator* collator = LocaleUtils::GetSharedCollator(); + int32 result = collator->Compare(c1->Name().String(), + c2->Name().String()); + if (result == 0) + result = c1->Code().Compare(c2->Code()); + return result; +} + + Model::Model() : fDepots(), - - fCategoryAudio(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Audio"), "audio"), true), - fCategoryBusiness(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Business"), "business"), true), - fCategoryDevelopment(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Development"), "development"), true), - fCategoryEducation(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Education"), "education"), true), - fCategoryGames(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Games"), "games"), true), - fCategoryGraphics(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Graphics"), "graphics"), true), - fCategoryInternetAndNetwork(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Internet & Network"), "internetandnetwork"), true), - fCategoryProductivity(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Productivity"), "productivity"), true), - fCategoryScienceAndMathematics(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Science & Mathematics"), "scienceandmathematics"), true), - fCategorySystemAndUtilities(new PackageCategory( - BitmapRef(), - B_TRANSLATE("System & Utilities"), "systemandutilities"), true), - fCategoryVideo(new PackageCategory( - BitmapRef(), - B_TRANSLATE("Video"), "video"), true), - + fCategories(&PackageCategoryCompareFn, NULL), fCategoryFilter(PackageFilterRef(new AnyFilter(), true)), fDepotFilter(""), fSearchTermsFilter(PackageFilterRef(new AnyFilter(), true)), @@ -360,23 +341,6 @@ Model::Model() fShowDevelopPackages(false) { _UpdateIsFeaturedFilter(); - - // Don't forget to add new categories to this list: - fCategories.Add(fCategoryGames); - fCategories.Add(fCategoryBusiness); - fCategories.Add(fCategoryAudio); - fCategories.Add(fCategoryVideo); - fCategories.Add(fCategoryGraphics); - fCategories.Add(fCategoryEducation); - fCategories.Add(fCategoryProductivity); - fCategories.Add(fCategorySystemAndUtilities); - fCategories.Add(fCategoryInternetAndNetwork); - fCategories.Add(fCategoryDevelopment); - fCategories.Add(fCategoryScienceAndMathematics); - // TODO: The server will eventually support an API to - // get the defined categories and their translated names. - // This should then be used instead of hard-coded - // categories and translations in the app. } @@ -1057,6 +1021,18 @@ Model::_NotifyAuthorizationChanged() } +void +Model::_NotifyCategoryListChanged() +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + const ModelListenerRef& listener = fListeners.ItemAtFast(i); + if (listener.Get() != NULL) + listener->CategoryListChanged(); + } +} + + + /*! This method will find the stored 'DepotInfo' that correlates to the supplied 'url' and will invoke the mapper function in order to get a replacement for the 'DepotInfo'. The 'url' is a unique identifier @@ -1117,3 +1093,28 @@ Model::_MaybeLogJsonRpcError(const BMessage &responsePayload, printf("[%s] --> an undefined error has occurred\n", sourceDescription); } } + + +void +Model::AddCategories(const CategoryList& categories) +{ + int32 i; + for (i = 0; i < categories.CountItems(); i++) + _AddCategory(categories.ItemAt(i)); + _NotifyCategoryListChanged(); +} + + +void +Model::_AddCategory(const CategoryRef& category) +{ + int32 i; + for (i = 0; i < fCategories.CountItems(); i++) { + if (fCategories.ItemAt(i)->Code() == category->Code()) { + fCategories.Replace(i, category); + return; + } + } + + fCategories.Add(category); +} diff --git a/src/apps/haikudepot/model/Model.h b/src/apps/haikudepot/model/Model.h index 553f48614a..0e23af33bb 100644 --- a/src/apps/haikudepot/model/Model.h +++ b/src/apps/haikudepot/model/Model.h @@ -37,6 +37,7 @@ public: virtual ~ModelListener(); virtual void AuthorizationChanged() = 0; + virtual void CategoryListChanged() = 0; }; @@ -86,30 +87,7 @@ public: void Clear(); - // Access to global categories - const CategoryRef& CategoryAudio() const - { return fCategoryAudio; } - const CategoryRef& CategoryBusiness() const - { return fCategoryBusiness; } - const CategoryRef& CategoryDevelopment() const - { return fCategoryDevelopment; } - const CategoryRef& CategoryEducation() const - { return fCategoryEducation; } - const CategoryRef& CategoryInternetAndNetwork() const - { return fCategoryInternetAndNetwork; } - const CategoryRef& CategoryGames() const - { return fCategoryGames; } - const CategoryRef& CategoryGraphics() const - { return fCategoryGraphics; } - const CategoryRef& CategoryProductivity() const - { return fCategoryProductivity; } - const CategoryRef& CategoryScienceAndMathematics() const - { return fCategoryScienceAndMathematics; } - const CategoryRef& CategorySystemAndUtilities() const - { return fCategorySystemAndUtilities; } - const CategoryRef& CategoryVideo() const - { return fCategoryVideo; } - + void AddCategories(const CategoryList& categories); const CategoryList& Categories() const { return fCategories; } @@ -176,6 +154,7 @@ public: void LogDepotsWithNoWebAppRepositoryCode() const; private: + void _AddCategory(const CategoryRef& category); status_t _LocalDataPath(const BString leaf, BPath& path) const; @@ -207,25 +186,13 @@ private: bool ignoreAge, time_t maxAge) const; void _NotifyAuthorizationChanged(); + void _NotifyCategoryListChanged(); private: BLocker fLock; DepotList fDepots; - CategoryRef fCategoryAudio; - CategoryRef fCategoryBusiness; - CategoryRef fCategoryDevelopment; - CategoryRef fCategoryEducation; - CategoryRef fCategoryGames; - CategoryRef fCategoryGraphics; - CategoryRef fCategoryInternetAndNetwork; - CategoryRef fCategoryProductivity; - CategoryRef fCategoryScienceAndMathematics; - CategoryRef fCategorySystemAndUtilities; - CategoryRef fCategoryVideo; - // TODO: Dynamic categories retrieved from web-app - CategoryList fCategories; PackageList fInstalledPackages; diff --git a/src/apps/haikudepot/model/PackageInfo.cpp b/src/apps/haikudepot/model/PackageInfo.cpp index e1cade50db..4006bbf27f 100644 --- a/src/apps/haikudepot/model/PackageInfo.cpp +++ b/src/apps/haikudepot/model/PackageInfo.cpp @@ -371,19 +371,16 @@ PublisherInfo::operator!=(const PublisherInfo& other) const PackageCategory::PackageCategory() : BReferenceable(), - fIcon(), - fLabel(), + fCode(), fName() { } -PackageCategory::PackageCategory(const BitmapRef& icon, const BString& label, - const BString& name) +PackageCategory::PackageCategory(const BString& code, const BString& name) : BReferenceable(), - fIcon(icon), - fLabel(label), + fCode(code), fName(name) { } @@ -392,8 +389,7 @@ PackageCategory::PackageCategory(const BitmapRef& icon, const BString& label, PackageCategory::PackageCategory(const PackageCategory& other) : BReferenceable(), - fIcon(other.fIcon), - fLabel(other.fLabel), + fCode(other.fCode), fName(other.fName) { } @@ -402,8 +398,7 @@ PackageCategory::PackageCategory(const PackageCategory& other) PackageCategory& PackageCategory::operator=(const PackageCategory& other) { - fIcon = other.fIcon; - fLabel = other.fLabel; + fCode = other.fCode; fName = other.fName; return *this; } @@ -412,9 +407,7 @@ PackageCategory::operator=(const PackageCategory& other) bool PackageCategory::operator==(const PackageCategory& other) const { - return fIcon == other.fIcon - && fLabel == other.fLabel - && fName == other.fName; + return fCode == other.fCode && fName == other.fName; } diff --git a/src/apps/haikudepot/model/PackageInfo.h b/src/apps/haikudepot/model/PackageInfo.h index c2c8ddb35b..09aabd5a19 100644 --- a/src/apps/haikudepot/model/PackageInfo.h +++ b/src/apps/haikudepot/model/PackageInfo.h @@ -192,8 +192,7 @@ private: class PackageCategory : public BReferenceable { public: PackageCategory(); - PackageCategory(const BitmapRef& icon, - const BString& label, + PackageCategory(const BString& code, const BString& name); PackageCategory(const PackageCategory& other); @@ -201,15 +200,12 @@ public: bool operator==(const PackageCategory& other) const; bool operator!=(const PackageCategory& other) const; - const BitmapRef& Icon() const - { return fIcon; } - const BString& Label() const - { return fLabel; } + const BString& Code() const + { return fCode; } const BString& Name() const { return fName; } private: - BitmapRef fIcon; - BString fLabel; + BString fCode; BString fName; }; diff --git a/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp b/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp index 596a2a2a5c..10bdfe2f9b 100644 --- a/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerPkgDataUpdateProcess.cpp @@ -86,8 +86,8 @@ PackageFillingPkgListener::~PackageFillingPkgListener() // TODO; performance could be improved by not needing the linear search inline int32 -PackageFillingPkgListener::IndexOfCategoryByName( - const BString& name) const +PackageFillingPkgListener::IndexOfCategoryByCode( + const BString& code) const { int32 i; int32 categoryCount = fCategories.CountItems(); @@ -95,7 +95,7 @@ PackageFillingPkgListener::IndexOfCategoryByName( for (i = 0; i < categoryCount; i++) { const CategoryRef categoryRef = fCategories.ItemAtFast(i); - if (categoryRef->Name() == name) + if (categoryRef->Code() == code) return i; } @@ -140,7 +140,7 @@ PackageFillingPkgListener::ConsumePackage(const PackageInfoRef& package, for (i = 0; i < countPkgCategories; i++) { BString* categoryCode = pkg->PkgCategoriesItemAt(i)->Code(); - int categoryIndex = IndexOfCategoryByName(*(categoryCode)); + int categoryIndex = IndexOfCategoryByCode(*(categoryCode)); if (categoryIndex == -1) { printf("unable to find the category for [%s]\n", diff --git a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp index 622fcfb2a5..97acc8928a 100644 --- a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.cpp @@ -107,8 +107,12 @@ ServerReferenceDataUpdateProcess::ProcessLocalData() status_t ServerReferenceDataUpdateProcess::_ProcessData(DumpExportReference* data) { - // more to come here later... - return _ProcessNaturalLanguages(data); + status_t result = B_OK; + if (result == B_OK) + result = _ProcessNaturalLanguages(data); + if (result == B_OK) + result = _ProcessPkgCategories(data); + return result; } @@ -124,10 +128,13 @@ ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages( for (int32 i = 0; i < data->CountNaturalLanguages(); i++) { DumpExportReferenceNaturalLanguage* naturalLanguage = data->NaturalLanguagesItemAt(i); - result.Add(LanguageRef(new Language( - *(naturalLanguage->Code()), - *(naturalLanguage->Name()), - naturalLanguage->IsPopular()))); + result.Add(LanguageRef( + new Language( + *(naturalLanguage->Code()), + *(naturalLanguage->Name()), + naturalLanguage->IsPopular() + ), + true)); } { @@ -142,6 +149,35 @@ ServerReferenceDataUpdateProcess::_ProcessNaturalLanguages( } +status_t +ServerReferenceDataUpdateProcess::_ProcessPkgCategories( + DumpExportReference* data) +{ + printf("[%s] will populate %" B_PRId32 " pkg categories\n", + Name(), data->CountPkgCategories()); + + CategoryList result; + + for (int32 i = 0; i < data->CountPkgCategories(); i++) { + DumpExportReferencePkgCategory* pkgCategory = + data->PkgCategoriesItemAt(i); + result.Add(CategoryRef( + new PackageCategory( + *(pkgCategory->Code()), + *(pkgCategory->Name()) + ), + true)); + } + + { + AutoLocker locker(fModel->Lock()); + fModel->AddCategories(result); + } + + return B_OK; +} + + status_t ServerReferenceDataUpdateProcess::GetStandardMetaDataPath(BPath& path) const { diff --git a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h index fe051b6efa..25ff2c1101 100644 --- a/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h +++ b/src/apps/haikudepot/server/ServerReferenceDataUpdateProcess.h @@ -46,6 +46,8 @@ private: status_t _ProcessData(DumpExportReference* data); status_t _ProcessNaturalLanguages( DumpExportReference* data); + status_t _ProcessPkgCategories( + DumpExportReference* data); private: Model* fModel; diff --git a/src/apps/haikudepot/ui/FilterView.cpp b/src/apps/haikudepot/ui/FilterView.cpp index 807b030a84..cccf70185d 100644 --- a/src/apps/haikudepot/ui/FilterView.cpp +++ b/src/apps/haikudepot/ui/FilterView.cpp @@ -1,5 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . + * Copyright 2019, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -8,6 +9,7 @@ #include #include +#include #include #include #include @@ -31,8 +33,8 @@ add_categories_to_menu(const CategoryList& categories, BMenu* menu) for (int i = 0; i < categories.CountItems(); i++) { const CategoryRef& category = categories.ItemAtFast(i); BMessage* message = new BMessage(MSG_CATEGORY_SELECTED); - message->AddString("name", category->Name()); - BMenuItem* item = new BMenuItem(category->Label(), message); + message->AddString("code", category->Code()); + BMenuItem* item = new BMenuItem(category->Name(), message); menu->AddItem(item); } } @@ -88,7 +90,6 @@ FilterView::AttachedToWindow() { fShowField->Menu()->SetTargetForItems(Window()); fSearchTermsText->SetTarget(this); - fSearchTermsText->MakeFocus(); } @@ -113,7 +114,7 @@ FilterView::MessageReceived(BMessage* message) void -FilterView::AdoptModel(const Model& model) +FilterView::AdoptModel(Model& model) { // Adopt categories BMenu* showMenu = fShowField->Menu(); @@ -122,25 +123,47 @@ FilterView::AdoptModel(const Model& model) showMenu->AddItem(new BMenuItem(B_TRANSLATE("All categories"), new BMessage(MSG_CATEGORY_SELECTED))); - showMenu->AddItem(new BSeparatorItem()); + AutoLocker locker(model.Lock()); + CategoryList categories = model.Categories(); - add_categories_to_menu(model.Categories(), showMenu); - - bool foundSelectedCategory = false; - for (int32 i = 0; i < showMenu->CountItems(); i++) { - BMenuItem* item = showMenu->ItemAt(i); - BMessage* message = item->Message(); - if (message == NULL) - continue; - BString category; - if (message->FindString("name", &category) == B_OK - && model.Category() == category) { - item->SetMarked(true); - foundSelectedCategory = true; - break; - } + if (!categories.IsEmpty()) { + showMenu->AddItem(new BSeparatorItem()); + add_categories_to_menu(categories, showMenu); } - if (!foundSelectedCategory) + + showMenu->SetEnabled(!categories.IsEmpty()); + + if (!_SelectCategoryCode(showMenu, model.Category())) showMenu->ItemAt(0)->SetMarked(true); } + +/*! Tries to mark the menu item that corresponds to the supplied + category code. If the supplied code was found and the item marked + then the method will return true. +*/ + +/*static*/ bool +FilterView::_SelectCategoryCode(BMenu* menu, const BString& code) +{ + for (int32 i = 0; i < menu->CountItems(); i++) { + BMenuItem* item = menu->ItemAt(i); + if (_MatchesCategoryCode(item, code)) { + item->SetMarked(true); + return true; + } + } + return false; +} + + +/*static*/ bool +FilterView::_MatchesCategoryCode(BMenuItem* item, const BString& code) +{ + BMessage* message = item->Message(); + if (message == NULL) + return false; + BString itemCode; + message->FindString("code", &itemCode); + return itemCode == code; +} \ No newline at end of file diff --git a/src/apps/haikudepot/ui/FilterView.h b/src/apps/haikudepot/ui/FilterView.h index 6740766785..795c095a60 100644 --- a/src/apps/haikudepot/ui/FilterView.h +++ b/src/apps/haikudepot/ui/FilterView.h @@ -1,5 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . + * Copyright 2019, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef FILTER_VIEW_H @@ -9,7 +10,9 @@ class BCheckBox; +class BMenu; class BMenuField; +class BMenuItem; class BTextControl; class Model; @@ -29,7 +32,13 @@ public: virtual void AttachedToWindow(); virtual void MessageReceived(BMessage* message); - void AdoptModel(const Model& model); + void AdoptModel(Model& model); + +private: + static bool _SelectCategoryCode(BMenu* menu, + const BString& code); + static bool _MatchesCategoryCode(BMenuItem* item, + const BString& code); private: BMenuField* fShowField; diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index fb26b69ba0..e0a32ec567 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -3,7 +3,7 @@ * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent, rene@gollent.com. * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2016-2018, Andrew Lindesay . + * Copyright 2016-2019, Andrew Lindesay . * Copyright 2017, Julian Harnath . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -63,6 +63,7 @@ enum { MSG_LOG_IN = 'lgin', MSG_LOG_OUT = 'lgot', MSG_AUTHORIZATION_CHANGED = 'athc', + MSG_CATEGORIES_LIST_CHANGED = 'clic', MSG_PACKAGE_CHANGED = 'pchd', MSG_WORK_STATUS_CHANGE = 'wsch', MSG_WORK_STATUS_CLEAR = 'wscl', @@ -95,9 +96,9 @@ struct RefreshWorkerParameters { }; -class MessageModelListener : public ModelListener { +class MainWindowModelListener : public ModelListener { public: - MessageModelListener(const BMessenger& messenger) + MainWindowModelListener(const BMessenger& messenger) : fMessenger(messenger) { @@ -109,6 +110,12 @@ public: fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); } + virtual void CategoryListChanged() + { + if (fMessenger.IsValid()) + fMessenger.SendMessage(MSG_CATEGORIES_LIST_CHANGED); + } + private: BMessenger fMessenger; }; @@ -123,7 +130,7 @@ MainWindow::MainWindow(const BMessage& settings) fUserMenu(NULL), fLogInItem(NULL), fLogOutItem(NULL), - fModelListener(new MessageModelListener(BMessenger(this)), true), + fModelListener(new MainWindowModelListener(BMessenger(this)), true), fBulkLoadProcessCoordinator(NULL), fSinglePackageMode(false) { @@ -221,7 +228,7 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package) fUserMenu(NULL), fLogInItem(NULL), fLogOutItem(NULL), - fModelListener(new MessageModelListener(BMessenger(this)), true), + fModelListener(new MainWindowModelListener(BMessenger(this)), true), fBulkLoadProcessCoordinator(NULL), fSinglePackageMode(true) { @@ -331,6 +338,10 @@ MainWindow::MessageReceived(BMessage* message) _UpdateAuthorization(); break; + case MSG_CATEGORIES_LIST_CHANGED: + fFilterView->AdoptModel(fModel); + break; + case MSG_SHOW_FEATURED_PACKAGES: // check to see if we aren't already on the current tab if (fListTabs->Selection() == @@ -421,12 +432,12 @@ MainWindow::MessageReceived(BMessage* message) case MSG_CATEGORY_SELECTED: { - BString name; - if (message->FindString("name", &name) != B_OK) - name = ""; + BString code; + if (message->FindString("code", &code) != B_OK) + code = ""; { BAutolock locker(fModel.Lock()); - fModel.SetCategory(name); + fModel.SetCategory(code); } _AdoptModel(); break; diff --git a/src/apps/haikudepot/util/LocaleUtils.cpp b/src/apps/haikudepot/util/LocaleUtils.cpp new file mode 100644 index 0000000000..d354aa7929 --- /dev/null +++ b/src/apps/haikudepot/util/LocaleUtils.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2019, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#include "LocaleUtils.h" + + +#include +#include +#include + + +BCollator* LocaleUtils::sSharedCollator = NULL; + + +/*static*/ BCollator* +LocaleUtils::GetSharedCollator() +{ + if (sSharedCollator == NULL) { + GetCollator(sSharedCollator); + } + + return sSharedCollator; +} + + +/*static*/ void +LocaleUtils::GetCollator(BCollator* collator) +{ + const BLocale* locale = BLocaleRoster::Default()->GetDefaultLocale(); + + if (B_OK != locale->GetCollator(collator)) { + debugger("unable to get the locale's collator"); + exit(EXIT_FAILURE); + } +} \ No newline at end of file diff --git a/src/apps/haikudepot/util/LocaleUtils.h b/src/apps/haikudepot/util/LocaleUtils.h new file mode 100644 index 0000000000..9887012239 --- /dev/null +++ b/src/apps/haikudepot/util/LocaleUtils.h @@ -0,0 +1,25 @@ +/* + * Copyright 2019, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef LOCALE_UTILS_H +#define LOCALE_UTILS_H + + +class BCollator; + + +class LocaleUtils { + +public: + static BCollator* GetSharedCollator(); + +private: + static void GetCollator(BCollator* collator); + +private: + static BCollator* sSharedCollator; +}; + + +#endif // LOCALE_UTILS_H