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:
@@ -21,14 +21,19 @@ class BMessage;
|
|||||||
class BTimeZone;
|
class BTimeZone;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
class LocaleRosterData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
B_LOCALE_CHANGED = '_LCC',
|
B_LOCALE_CHANGED = '_LCC',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BLocaleRoster {
|
class BLocaleRoster {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BLocaleRoster();
|
|
||||||
~BLocaleRoster();
|
~BLocaleRoster();
|
||||||
|
|
||||||
static BLocaleRoster* Default();
|
static BLocaleRoster* Default();
|
||||||
@@ -70,6 +75,8 @@ public:
|
|||||||
// Get the catalog for the calling image
|
// Get the catalog for the calling image
|
||||||
// (that needs to link with liblocalestub.a)
|
// (that needs to link with liblocalestub.a)
|
||||||
|
|
||||||
|
const BLocale* GetDefaultLocale() const;
|
||||||
|
|
||||||
bool IsFilesystemTranslationPreferred() const;
|
bool IsFilesystemTranslationPreferred() const;
|
||||||
|
|
||||||
status_t GetLocalizedFileName(BString& localizedFileName,
|
status_t GetLocalizedFileName(BString& localizedFileName,
|
||||||
@@ -83,6 +90,12 @@ public:
|
|||||||
static const char* kEmbeddedCatAttr;
|
static const char* kEmbeddedCatAttr;
|
||||||
static int32 kEmbeddedCatResId;
|
static int32 kEmbeddedCatResId;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BLocaleRoster();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BPrivate::LocaleRosterData* fData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static BCatalog* _GetCatalog(BCatalog* catalog,
|
static BCatalog* _GetCatalog(BCatalog* catalog,
|
||||||
vint32* catalogInitStatus);
|
vint32* catalogInitStatus);
|
||||||
@@ -90,6 +103,7 @@ private:
|
|||||||
status_t _PrepareCatalogEntry(const entry_ref& ref,
|
status_t _PrepareCatalogEntry(const entry_ref& ref,
|
||||||
BString& signature, BString& context,
|
BString& signature, BString& context,
|
||||||
BString& string, bool traverse);
|
BString& string, bool traverse);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ local sources =
|
|||||||
Language.cpp
|
Language.cpp
|
||||||
Locale.cpp
|
Locale.cpp
|
||||||
LocaleRoster.cpp
|
LocaleRoster.cpp
|
||||||
|
LocaleRosterData.cpp
|
||||||
MutableLocaleRoster.cpp
|
MutableLocaleRoster.cpp
|
||||||
TimeZone.cpp
|
TimeZone.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include <LanguagePrivate.h>
|
#include <LanguagePrivate.h>
|
||||||
#include <Locale.h>
|
#include <Locale.h>
|
||||||
#include <LocaleRoster.h>
|
#include <LocaleRoster.h>
|
||||||
#include <MutableLocaleRoster.h>
|
|
||||||
#include <TimeZone.h>
|
#include <TimeZone.h>
|
||||||
|
|
||||||
#include <ICUWrapper.h>
|
#include <ICUWrapper.h>
|
||||||
@@ -59,7 +58,7 @@ BLocale::BLocale(const BLocale& other)
|
|||||||
/*static*/ const BLocale*
|
/*static*/ const BLocale*
|
||||||
BLocale::Default()
|
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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -10,27 +10,23 @@
|
|||||||
|
|
||||||
#include <LocaleRoster.h>
|
#include <LocaleRoster.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Bitmap.h>
|
#include <Bitmap.h>
|
||||||
#include <Catalog.h>
|
#include <Catalog.h>
|
||||||
#include <Collator.h>
|
|
||||||
#include <DefaultCatalog.h>
|
|
||||||
#include <Directory.h>
|
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <File.h>
|
|
||||||
#include <FormattingConventions.h>
|
#include <FormattingConventions.h>
|
||||||
#include <fs_attr.h>
|
#include <fs_attr.h>
|
||||||
#include <IconUtils.h>
|
#include <IconUtils.h>
|
||||||
#include <Language.h>
|
#include <Language.h>
|
||||||
#include <Locale.h>
|
#include <Locale.h>
|
||||||
|
#include <LocaleRosterData.h>
|
||||||
#include <MutableLocaleRoster.h>
|
#include <MutableLocaleRoster.h>
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <Path.h>
|
|
||||||
#include <Roster.h>
|
#include <Roster.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <TimeZone.h>
|
#include <TimeZone.h>
|
||||||
@@ -45,7 +41,6 @@
|
|||||||
|
|
||||||
using BPrivate::CatalogAddOnInfo;
|
using BPrivate::CatalogAddOnInfo;
|
||||||
using BPrivate::MutableLocaleRoster;
|
using BPrivate::MutableLocaleRoster;
|
||||||
using BPrivate::RosterData;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,26 +62,6 @@ int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
|
|||||||
// this may live in an app- or add-on-file
|
// 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*
|
static const char*
|
||||||
country_code_for_language(const BLanguage& language)
|
country_code_for_language(const BLanguage& language)
|
||||||
{
|
{
|
||||||
@@ -149,12 +124,16 @@ country_code_for_language(const BLanguage& language)
|
|||||||
|
|
||||||
|
|
||||||
BLocaleRoster::BLocaleRoster()
|
BLocaleRoster::BLocaleRoster()
|
||||||
|
:
|
||||||
|
fData(new(std::nothrow) BPrivate::LocaleRosterData(BLanguage("en_US"),
|
||||||
|
BFormattingConventions("en_US")))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BLocaleRoster::~BLocaleRoster()
|
BLocaleRoster::~BLocaleRoster()
|
||||||
{
|
{
|
||||||
|
delete fData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +147,7 @@ BLocaleRoster::Default()
|
|||||||
status_t
|
status_t
|
||||||
BLocaleRoster::Refresh()
|
BLocaleRoster::Refresh()
|
||||||
{
|
{
|
||||||
return RosterData::Default()->Refresh();
|
return fData->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -178,17 +157,22 @@ BLocaleRoster::GetDefaultTimeZone(BTimeZone* timezone) const
|
|||||||
if (!timezone)
|
if (!timezone)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
*timezone = rosterData->fDefaultTimeZone;
|
*timezone = fData->fDefaultTimeZone;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BLocale*
|
||||||
|
BLocaleRoster::GetDefaultLocale() const
|
||||||
|
{
|
||||||
|
return &fData->fDefaultLocale;
|
||||||
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BLocaleRoster::GetLanguage(const char* languageCode,
|
BLocaleRoster::GetLanguage(const char* languageCode,
|
||||||
BLanguage** _language) const
|
BLanguage** _language) const
|
||||||
@@ -211,12 +195,11 @@ BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
|
|||||||
if (!languages)
|
if (!languages)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
*languages = rosterData->fPreferredLanguages;
|
*languages = fData->fPreferredLanguages;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -367,12 +350,12 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
|
|||||||
if (countryCode == NULL)
|
if (countryCode == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
status_t status = load_resources_if_needed(rosterData);
|
BResources* resources;
|
||||||
|
status_t status = fData->GetResources(&resources);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -389,8 +372,8 @@ BLocaleRoster::GetFlagIconForCountry(BBitmap* flagIcon, const char* countryCode)
|
|||||||
normalizedCode[2] = '\0';
|
normalizedCode[2] = '\0';
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
const void* buffer = rosterData->fResources.LoadResource(
|
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
|
||||||
B_VECTOR_ICON_TYPE, normalizedCode, &size);
|
normalizedCode, &size);
|
||||||
if (buffer == NULL || size == 0)
|
if (buffer == NULL || size == 0)
|
||||||
return B_NAME_NOT_FOUND;
|
return B_NAME_NOT_FOUND;
|
||||||
|
|
||||||
@@ -407,12 +390,12 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
|
|||||||
|| languageCode[1] == '\0')
|
|| languageCode[1] == '\0')
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
status_t status = load_resources_if_needed(rosterData);
|
BResources* resources;
|
||||||
|
status_t status = fData->GetResources(&resources);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -424,8 +407,8 @@ BLocaleRoster::GetFlagIconForLanguage(BBitmap* flagIcon,
|
|||||||
normalizedCode[2] = '\0';
|
normalizedCode[2] = '\0';
|
||||||
|
|
||||||
size_t size;
|
size_t size;
|
||||||
const void* buffer = rosterData->fResources.LoadResource(
|
const void* buffer = resources->LoadResource(B_VECTOR_ICON_TYPE,
|
||||||
B_VECTOR_ICON_TYPE, normalizedCode, &size);
|
normalizedCode, &size);
|
||||||
if (buffer != NULL && size != 0) {
|
if (buffer != NULL && size != 0) {
|
||||||
return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer),
|
return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer),
|
||||||
size, flagIcon);
|
size, flagIcon);
|
||||||
@@ -450,15 +433,14 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
|
|||||||
if (languageList == NULL)
|
if (languageList == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
int32 count = rosterData->fCatalogAddOnInfos.CountItems();
|
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||||
for (int32 i = 0; i < count; ++i) {
|
for (int32 i = 0; i < count; ++i) {
|
||||||
CatalogAddOnInfo* info
|
CatalogAddOnInfo* info
|
||||||
= (CatalogAddOnInfo*)rosterData->fCatalogAddOnInfos.ItemAt(i);
|
= (CatalogAddOnInfo*)fData->fCatalogAddOnInfos.ItemAt(i);
|
||||||
|
|
||||||
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
|
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
|
||||||
continue;
|
continue;
|
||||||
@@ -474,12 +456,11 @@ BLocaleRoster::GetAvailableCatalogs(BMessage* languageList,
|
|||||||
bool
|
bool
|
||||||
BLocaleRoster::IsFilesystemTranslationPreferred() const
|
BLocaleRoster::IsFilesystemTranslationPreferred() const
|
||||||
{
|
{
|
||||||
RosterData* rosterData = RosterData::Default();
|
BAutolock lock(fData->fLock);
|
||||||
BAutolock lock(rosterData->fLock);
|
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
return rosterData->fIsFilesystemTranslationPreferred;
|
return fData->fIsFilesystemTranslationPreferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 <MutableLocaleRoster.h>
|
||||||
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <AppFileInfo.h>
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Catalog.h>
|
#include <Catalog.h>
|
||||||
#include <Collator.h>
|
#include <CatalogData.h>
|
||||||
#include <Debug.h>
|
#include <Debug.h>
|
||||||
#include <DefaultCatalog.h>
|
|
||||||
#include <Directory.h>
|
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <File.h>
|
|
||||||
#include <FindDirectory.h>
|
|
||||||
#include <FormattingConventions.h>
|
#include <FormattingConventions.h>
|
||||||
#include <Language.h>
|
#include <Language.h>
|
||||||
#include <Locale.h>
|
#include <LocaleRosterData.h>
|
||||||
#include <Node.h>
|
|
||||||
#include <Path.h>
|
|
||||||
#include <Roster.h>
|
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <TimeZone.h>
|
|
||||||
|
|
||||||
#include <ICUWrapper.h>
|
|
||||||
|
|
||||||
// ICU includes
|
|
||||||
#include <unicode/locid.h>
|
|
||||||
#include <unicode/timezone.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace BPrivate {
|
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 {
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
static const char* kPriorityAttr = "ADDON:priority";
|
static MutableLocaleRoster* sLocaleRoster;
|
||||||
|
|
||||||
static const char* kLanguageField = "language";
|
static pthread_once_t sLocaleRosterInitOnce = PTHREAD_ONCE_INIT;
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
InitializeRosterData()
|
InitializeLocaleRoster()
|
||||||
{
|
{
|
||||||
sRosterData = new (std::nothrow) RosterData(BLanguage("en_US"),
|
sLocaleRoster = new (std::nothrow) MutableLocaleRoster();
|
||||||
BFormattingConventions("en_US"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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()
|
MutableLocaleRoster::MutableLocaleRoster()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -719,7 +58,10 @@ MutableLocaleRoster::~MutableLocaleRoster()
|
|||||||
/*static*/ MutableLocaleRoster*
|
/*static*/ MutableLocaleRoster*
|
||||||
MutableLocaleRoster::Default()
|
MutableLocaleRoster::Default()
|
||||||
{
|
{
|
||||||
return &sLocaleRoster;
|
if (sLocaleRoster == NULL)
|
||||||
|
pthread_once(&sLocaleRosterInitOnce, &InitializeLocaleRoster);
|
||||||
|
|
||||||
|
return sLocaleRoster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -727,29 +69,28 @@ status_t
|
|||||||
MutableLocaleRoster::SetDefaultFormattingConventions(
|
MutableLocaleRoster::SetDefaultFormattingConventions(
|
||||||
const BFormattingConventions& newFormattingConventions)
|
const BFormattingConventions& newFormattingConventions)
|
||||||
{
|
{
|
||||||
return RosterData::Default()->SetDefaultFormattingConventions(
|
return fData->SetDefaultFormattingConventions(newFormattingConventions);
|
||||||
newFormattingConventions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
|
MutableLocaleRoster::SetDefaultTimeZone(const BTimeZone& newZone)
|
||||||
{
|
{
|
||||||
return RosterData::Default()->SetDefaultTimeZone(newZone);
|
return fData->SetDefaultTimeZone(newZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
|
MutableLocaleRoster::SetPreferredLanguages(const BMessage* languages)
|
||||||
{
|
{
|
||||||
return RosterData::Default()->SetPreferredLanguages(languages);
|
return fData->SetPreferredLanguages(languages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MutableLocaleRoster::SetFilesystemTranslationPreferred(bool preferred)
|
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)
|
if (!type || !signature || !language)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
BAutolock lock(RosterData::Default()->fLock);
|
BAutolock lock(fData->fLock);
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||||
for (int32 i = 0; i < count; ++i) {
|
for (int32 i = 0; i < count; ++i) {
|
||||||
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
||||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
|
fData->fCatalogAddOnInfos.ItemAt(i);
|
||||||
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|
if (info->fName.ICompare(type)!=0 || !info->MakeSureItsLoaded()
|
||||||
|| !info->fCreateFunc)
|
|| !info->fCreateFunc)
|
||||||
continue;
|
continue;
|
||||||
@@ -838,14 +179,14 @@ BCatalogData*
|
|||||||
MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner,
|
MutableLocaleRoster::LoadCatalog(const entry_ref& catalogOwner,
|
||||||
const char* language, int32 fingerprint) const
|
const char* language, int32 fingerprint) const
|
||||||
{
|
{
|
||||||
BAutolock lock(RosterData::Default()->fLock);
|
BAutolock lock(fData->fLock);
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||||
for (int32 i = 0; i < count; ++i) {
|
for (int32 i = 0; i < count; ++i) {
|
||||||
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
CatalogAddOnInfo* info = (CatalogAddOnInfo*)
|
||||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i);
|
fData->fCatalogAddOnInfos.ItemAt(i);
|
||||||
|
|
||||||
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
|
if (!info->MakeSureItsLoaded() || !info->fInstantiateFunc)
|
||||||
continue;
|
continue;
|
||||||
@@ -909,7 +250,7 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
|
|||||||
if (!catalog)
|
if (!catalog)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
BAutolock lock(RosterData::Default()->fLock);
|
BAutolock lock(fData->fLock);
|
||||||
if (!lock.IsLocked())
|
if (!lock.IsLocked())
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
@@ -918,10 +259,10 @@ MutableLocaleRoster::UnloadCatalog(BCatalogData* catalog)
|
|||||||
|
|
||||||
while (catalog != NULL) {
|
while (catalog != NULL) {
|
||||||
nextCatalog = catalog->Next();
|
nextCatalog = catalog->Next();
|
||||||
int32 count = RosterData::Default()->fCatalogAddOnInfos.CountItems();
|
int32 count = fData->fCatalogAddOnInfos.CountItems();
|
||||||
for (int32 i = 0; i < count; ++i) {
|
for (int32 i = 0; i < count; ++i) {
|
||||||
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
|
CatalogAddOnInfo* info = static_cast<CatalogAddOnInfo*>(
|
||||||
RosterData::Default()->fCatalogAddOnInfos.ItemAt(i));
|
fData->fCatalogAddOnInfos.ItemAt(i));
|
||||||
if (info->fLoadedCatalogs.HasItem(catalog)) {
|
if (info->fLoadedCatalogs.HasItem(catalog)) {
|
||||||
info->fLoadedCatalogs.RemoveItem(catalog);
|
info->fLoadedCatalogs.RemoveItem(catalog);
|
||||||
delete catalog;
|
delete catalog;
|
||||||
|
|||||||
Reference in New Issue
Block a user