Fix relying on order of static object destruction in Locale Kit.
* use only a single static object (MutableLocaleRoster) instead of two, which avoids any problems if the order of static object destruction would destroy RosterData before MutableLocaleRoster * rename BPrivate::RosterData to BPrivate::LocaleRosterData and move it into a header and implementation file of its own This should hopefully fix problems encountered with a clang-compiled Locale Kit.
This commit is contained in:
parent
a22e8c6fe2
commit
52cdfde04b
@ -21,14 +21,19 @@ class BMessage;
|
||||
class BTimeZone;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
class LocaleRosterData;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
B_LOCALE_CHANGED = '_LCC',
|
||||
};
|
||||
|
||||
|
||||
class BLocaleRoster {
|
||||
|
||||
public:
|
||||
BLocaleRoster();
|
||||
~BLocaleRoster();
|
||||
|
||||
static BLocaleRoster* Default();
|
||||
@ -70,6 +75,8 @@ public:
|
||||
// Get the catalog for the calling image
|
||||
// (that needs to link with liblocalestub.a)
|
||||
|
||||
const BLocale* GetDefaultLocale() const;
|
||||
|
||||
bool IsFilesystemTranslationPreferred() const;
|
||||
|
||||
status_t GetLocalizedFileName(BString& localizedFileName,
|
||||
@ -83,6 +90,12 @@ public:
|
||||
static const char* kEmbeddedCatAttr;
|
||||
static int32 kEmbeddedCatResId;
|
||||
|
||||
protected:
|
||||
BLocaleRoster();
|
||||
|
||||
protected:
|
||||
BPrivate::LocaleRosterData* fData;
|
||||
|
||||
private:
|
||||
static BCatalog* _GetCatalog(BCatalog* catalog,
|
||||
vint32* catalogInitStatus);
|
||||
@ -90,6 +103,7 @@ private:
|
||||
status_t _PrepareCatalogEntry(const entry_ref& ref,
|
||||
BString& signature, BString& context,
|
||||
BString& string, bool traverse);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
142
headers/private/locale/LocaleRosterData.h
Normal file
142
headers/private/locale/LocaleRosterData.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2010-2012, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef _LOCALE_ROSTER_DATA_H_
|
||||
#define _LOCALE_ROSTER_DATA_H_
|
||||
|
||||
|
||||
#include <Collator.h>
|
||||
#include <FormattingConventions.h>
|
||||
#include <image.h>
|
||||
#include <Language.h>
|
||||
#include <List.h>
|
||||
#include <Locale.h>
|
||||
#include <Locker.h>
|
||||
#include <Message.h>
|
||||
#include <Resources.h>
|
||||
#include <TimeZone.h>
|
||||
|
||||
|
||||
class BCatalogData;
|
||||
class BLocale;
|
||||
|
||||
struct entry_ref;
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
/*
|
||||
* Struct containing the actual locale data.
|
||||
*/
|
||||
struct LocaleRosterData {
|
||||
BLocker fLock;
|
||||
BList fCatalogAddOnInfos;
|
||||
BMessage fPreferredLanguages;
|
||||
|
||||
BLocale fDefaultLocale;
|
||||
BTimeZone fDefaultTimeZone;
|
||||
|
||||
bool fIsFilesystemTranslationPreferred;
|
||||
|
||||
LocaleRosterData(const BLanguage& language,
|
||||
const BFormattingConventions& conventions);
|
||||
~LocaleRosterData();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t Refresh();
|
||||
|
||||
static int CompareInfos(const void* left,
|
||||
const void* right);
|
||||
|
||||
status_t GetResources(BResources** resources);
|
||||
|
||||
status_t SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& convetions);
|
||||
status_t SetDefaultTimeZone(const BTimeZone& zone);
|
||||
status_t SetPreferredLanguages(const BMessage* msg);
|
||||
status_t SetFilesystemTranslationPreferred(
|
||||
bool preferred);
|
||||
private:
|
||||
status_t _Initialize();
|
||||
|
||||
status_t _InitializeCatalogAddOns();
|
||||
void _CleanupCatalogAddOns();
|
||||
|
||||
status_t _LoadLocaleSettings();
|
||||
status_t _SaveLocaleSettings();
|
||||
|
||||
status_t _LoadTimeSettings();
|
||||
status_t _SaveTimeSettings();
|
||||
|
||||
status_t _SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& conventions);
|
||||
status_t _SetDefaultTimeZone(const BTimeZone& zone);
|
||||
status_t _SetPreferredLanguages(const BMessage* msg);
|
||||
void _SetFilesystemTranslationPreferred(
|
||||
bool preferred);
|
||||
|
||||
status_t _AddDefaultFormattingConventionsToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddDefaultTimeZoneToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddPreferredLanguagesToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddFilesystemTranslationPreferenceToMessage(
|
||||
BMessage* message) const;
|
||||
|
||||
private:
|
||||
status_t fInitStatus;
|
||||
|
||||
bool fAreResourcesLoaded;
|
||||
BResources fResources;
|
||||
};
|
||||
|
||||
|
||||
typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner,
|
||||
const char* language, uint32 fingerprint);
|
||||
|
||||
typedef BCatalogData* (*CreateCatalogFunc)(const char* name,
|
||||
const char* language);
|
||||
|
||||
typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)(
|
||||
entry_ref* appOrAddOnRef);
|
||||
|
||||
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
|
||||
const char*, int32);
|
||||
|
||||
|
||||
/*
|
||||
* info about a single catalog-add-on (representing a catalog type):
|
||||
*/
|
||||
struct CatalogAddOnInfo {
|
||||
InstantiateCatalogFunc fInstantiateFunc;
|
||||
CreateCatalogFunc fCreateFunc;
|
||||
GetAvailableLanguagesFunc fLanguagesFunc;
|
||||
|
||||
BString fName;
|
||||
BString fPath;
|
||||
image_id fAddOnImage;
|
||||
uint8 fPriority;
|
||||
BList fLoadedCatalogs;
|
||||
bool fIsEmbedded;
|
||||
// an embedded add-on actually isn't an
|
||||
// add-on, it is included as part of the
|
||||
// library.
|
||||
// The DefaultCatalog is such a beast!
|
||||
|
||||
CatalogAddOnInfo(const BString& name,
|
||||
const BString& path, uint8 priority);
|
||||
~CatalogAddOnInfo();
|
||||
|
||||
bool MakeSureItsLoaded();
|
||||
void UnloadIfPossible();
|
||||
};
|
||||
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
|
||||
#endif // _LOCALE_ROSTER_DATA_H_
|
@ -60,113 +60,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
typedef BCatalogData* (*InstantiateCatalogFunc)(const entry_ref& catalogOwner,
|
||||
const char* language, uint32 fingerprint);
|
||||
|
||||
typedef BCatalogData* (*CreateCatalogFunc)(const char* name,
|
||||
const char* language);
|
||||
|
||||
typedef BCatalogData* (*InstantiateEmbeddedCatalogFunc)(
|
||||
entry_ref* appOrAddOnRef);
|
||||
|
||||
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
|
||||
const char*, int32);
|
||||
|
||||
/*
|
||||
* info about a single catalog-add-on (representing a catalog type):
|
||||
*/
|
||||
struct CatalogAddOnInfo {
|
||||
InstantiateCatalogFunc fInstantiateFunc;
|
||||
CreateCatalogFunc fCreateFunc;
|
||||
GetAvailableLanguagesFunc fLanguagesFunc;
|
||||
|
||||
BString fName;
|
||||
BString fPath;
|
||||
image_id fAddOnImage;
|
||||
uint8 fPriority;
|
||||
BList fLoadedCatalogs;
|
||||
bool fIsEmbedded;
|
||||
// an embedded add-on actually isn't an
|
||||
// add-on, it is included as part of the
|
||||
// library.
|
||||
// The DefaultCatalog is such a beast!
|
||||
|
||||
CatalogAddOnInfo(const BString& name,
|
||||
const BString& path, uint8 priority);
|
||||
~CatalogAddOnInfo();
|
||||
|
||||
bool MakeSureItsLoaded();
|
||||
void UnloadIfPossible();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The global data that is shared between all roster-objects of a process.
|
||||
*/
|
||||
struct RosterData {
|
||||
BLocker fLock;
|
||||
BList fCatalogAddOnInfos;
|
||||
BMessage fPreferredLanguages;
|
||||
|
||||
BLocale fDefaultLocale;
|
||||
BTimeZone fDefaultTimeZone;
|
||||
|
||||
bool fIsFilesystemTranslationPreferred;
|
||||
|
||||
bool fAreResourcesLoaded;
|
||||
BResources fResources;
|
||||
|
||||
status_t fInitStatus;
|
||||
|
||||
RosterData(const BLanguage& language,
|
||||
const BFormattingConventions& conventions);
|
||||
~RosterData();
|
||||
|
||||
static RosterData* Default();
|
||||
|
||||
status_t InitCheck() const;
|
||||
|
||||
status_t Refresh();
|
||||
|
||||
static int CompareInfos(const void* left,
|
||||
const void* right);
|
||||
|
||||
status_t SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& convetions);
|
||||
status_t SetDefaultTimeZone(const BTimeZone& zone);
|
||||
status_t SetPreferredLanguages(const BMessage* msg);
|
||||
status_t SetFilesystemTranslationPreferred(
|
||||
bool preferred);
|
||||
private:
|
||||
status_t _Initialize();
|
||||
|
||||
status_t _InitializeCatalogAddOns();
|
||||
void _CleanupCatalogAddOns();
|
||||
|
||||
status_t _LoadLocaleSettings();
|
||||
status_t _SaveLocaleSettings();
|
||||
|
||||
status_t _LoadTimeSettings();
|
||||
status_t _SaveTimeSettings();
|
||||
|
||||
status_t _SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& conventions);
|
||||
status_t _SetDefaultTimeZone(const BTimeZone& zone);
|
||||
status_t _SetPreferredLanguages(const BMessage* msg);
|
||||
void _SetFilesystemTranslationPreferred(
|
||||
bool preferred);
|
||||
|
||||
status_t _AddDefaultFormattingConventionsToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddDefaultTimeZoneToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddPreferredLanguagesToMessage(
|
||||
BMessage* message) const;
|
||||
status_t _AddFilesystemTranslationPreferenceToMessage(
|
||||
BMessage* message) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace BPrivate
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ local sources =
|
||||
Language.cpp
|
||||
Locale.cpp
|
||||
LocaleRoster.cpp
|
||||
LocaleRosterData.cpp
|
||||
MutableLocaleRoster.cpp
|
||||
TimeZone.cpp
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <LanguagePrivate.h>
|
||||
#include <Locale.h>
|
||||
#include <LocaleRoster.h>
|
||||
#include <MutableLocaleRoster.h>
|
||||
#include <TimeZone.h>
|
||||
|
||||
#include <ICUWrapper.h>
|
||||
@ -59,7 +58,7 @@ BLocale::BLocale(const BLocale& other)
|
||||
/*static*/ const BLocale*
|
||||
BLocale::Default()
|
||||
{
|
||||
return &BPrivate::RosterData::Default()->fDefaultLocale;
|
||||
return BLocaleRoster::Default()->GetDefaultLocale();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2010, Haiku. All rights reserved.
|
||||
* Copyright 2003-2012, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -10,27 +10,23 @@
|
||||
|
||||
#include <LocaleRoster.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <set>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Catalog.h>
|
||||
#include <Collator.h>
|
||||
#include <DefaultCatalog.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FormattingConventions.h>
|
||||
#include <fs_attr.h>
|
||||
#include <IconUtils.h>
|
||||
#include <Language.h>
|
||||
#include <Locale.h>
|
||||
#include <LocaleRosterData.h>
|
||||
#include <MutableLocaleRoster.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <String.h>
|
||||
#include <TimeZone.h>
|
||||
@ -45,7 +41,6 @@
|
||||
|
||||
using BPrivate::CatalogAddOnInfo;
|
||||
using BPrivate::MutableLocaleRoster;
|
||||
using BPrivate::RosterData;
|
||||
|
||||
|
||||
/*
|
||||
@ -67,26 +62,6 @@ int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
|
||||
// this may live in an app- or add-on-file
|
||||
|
||||
|
||||
static status_t
|
||||
load_resources_if_needed(RosterData* rosterData)
|
||||
{
|
||||
if (rosterData->fAreResourcesLoaded)
|
||||
return B_OK;
|
||||
|
||||
status_t result = rosterData->fResources.SetToImage(
|
||||
(const void*)&BLocaleRoster::Default);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = rosterData->fResources.PreloadResourceType();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
rosterData->fAreResourcesLoaded = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
country_code_for_language(const BLanguage& language)
|
||||
{
|
||||
@ -149,12 +124,16 @@ country_code_for_language(const BLanguage& language)
|
||||
|
||||
|
||||
BLocaleRoster::BLocaleRoster()
|
||||
:
|
||||
fData(new(std::nothrow) BPrivate::LocaleRosterData(BLanguage("en_US"),
|
||||
BFormattingConventions("en_US")))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BLocaleRoster::~BLocaleRoster()
|
||||
{
|
||||
delete fData;
|
||||
}
|
||||
|
||||
|
||||
@ -168,7 +147,7 @@ BLocaleRoster::Default()
|
||||
status_t
|
||||
BLocaleRoster::Refresh()
|
||||
{
|
||||
return RosterData::Default()->Refresh();
|
||||
return fData->Refresh();
|
||||
}
|
||||
|
||||
|
||||
@ -178,17 +157,22 @@ BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const
|
||||
if (!timezone)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
*timezone = rosterData->fDefaultTimeZone;
|
||||
*timezone = fData->fDefaultTimeZone;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
const BLocale*
|
||||
BLocaleRoster::GetDefaultLocale() const
|
||||
{
|
||||
return &fData->fDefaultLocale;
|
||||
}
|
||||
|
||||
status_t
|
||||
BLocaleRoster::GetLanguage(const char* languageCode,
|
||||
BLanguage** _language) const
|
||||
@ -211,12 +195,11 @@ BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
|
||||
if (!languages)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
*languages = rosterData->fPreferredLanguages;
|
||||
*languages = fData->fPreferredLanguages;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -367,12 +350,12 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
|
||||
if (countryCode == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status_t status = load_resources_if_needed(rosterData);
|
||||
BResources* resources;
|
||||
status_t status = fData->GetResources(&resources);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
@ -389,8 +372,8 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
|
||||
normalizedCode[2] = '\0';
|
||||
|
||||
size_t size;
|
||||
const void* buffer = rosterData->fResources.LoadResource(
|
||||
B_VECTOR_ICON_TYPE, normalizedCode, &size);
|
||||
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
|
||||
normalizedCode, &size);
|
||||
if (buffer == NULL || size == 0)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
@ -407,12 +390,12 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
|
||||
|| languageCode[1] == '\0')
|
||||
return B_BAD_VALUE;
|
||||
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status_t status = load_resources_if_needed(rosterData);
|
||||
BResources* resources;
|
||||
status_t status = fData->GetResources(&resources);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
@ -424,8 +407,8 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
|
||||
normalizedCode[2] = '\0';
|
||||
|
||||
size_t size;
|
||||
const void* buffer = rosterData->fResources.LoadResource(
|
||||
B_VECTOR_ICON_TYPE, normalizedCode, &size);
|
||||
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
|
||||
normalizedCode, &size);
|
||||
if (buffer != NULL && size != 0) {
|
||||
return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer),
|
||||
size, flagIcon);
|
||||
@ -450,15 +433,14 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
|
||||
if (languageList == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
int32 count = rosterData->fCatalogAddOnInfos.CountItems();
|
||||
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
CatalogAddOnInfo* info
|
||||
= (CatalogAddOnInfo*)rosterData->fCatalogAddOnInfos.ItemAt(i);
|
||||
= (CatalogAddOnInfo*)fData->fCatalogAddOnInfos.ItemAt(i);
|
||||
|
||||
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
|
||||
continue;
|
||||
@ -474,12 +456,11 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
|
||||
bool
|
||||
BLocaleRoster::IsFilesystemTranslationPreferred() const
|
||||
{
|
||||
RosterData* rosterData = RosterData::Default();
|
||||
BAutolock lock(rosterData->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
return rosterData->fIsFilesystemTranslationPreferred;
|
||||
return fData->fIsFilesystemTranslationPreferred;
|
||||
}
|
||||
|
||||
|
||||
|
682
src/kits/locale/LocaleRosterData.cpp
Normal file
682
src/kits/locale/LocaleRosterData.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* Copyright 2003-2012, Haiku. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
* Oliver Tappe, zooey@hirschkaefer.de
|
||||
*/
|
||||
|
||||
|
||||
#include <LocaleRosterData.h>
|
||||
|
||||
#include <Autolock.h>
|
||||
#include <Catalog.h>
|
||||
#include <Collator.h>
|
||||
#include <Debug.h>
|
||||
#include <DefaultCatalog.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <FormattingConventions.h>
|
||||
#include <Language.h>
|
||||
#include <Locale.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <String.h>
|
||||
#include <TimeZone.h>
|
||||
|
||||
// ICU includes
|
||||
#include <unicode/locid.h>
|
||||
#include <unicode/timezone.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
// #pragma mark - CatalogAddOnInfo
|
||||
|
||||
|
||||
CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path,
|
||||
uint8 priority)
|
||||
:
|
||||
fInstantiateFunc(NULL),
|
||||
fCreateFunc(NULL),
|
||||
fLanguagesFunc(NULL),
|
||||
fName(name),
|
||||
fPath(path),
|
||||
fAddOnImage(B_NO_INIT),
|
||||
fPriority(priority),
|
||||
fIsEmbedded(path.Length()==0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CatalogAddOnInfo::~CatalogAddOnInfo()
|
||||
{
|
||||
int32 count = fLoadedCatalogs.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
BCatalogData* cat
|
||||
= static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i));
|
||||
delete cat;
|
||||
}
|
||||
fLoadedCatalogs.MakeEmpty();
|
||||
UnloadIfPossible();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CatalogAddOnInfo::MakeSureItsLoaded()
|
||||
{
|
||||
if (!fIsEmbedded && fAddOnImage < B_OK) {
|
||||
// add-on has not been loaded yet, so we try to load it:
|
||||
BString fullAddOnPath(fPath);
|
||||
fullAddOnPath << "/" << fName;
|
||||
fAddOnImage = load_add_on(fullAddOnPath.String());
|
||||
if (fAddOnImage >= B_OK) {
|
||||
get_image_symbol(fAddOnImage, "instantiate_catalog",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc);
|
||||
get_image_symbol(fAddOnImage, "create_catalog",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc);
|
||||
get_image_symbol(fAddOnImage, "get_available_languages",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc);
|
||||
} else
|
||||
return false;
|
||||
} else if (fIsEmbedded) {
|
||||
// The built-in catalog still has to provide this function
|
||||
fLanguagesFunc = default_catalog_get_available_languages;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CatalogAddOnInfo::UnloadIfPossible()
|
||||
{
|
||||
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
|
||||
unload_add_on(fAddOnImage);
|
||||
fAddOnImage = B_NO_INIT;
|
||||
fInstantiateFunc = NULL;
|
||||
fCreateFunc = NULL;
|
||||
fLanguagesFunc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - LocaleRosterData
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
static const char* kPriorityAttr = "ADDON:priority";
|
||||
|
||||
static const char* kLanguageField = "language";
|
||||
static const char* kTimezoneField = "timezone";
|
||||
static const char* kTranslateFilesystemField = "filesys";
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
LocaleRosterData::LocaleRosterData(const BLanguage& language,
|
||||
const BFormattingConventions& conventions)
|
||||
:
|
||||
fLock("LocaleRosterData"),
|
||||
fDefaultLocale(&language, &conventions),
|
||||
fIsFilesystemTranslationPreferred(false),
|
||||
fAreResourcesLoaded(false)
|
||||
{
|
||||
fInitStatus = _Initialize();
|
||||
}
|
||||
|
||||
|
||||
LocaleRosterData::~LocaleRosterData()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
|
||||
_CleanupCatalogAddOns();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::InitCheck() const
|
||||
{
|
||||
return fAreResourcesLoaded ? B_OK : B_NO_INIT;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::Refresh()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
_LoadLocaleSettings();
|
||||
_LoadTimeSettings();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
LocaleRosterData::CompareInfos(const void* left, const void* right)
|
||||
{
|
||||
return ((CatalogAddOnInfo*)right)->fPriority
|
||||
- ((CatalogAddOnInfo*)left)->fPriority;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& newFormattingConventions)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetDefaultFormattingConventions(newFormattingConventions);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddDefaultFormattingConventionsToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetDefaultTimeZone(newZone);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveTimeSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddDefaultTimeZoneToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::SetPreferredLanguages(const BMessage* languages)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetPreferredLanguages(languages);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddPreferredLanguagesToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::SetFilesystemTranslationPreferred(bool preferred)
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
_SetFilesystemTranslationPreferred(preferred);
|
||||
|
||||
status_t status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::GetResources(BResources** resources)
|
||||
{
|
||||
if (resources == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!fAreResourcesLoaded) {
|
||||
status_t result
|
||||
= fResources.SetToImage((const void*)&BLocaleRoster::Default);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = fResources.PreloadResourceType();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fAreResourcesLoaded = true;
|
||||
}
|
||||
|
||||
*resources = &fResources;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_Initialize()
|
||||
{
|
||||
status_t result = _InitializeCatalogAddOns();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if ((result = Refresh()) != B_OK)
|
||||
return result;
|
||||
|
||||
fInitStatus = B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
iterate over add-on-folders and collect information about each
|
||||
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
|
||||
*/
|
||||
status_t
|
||||
LocaleRosterData::_InitializeCatalogAddOns()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
// add info about embedded default catalog:
|
||||
CatalogAddOnInfo* defaultCatalogAddOnInfo
|
||||
= new(std::nothrow) CatalogAddOnInfo("Default", "",
|
||||
DefaultCatalog::kDefaultCatalogAddOnPriority);
|
||||
if (!defaultCatalogAddOnInfo)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
|
||||
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
|
||||
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
|
||||
|
||||
directory_which folders[] = {
|
||||
B_USER_ADDONS_DIRECTORY,
|
||||
B_COMMON_ADDONS_DIRECTORY,
|
||||
B_SYSTEM_ADDONS_DIRECTORY,
|
||||
};
|
||||
BPath addOnPath;
|
||||
BDirectory addOnFolder;
|
||||
char buf[4096];
|
||||
status_t err;
|
||||
for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) {
|
||||
find_directory(folders[f], &addOnPath);
|
||||
BString addOnFolderName(addOnPath.Path());
|
||||
addOnFolderName << "/locale/catalogs";
|
||||
|
||||
system_info info;
|
||||
if (get_system_info(&info) == B_OK
|
||||
&& (info.abi & B_HAIKU_ABI_MAJOR)
|
||||
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
|
||||
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
|
||||
case B_HAIKU_ABI_GCC_2:
|
||||
addOnFolderName << "/gcc2";
|
||||
break;
|
||||
case B_HAIKU_ABI_GCC_4:
|
||||
addOnFolderName << "/gcc4";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
err = addOnFolder.SetTo(addOnFolderName.String());
|
||||
if (err != B_OK)
|
||||
continue;
|
||||
|
||||
// scan through all the folder's entries for catalog add-ons:
|
||||
int32 count;
|
||||
int8 priority;
|
||||
entry_ref eref;
|
||||
BNode node;
|
||||
BEntry entry;
|
||||
dirent* dent;
|
||||
while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) {
|
||||
dent = (dirent*)buf;
|
||||
while (count-- > 0) {
|
||||
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
|
||||
&& strcmp(dent->d_name, "gcc2")
|
||||
&& strcmp(dent->d_name, "gcc4")) {
|
||||
// we have found (what should be) a catalog-add-on:
|
||||
eref.device = dent->d_pdev;
|
||||
eref.directory = dent->d_pino;
|
||||
eref.set_name(dent->d_name);
|
||||
entry.SetTo(&eref, true);
|
||||
// traverse through any links to get to the real thang!
|
||||
node.SetTo(&entry);
|
||||
priority = -1;
|
||||
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
|
||||
&priority, sizeof(int8)) <= 0) {
|
||||
// add-on has no priority-attribute yet, so we load it
|
||||
// to fetch the priority from the corresponding
|
||||
// symbol...
|
||||
BString fullAddOnPath(addOnFolderName);
|
||||
fullAddOnPath << "/" << dent->d_name;
|
||||
image_id image = load_add_on(fullAddOnPath.String());
|
||||
if (image >= B_OK) {
|
||||
uint8* prioPtr;
|
||||
if (get_image_symbol(image, "gCatalogAddOnPriority",
|
||||
B_SYMBOL_TYPE_DATA,
|
||||
(void**)&prioPtr) == B_OK) {
|
||||
priority = *prioPtr;
|
||||
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
|
||||
&priority, sizeof(int8));
|
||||
}
|
||||
unload_add_on(image);
|
||||
}
|
||||
}
|
||||
|
||||
if (priority >= 0) {
|
||||
// add-ons with priority < 0 will be ignored
|
||||
CatalogAddOnInfo* addOnInfo
|
||||
= new(std::nothrow) CatalogAddOnInfo(dent->d_name,
|
||||
addOnFolderName, priority);
|
||||
if (addOnInfo)
|
||||
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
|
||||
}
|
||||
}
|
||||
// Bump the dirent-pointer by length of the dirent just handled:
|
||||
dent = (dirent*)((char*)dent + dent->d_reclen);
|
||||
}
|
||||
}
|
||||
}
|
||||
fCatalogAddOnInfos.SortItems(CompareInfos);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
|
||||
*/
|
||||
void
|
||||
LocaleRosterData::_CleanupCatalogAddOns()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
|
||||
int32 count = fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i<count; ++i) {
|
||||
CatalogAddOnInfo* info
|
||||
= static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
|
||||
delete info;
|
||||
}
|
||||
fCatalogAddOnInfos.MakeEmpty();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_LoadLocaleSettings()
|
||||
{
|
||||
BPath path;
|
||||
BFile file;
|
||||
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
if (status == B_OK) {
|
||||
path.Append("Locale settings");
|
||||
status = file.SetTo(path.Path(), B_READ_ONLY);
|
||||
}
|
||||
BMessage settings;
|
||||
if (status == B_OK)
|
||||
status = settings.Unflatten(&file);
|
||||
|
||||
if (status == B_OK) {
|
||||
BFormattingConventions conventions(&settings);
|
||||
fDefaultLocale.SetFormattingConventions(conventions);
|
||||
|
||||
_SetPreferredLanguages(&settings);
|
||||
|
||||
bool preferred;
|
||||
if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK)
|
||||
_SetFilesystemTranslationPreferred(preferred);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Something went wrong (no settings file or invalid BMessage), so we
|
||||
// set everything to default values
|
||||
|
||||
fPreferredLanguages.MakeEmpty();
|
||||
fPreferredLanguages.AddString(kLanguageField, "en");
|
||||
BLanguage defaultLanguage("en_US");
|
||||
fDefaultLocale.SetLanguage(defaultLanguage);
|
||||
BFormattingConventions conventions("en_US");
|
||||
fDefaultLocale.SetFormattingConventions(conventions);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_LoadTimeSettings()
|
||||
{
|
||||
BPath path;
|
||||
BFile file;
|
||||
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
if (status == B_OK) {
|
||||
path.Append("Time settings");
|
||||
status = file.SetTo(path.Path(), B_READ_ONLY);
|
||||
}
|
||||
BMessage settings;
|
||||
if (status == B_OK)
|
||||
status = settings.Unflatten(&file);
|
||||
if (status == B_OK) {
|
||||
BString timeZoneID;
|
||||
if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK)
|
||||
_SetDefaultTimeZone(BTimeZone(timeZoneID.String()));
|
||||
else
|
||||
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Something went wrong (no settings file or invalid BMessage), so we
|
||||
// set everything to default values
|
||||
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_SaveLocaleSettings()
|
||||
{
|
||||
BMessage settings;
|
||||
status_t status = _AddDefaultFormattingConventionsToMessage(&settings);
|
||||
if (status == B_OK)
|
||||
_AddPreferredLanguagesToMessage(&settings);
|
||||
if (status == B_OK)
|
||||
_AddFilesystemTranslationPreferenceToMessage(&settings);
|
||||
|
||||
BPath path;
|
||||
if (status == B_OK)
|
||||
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
|
||||
BFile file;
|
||||
if (status == B_OK) {
|
||||
path.Append("Locale settings");
|
||||
status = file.SetTo(path.Path(),
|
||||
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||||
}
|
||||
if (status == B_OK)
|
||||
status = settings.Flatten(&file);
|
||||
if (status == B_OK)
|
||||
status = file.Sync();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_SaveTimeSettings()
|
||||
{
|
||||
BMessage settings;
|
||||
status_t status = _AddDefaultTimeZoneToMessage(&settings);
|
||||
|
||||
BPath path;
|
||||
if (status == B_OK)
|
||||
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
|
||||
BFile file;
|
||||
if (status == B_OK) {
|
||||
path.Append("Time settings");
|
||||
status = file.SetTo(path.Path(),
|
||||
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||||
}
|
||||
if (status == B_OK)
|
||||
status = settings.Flatten(&file);
|
||||
if (status == B_OK)
|
||||
status = file.Sync();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& newFormattingConventions)
|
||||
{
|
||||
fDefaultLocale.SetFormattingConventions(newFormattingConventions);
|
||||
|
||||
UErrorCode icuError = U_ZERO_ERROR;
|
||||
Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID());
|
||||
if (icuLocale.isBogus())
|
||||
return B_ERROR;
|
||||
|
||||
Locale::setDefault(icuLocale, icuError);
|
||||
if (!U_SUCCESS(icuError))
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
fDefaultTimeZone = newZone;
|
||||
|
||||
TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String());
|
||||
if (timeZone == NULL)
|
||||
return B_ERROR;
|
||||
TimeZone::adoptDefault(timeZone);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_SetPreferredLanguages(const BMessage* languages)
|
||||
{
|
||||
BString langName;
|
||||
if (languages != NULL
|
||||
&& languages->FindString(kLanguageField, &langName) == B_OK) {
|
||||
fDefaultLocale.SetCollator(BCollator(langName.String()));
|
||||
fDefaultLocale.SetLanguage(BLanguage(langName.String()));
|
||||
|
||||
fPreferredLanguages.RemoveName(kLanguageField);
|
||||
for (int i = 0; languages->FindString(kLanguageField, i, &langName)
|
||||
== B_OK; i++) {
|
||||
fPreferredLanguages.AddString(kLanguageField, langName);
|
||||
}
|
||||
} else {
|
||||
fPreferredLanguages.MakeEmpty();
|
||||
fPreferredLanguages.AddString(kLanguageField, "en");
|
||||
fDefaultLocale.SetCollator(BCollator("en"));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LocaleRosterData::_SetFilesystemTranslationPreferred(bool preferred)
|
||||
{
|
||||
fIsFilesystemTranslationPreferred = preferred;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_AddDefaultFormattingConventionsToMessage(
|
||||
BMessage* message) const
|
||||
{
|
||||
BFormattingConventions conventions;
|
||||
fDefaultLocale.GetFormattingConventions(&conventions);
|
||||
|
||||
return conventions.Archive(message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
|
||||
{
|
||||
return message->AddString(kTimezoneField, fDefaultTimeZone.ID());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_AddPreferredLanguagesToMessage(BMessage* message) const
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BString langName;
|
||||
for (int i = 0; fPreferredLanguages.FindString("language", i,
|
||||
&langName) == B_OK; i++) {
|
||||
status = message->AddString(kLanguageField, langName);
|
||||
if (status != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LocaleRosterData::_AddFilesystemTranslationPreferenceToMessage(
|
||||
BMessage* message) const
|
||||
{
|
||||
return message->AddBool(kTranslateFilesystemField,
|
||||
fIsFilesystemTranslationPreferred);
|
||||
}
|
||||
|
||||
|
||||
} // namespace BPrivate
|
@ -10,702 +10,41 @@
|
||||
|
||||
#include <MutableLocaleRoster.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <AppFileInfo.h>
|
||||
#include <Application.h>
|
||||
#include <Autolock.h>
|
||||
#include <Catalog.h>
|
||||
#include <Collator.h>
|
||||
#include <CatalogData.h>
|
||||
#include <Debug.h>
|
||||
#include <DefaultCatalog.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <FormattingConventions.h>
|
||||
#include <Language.h>
|
||||
#include <Locale.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <LocaleRosterData.h>
|
||||
#include <String.h>
|
||||
#include <TimeZone.h>
|
||||
|
||||
#include <ICUWrapper.h>
|
||||
|
||||
// ICU includes
|
||||
#include <unicode/locid.h>
|
||||
#include <unicode/timezone.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
|
||||
|
||||
// #pragma mark - CatalogAddOnInfo
|
||||
|
||||
|
||||
CatalogAddOnInfo::CatalogAddOnInfo(const BString& name, const BString& path,
|
||||
uint8 priority)
|
||||
:
|
||||
fInstantiateFunc(NULL),
|
||||
fCreateFunc(NULL),
|
||||
fLanguagesFunc(NULL),
|
||||
fName(name),
|
||||
fPath(path),
|
||||
fAddOnImage(B_NO_INIT),
|
||||
fPriority(priority),
|
||||
fIsEmbedded(path.Length()==0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CatalogAddOnInfo::~CatalogAddOnInfo()
|
||||
{
|
||||
int32 count = fLoadedCatalogs.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
BCatalogData* cat
|
||||
= static_cast<BCatalogData*>(fLoadedCatalogs.ItemAt(i));
|
||||
delete cat;
|
||||
}
|
||||
fLoadedCatalogs.MakeEmpty();
|
||||
UnloadIfPossible();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CatalogAddOnInfo::MakeSureItsLoaded()
|
||||
{
|
||||
if (!fIsEmbedded && fAddOnImage < B_OK) {
|
||||
// add-on has not been loaded yet, so we try to load it:
|
||||
BString fullAddOnPath(fPath);
|
||||
fullAddOnPath << "/" << fName;
|
||||
fAddOnImage = load_add_on(fullAddOnPath.String());
|
||||
if (fAddOnImage >= B_OK) {
|
||||
get_image_symbol(fAddOnImage, "instantiate_catalog",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fInstantiateFunc);
|
||||
get_image_symbol(fAddOnImage, "create_catalog",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fCreateFunc);
|
||||
get_image_symbol(fAddOnImage, "get_available_languages",
|
||||
B_SYMBOL_TYPE_TEXT, (void**)&fLanguagesFunc);
|
||||
} else
|
||||
return false;
|
||||
} else if (fIsEmbedded) {
|
||||
// The built-in catalog still has to provide this function
|
||||
fLanguagesFunc = default_catalog_get_available_languages;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CatalogAddOnInfo::UnloadIfPossible()
|
||||
{
|
||||
if (!fIsEmbedded && fLoadedCatalogs.IsEmpty()) {
|
||||
unload_add_on(fAddOnImage);
|
||||
fAddOnImage = B_NO_INIT;
|
||||
fInstantiateFunc = NULL;
|
||||
fCreateFunc = NULL;
|
||||
fLanguagesFunc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - RosterData
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
static const char* kPriorityAttr = "ADDON:priority";
|
||||
static MutableLocaleRoster* sLocaleRoster;
|
||||
|
||||
static const char* kLanguageField = "language";
|
||||
static const char* kTimezoneField = "timezone";
|
||||
static const char* kTranslateFilesystemField = "filesys";
|
||||
|
||||
|
||||
static RosterData* sRosterData = NULL;
|
||||
static pthread_once_t sRosterDataInitOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
static struct RosterDataReaper {
|
||||
~RosterDataReaper()
|
||||
{
|
||||
delete sRosterData;
|
||||
sRosterData = NULL;
|
||||
}
|
||||
} sRosterDataReaper;
|
||||
static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT;
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
static void
|
||||
InitializeRosterData()
|
||||
InitializeLocaleRoster()
|
||||
{
|
||||
sRosterData = new (std::nothrow) RosterData(BLanguage("en_US"),
|
||||
BFormattingConventions("en_US"));
|
||||
sLocaleRoster = new (std::nothrow) MutableLocaleRoster();
|
||||
}
|
||||
|
||||
|
||||
RosterData::RosterData(const BLanguage& language,
|
||||
const BFormattingConventions& conventions)
|
||||
:
|
||||
fLock("LocaleRosterData"),
|
||||
fDefaultLocale(&language, &conventions),
|
||||
fIsFilesystemTranslationPreferred(false),
|
||||
fAreResourcesLoaded(false)
|
||||
{
|
||||
fInitStatus = _Initialize();
|
||||
}
|
||||
|
||||
|
||||
RosterData::~RosterData()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
|
||||
_CleanupCatalogAddOns();
|
||||
}
|
||||
|
||||
|
||||
/*static*/ RosterData*
|
||||
RosterData::Default()
|
||||
{
|
||||
if (sRosterData == NULL)
|
||||
pthread_once(&sRosterDataInitOnce, &BPrivate::InitializeRosterData);
|
||||
|
||||
return sRosterData;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::InitCheck() const
|
||||
{
|
||||
return fAreResourcesLoaded ? B_OK : B_NO_INIT;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::Refresh()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
_LoadLocaleSettings();
|
||||
_LoadTimeSettings();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
RosterData::CompareInfos(const void* left, const void* right)
|
||||
{
|
||||
return ((CatalogAddOnInfo*)right)->fPriority
|
||||
- ((CatalogAddOnInfo*)left)->fPriority;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& newFormattingConventions)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetDefaultFormattingConventions(newFormattingConventions);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddDefaultFormattingConventionsToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetDefaultTimeZone(newZone);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveTimeSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddDefaultTimeZoneToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::SetPreferredLanguages(const BMessage* languages)
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
status = _SetPreferredLanguages(languages);
|
||||
|
||||
if (status == B_OK)
|
||||
status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddPreferredLanguagesToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::SetFilesystemTranslationPreferred(bool preferred)
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
_SetFilesystemTranslationPreferred(preferred);
|
||||
|
||||
status_t status = _SaveLocaleSettings();
|
||||
|
||||
if (status == B_OK) {
|
||||
BMessage updateMessage(B_LOCALE_CHANGED);
|
||||
status = _AddFilesystemTranslationPreferenceToMessage(&updateMessage);
|
||||
if (status == B_OK)
|
||||
status = be_roster->Broadcast(&updateMessage);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_Initialize()
|
||||
{
|
||||
status_t result = _InitializeCatalogAddOns();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if ((result = Refresh()) != B_OK)
|
||||
return result;
|
||||
|
||||
fInitStatus = B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
iterate over add-on-folders and collect information about each
|
||||
catalog-add-ons (types of catalogs) into fCatalogAddOnInfos.
|
||||
*/
|
||||
status_t
|
||||
RosterData::_InitializeCatalogAddOns()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
// add info about embedded default catalog:
|
||||
CatalogAddOnInfo* defaultCatalogAddOnInfo
|
||||
= new(std::nothrow) CatalogAddOnInfo("Default", "",
|
||||
DefaultCatalog::kDefaultCatalogAddOnPriority);
|
||||
if (!defaultCatalogAddOnInfo)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
defaultCatalogAddOnInfo->fInstantiateFunc = DefaultCatalog::Instantiate;
|
||||
defaultCatalogAddOnInfo->fCreateFunc = DefaultCatalog::Create;
|
||||
fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo);
|
||||
|
||||
directory_which folders[] = {
|
||||
B_USER_ADDONS_DIRECTORY,
|
||||
B_COMMON_ADDONS_DIRECTORY,
|
||||
B_SYSTEM_ADDONS_DIRECTORY,
|
||||
};
|
||||
BPath addOnPath;
|
||||
BDirectory addOnFolder;
|
||||
char buf[4096];
|
||||
status_t err;
|
||||
for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) {
|
||||
find_directory(folders[f], &addOnPath);
|
||||
BString addOnFolderName(addOnPath.Path());
|
||||
addOnFolderName << "/locale/catalogs";
|
||||
|
||||
system_info info;
|
||||
if (get_system_info(&info) == B_OK
|
||||
&& (info.abi & B_HAIKU_ABI_MAJOR)
|
||||
!= (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR)) {
|
||||
switch (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) {
|
||||
case B_HAIKU_ABI_GCC_2:
|
||||
addOnFolderName << "/gcc2";
|
||||
break;
|
||||
case B_HAIKU_ABI_GCC_4:
|
||||
addOnFolderName << "/gcc4";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
err = addOnFolder.SetTo(addOnFolderName.String());
|
||||
if (err != B_OK)
|
||||
continue;
|
||||
|
||||
// scan through all the folder's entries for catalog add-ons:
|
||||
int32 count;
|
||||
int8 priority;
|
||||
entry_ref eref;
|
||||
BNode node;
|
||||
BEntry entry;
|
||||
dirent* dent;
|
||||
while ((count = addOnFolder.GetNextDirents((dirent*)buf, 4096)) > 0) {
|
||||
dent = (dirent*)buf;
|
||||
while (count-- > 0) {
|
||||
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")
|
||||
&& strcmp(dent->d_name, "gcc2")
|
||||
&& strcmp(dent->d_name, "gcc4")) {
|
||||
// we have found (what should be) a catalog-add-on:
|
||||
eref.device = dent->d_pdev;
|
||||
eref.directory = dent->d_pino;
|
||||
eref.set_name(dent->d_name);
|
||||
entry.SetTo(&eref, true);
|
||||
// traverse through any links to get to the real thang!
|
||||
node.SetTo(&entry);
|
||||
priority = -1;
|
||||
if (node.ReadAttr(kPriorityAttr, B_INT8_TYPE, 0,
|
||||
&priority, sizeof(int8)) <= 0) {
|
||||
// add-on has no priority-attribute yet, so we load it
|
||||
// to fetch the priority from the corresponding
|
||||
// symbol...
|
||||
BString fullAddOnPath(addOnFolderName);
|
||||
fullAddOnPath << "/" << dent->d_name;
|
||||
image_id image = load_add_on(fullAddOnPath.String());
|
||||
if (image >= B_OK) {
|
||||
uint8* prioPtr;
|
||||
if (get_image_symbol(image, "gCatalogAddOnPriority",
|
||||
B_SYMBOL_TYPE_DATA,
|
||||
(void**)&prioPtr) == B_OK) {
|
||||
priority = *prioPtr;
|
||||
node.WriteAttr(kPriorityAttr, B_INT8_TYPE, 0,
|
||||
&priority, sizeof(int8));
|
||||
}
|
||||
unload_add_on(image);
|
||||
}
|
||||
}
|
||||
|
||||
if (priority >= 0) {
|
||||
// add-ons with priority < 0 will be ignored
|
||||
CatalogAddOnInfo* addOnInfo
|
||||
= new(std::nothrow) CatalogAddOnInfo(dent->d_name,
|
||||
addOnFolderName, priority);
|
||||
if (addOnInfo)
|
||||
fCatalogAddOnInfos.AddItem((void*)addOnInfo);
|
||||
}
|
||||
}
|
||||
// Bump the dirent-pointer by length of the dirent just handled:
|
||||
dent = (dirent*)((char*)dent + dent->d_reclen);
|
||||
}
|
||||
}
|
||||
}
|
||||
fCatalogAddOnInfos.SortItems(CompareInfos);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* unloads all catalog-add-ons (which will throw away all loaded catalogs, too)
|
||||
*/
|
||||
void
|
||||
RosterData::_CleanupCatalogAddOns()
|
||||
{
|
||||
BAutolock lock(fLock);
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
|
||||
int32 count = fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i<count; ++i) {
|
||||
CatalogAddOnInfo* info
|
||||
= static_cast<CatalogAddOnInfo*>(fCatalogAddOnInfos.ItemAt(i));
|
||||
delete info;
|
||||
}
|
||||
fCatalogAddOnInfos.MakeEmpty();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_LoadLocaleSettings()
|
||||
{
|
||||
BPath path;
|
||||
BFile file;
|
||||
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
if (status == B_OK) {
|
||||
path.Append("Locale settings");
|
||||
status = file.SetTo(path.Path(), B_READ_ONLY);
|
||||
}
|
||||
BMessage settings;
|
||||
if (status == B_OK)
|
||||
status = settings.Unflatten(&file);
|
||||
|
||||
if (status == B_OK) {
|
||||
BFormattingConventions conventions(&settings);
|
||||
fDefaultLocale.SetFormattingConventions(conventions);
|
||||
|
||||
_SetPreferredLanguages(&settings);
|
||||
|
||||
bool preferred;
|
||||
if (settings.FindBool(kTranslateFilesystemField, &preferred) == B_OK)
|
||||
_SetFilesystemTranslationPreferred(preferred);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Something went wrong (no settings file or invalid BMessage), so we
|
||||
// set everything to default values
|
||||
|
||||
fPreferredLanguages.MakeEmpty();
|
||||
fPreferredLanguages.AddString(kLanguageField, "en");
|
||||
BLanguage defaultLanguage("en_US");
|
||||
fDefaultLocale.SetLanguage(defaultLanguage);
|
||||
BFormattingConventions conventions("en_US");
|
||||
fDefaultLocale.SetFormattingConventions(conventions);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_LoadTimeSettings()
|
||||
{
|
||||
BPath path;
|
||||
BFile file;
|
||||
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
if (status == B_OK) {
|
||||
path.Append("Time settings");
|
||||
status = file.SetTo(path.Path(), B_READ_ONLY);
|
||||
}
|
||||
BMessage settings;
|
||||
if (status == B_OK)
|
||||
status = settings.Unflatten(&file);
|
||||
if (status == B_OK) {
|
||||
BString timeZoneID;
|
||||
if (settings.FindString(kTimezoneField, &timeZoneID) == B_OK)
|
||||
_SetDefaultTimeZone(BTimeZone(timeZoneID.String()));
|
||||
else
|
||||
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Something went wrong (no settings file or invalid BMessage), so we
|
||||
// set everything to default values
|
||||
_SetDefaultTimeZone(BTimeZone(BTimeZone::kNameOfGmtZone));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_SaveLocaleSettings()
|
||||
{
|
||||
BMessage settings;
|
||||
status_t status = _AddDefaultFormattingConventionsToMessage(&settings);
|
||||
if (status == B_OK)
|
||||
_AddPreferredLanguagesToMessage(&settings);
|
||||
if (status == B_OK)
|
||||
_AddFilesystemTranslationPreferenceToMessage(&settings);
|
||||
|
||||
BPath path;
|
||||
if (status == B_OK)
|
||||
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
|
||||
BFile file;
|
||||
if (status == B_OK) {
|
||||
path.Append("Locale settings");
|
||||
status = file.SetTo(path.Path(),
|
||||
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||||
}
|
||||
if (status == B_OK)
|
||||
status = settings.Flatten(&file);
|
||||
if (status == B_OK)
|
||||
status = file.Sync();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_SaveTimeSettings()
|
||||
{
|
||||
BMessage settings;
|
||||
status_t status = _AddDefaultTimeZoneToMessage(&settings);
|
||||
|
||||
BPath path;
|
||||
if (status == B_OK)
|
||||
status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
|
||||
BFile file;
|
||||
if (status == B_OK) {
|
||||
path.Append("Time settings");
|
||||
status = file.SetTo(path.Path(),
|
||||
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
|
||||
}
|
||||
if (status == B_OK)
|
||||
status = settings.Flatten(&file);
|
||||
if (status == B_OK)
|
||||
status = file.Sync();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& newFormattingConventions)
|
||||
{
|
||||
fDefaultLocale.SetFormattingConventions(newFormattingConventions);
|
||||
|
||||
UErrorCode icuError = U_ZERO_ERROR;
|
||||
Locale icuLocale = Locale::createCanonical(newFormattingConventions.ID());
|
||||
if (icuLocale.isBogus())
|
||||
return B_ERROR;
|
||||
|
||||
Locale::setDefault(icuLocale, icuError);
|
||||
if (!U_SUCCESS(icuError))
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
fDefaultTimeZone = newZone;
|
||||
|
||||
TimeZone* timeZone = TimeZone::createTimeZone(newZone.ID().String());
|
||||
if (timeZone == NULL)
|
||||
return B_ERROR;
|
||||
TimeZone::adoptDefault(timeZone);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_SetPreferredLanguages(const BMessage* languages)
|
||||
{
|
||||
BString langName;
|
||||
if (languages != NULL
|
||||
&& languages->FindString(kLanguageField, &langName) == B_OK) {
|
||||
fDefaultLocale.SetCollator(BCollator(langName.String()));
|
||||
fDefaultLocale.SetLanguage(BLanguage(langName.String()));
|
||||
|
||||
fPreferredLanguages.RemoveName(kLanguageField);
|
||||
for (int i = 0; languages->FindString(kLanguageField, i, &langName)
|
||||
== B_OK; i++) {
|
||||
fPreferredLanguages.AddString(kLanguageField, langName);
|
||||
}
|
||||
} else {
|
||||
fPreferredLanguages.MakeEmpty();
|
||||
fPreferredLanguages.AddString(kLanguageField, "en");
|
||||
fDefaultLocale.SetCollator(BCollator("en"));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RosterData::_SetFilesystemTranslationPreferred(bool preferred)
|
||||
{
|
||||
fIsFilesystemTranslationPreferred = preferred;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_AddDefaultFormattingConventionsToMessage(BMessage* message) const
|
||||
{
|
||||
BFormattingConventions conventions;
|
||||
fDefaultLocale.GetFormattingConventions(&conventions);
|
||||
|
||||
return conventions.Archive(message);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_AddDefaultTimeZoneToMessage(BMessage* message) const
|
||||
{
|
||||
return message->AddString(kTimezoneField, fDefaultTimeZone.ID());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_AddPreferredLanguagesToMessage(BMessage* message) const
|
||||
{
|
||||
status_t status = B_OK;
|
||||
|
||||
BString langName;
|
||||
for (int i = 0; fPreferredLanguages.FindString("language", i,
|
||||
&langName) == B_OK; i++) {
|
||||
status = message->AddString(kLanguageField, langName);
|
||||
if (status != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RosterData::_AddFilesystemTranslationPreferenceToMessage(BMessage* message)
|
||||
const
|
||||
{
|
||||
return message->AddBool(kTranslateFilesystemField,
|
||||
fIsFilesystemTranslationPreferred);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MutableLocaleRoster
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
static MutableLocaleRoster sLocaleRoster;
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
MutableLocaleRoster::MutableLocaleRoster()
|
||||
{
|
||||
}
|
||||
@ -719,7 +58,10 @@ MutableLocaleRoster::~MutableLocaleRoster()
|
||||
/*static*/ MutableLocaleRoster*
|
||||
MutableLocaleRoster::Default()
|
||||
{
|
||||
return &sLocaleRoster;
|
||||
if (sLocaleRoster == NULL)
|
||||
pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster);
|
||||
|
||||
return sLocaleRoster;
|
||||
}
|
||||
|
||||
|
||||
@ -727,29 +69,28 @@ status_t
|
||||
MutableLocaleRoster::SetDefaultFormattingConventions(
|
||||
const BFormattingConventions& newFormattingConventions)
|
||||
{
|
||||
return RosterData::Default()->SetDefaultFormattingConventions(
|
||||
newFormattingConventions);
|
||||
return fData->SetDefaultFormattingConventions(newFormattingConventions);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
|
||||
{
|
||||
return RosterData::Default()->SetDefaultTimeZone(newZone);
|
||||
return fData->SetDefaultTimeZone(newZone);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
|
||||
{
|
||||
return RosterData::Default()->SetPreferredLanguages(languages);
|
||||
return fData->SetPreferredLanguages(languages);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred)
|
||||
{
|
||||
return RosterData::Default()->SetFilesystemTranslationPreferred(preferred);
|
||||
return fData->SetFilesystemTranslationPreferred(preferred);
|
||||
}
|
||||
|
||||
|
||||
@ -800,14 +141,14 @@ MutableLocaleRoster::CreateCatalog(const char* type, const char* signature,
|
||||
if (!type || !signature || !language)
|
||||
return NULL;
|
||||
|
||||
BAutolock lock(RosterData::Default()->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return NULL;
|
||||
|
||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
||||
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
|
||||
fData->fCatalogAddOnInfos.ItemAt(i);
|
||||
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|
||||
|| !info->fCreateFunc)
|
||||
continue;
|
||||
@ -838,14 +179,14 @@ BCatalogData*
|
||||
MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner,
|
||||
const char* language, int32 fingerprint) const
|
||||
{
|
||||
BAutolock lock(RosterData::Default()->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return NULL;
|
||||
|
||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
||||
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
|
||||
fData->fCatalogAddOnInfos.ItemAt(i);
|
||||
|
||||
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
|
||||
continue;
|
||||
@ -909,7 +250,7 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
|
||||
if (!catalog)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BAutolock lock(RosterData::Default()->fLock);
|
||||
BAutolock lock(fData->fLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
@ -918,10 +259,10 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
|
||||
|
||||
while (catalog != NULL) {
|
||||
nextCatalog = catalog->Next();
|
||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
||||
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||
for (int32 i = 0; i < count; ++i) {
|
||||
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
|
||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i));
|
||||
fData->fCatalogAddOnInfos.ItemAt(i));
|
||||
if (info->fLoadedCatalogs.HasItem(catalog)) {
|
||||
info->fLoadedCatalogs.RemoveItem(catalog);
|
||||
delete catalog;
|
||||
|
Loading…
Reference in New Issue
Block a user