* Changed BLocaleRoster::GetLanguage() to a signature that makes more sense,

and looks more like the rest of the API.
* Also, it will now return an appropriate error code if the language couldn't
  be allocated (anything else than B_OK is an improvement :-)).
* Several changes in BLanguage:
  - GetName() now gets a BString reference, also
  - it now returns the name in its own language, ie. for German this would
    always be "deutsch", no matter the current language settings, and finally,
  - it now empties the string it gets before adding the name.
  - added GetTranslatedName() that behaves like the previous version.
  - added const where it made sense (ie. almost everywhere).
  - Code() now returns the code of the language only.
  - ID() now returns the full ID of this language, ie. including country,
    variant, and keywords if any.
  - added Country(), and Variant().
  - renamed IsCountry() to IsCountrySpecific().
  - added IsVariant().
* Cleaned up Language.h, minor cleanup in LocaleRoster.cpp.
* Removed the whole move item logic from LanguageListView; while this was not
  only spaghetti code, it doesn't make much sense in the first place.
* Instead of removing stuff from the left, and even worse, moving all countries
  for a language even if only one had been dragged, we now only mark the items
  that are already in the preferred list, and only those.
* Fixed various mixups of FullList*() vs. *() methods that could lead to things
  like bug #5896.
* Pressing the delete key in the preferred list view will now remove the
  language.
* Moved LocaleWindow specific message constants to LocaleWindow.cpp; Locale.h
  is supposed to contain application wide constants.
* The drop logic is now in LocaleWindow.
* We now make sure that each base language can only be in the list once.
* Lots of cleanup, even though I mostly replaced spaghettie code with different
  looking spaghettie code - still, I think things have slightly improved.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36727 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-05-07 17:38:40 +00:00
parent 8da96bede1
commit 96eaa02e8f
10 changed files with 728 additions and 532 deletions

View File

@ -1,16 +1,14 @@
/*
** Copyright 2003, Haiku, Inc.
** Distributed under the terms of the MIT License.
*/
* Copyright 2003-2010, Haiku, Inc.
* Distributed under the terms of the MIT License.
*/
#ifndef _LANGUAGE_H_
#define _LANGUAGE_H_
#include <LocaleStrings.h>
#include <String.h>
#include <SupportDefs.h>
#include <LocaleStrings.h>
// We must not include the icu headers in there as it could mess up binary
@ -28,29 +26,37 @@ enum script_direction {
class BLanguage {
public:
~BLanguage();
public:
~BLanguage();
// language name, e.g. "english", "deutsch"
status_t GetName(BString* name);
// ISO-639 language code, e.g. "en", "de"
const char* Code();
bool IsCountry();
status_t GetName(BString& name) const;
status_t GetTranslatedName(BString& name) const;
uint8 Direction() const;
// ISO-639 language code, e.g. "en", "de"
const char* Code() const;
const char* Country() const;
const char* Variant() const;
const char* ID() const;
// see definitions below
const char *GetString(uint32 id) const;
bool IsCountrySpecific() const;
bool IsVariant() const;
private:
friend class BLocaleRoster;
uint8 Direction() const;
BLanguage(const char *language);
void Default();
// see definitions below
const char* GetString(uint32 id) const;
char *fStrings[B_NUM_LANGUAGE_STRINGS];
uint8 fDirection;
icu_4_2::Locale* fICULocale;
private:
friend class BLocaleRoster;
BLanguage(const char *language);
void Default();
private:
char* fStrings[B_NUM_LANGUAGE_STRINGS];
uint8 fDirection;
icu_4_2::Locale* fICULocale;
};
#endif /* _LANGUAGE_H_ */
#endif // _LANGUAGE_H_

View File

@ -1,3 +1,7 @@
/*
* Copyright 2003-2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT license.
*/
#ifndef _LOCALE_ROSTER_H_
#define _LOCALE_ROSTER_H_
@ -17,7 +21,7 @@ struct entry_ref;
namespace BPrivate {
class EditableCatalog;
};
}
enum {
B_LOCALE_CHANGED = '_LCC',
@ -25,7 +29,6 @@ enum {
class BLocaleRoster {
public:
BLocaleRoster();
~BLocaleRoster();
@ -42,7 +45,8 @@ class BLocaleRoster {
status_t GetDefaultCountry(BCountry **) const;
void SetDefaultCountry(BCountry *) const;
status_t GetLanguage(BLanguage** language, BString languageCode) const;
status_t GetLanguage(const char* languageCode,
BLanguage** _language) const;
status_t GetPreferredLanguages(BMessage *) const;
status_t SetPreferredLanguages(BMessage *);

View File

@ -80,10 +80,7 @@ static const char *gBuiltInStrings[] = {
};
// #pragma mark -
BLanguage::BLanguage(const char *language)
BLanguage::BLanguage(const char* language)
:
fDirection(B_LEFT_TO_RIGHT)
{
@ -123,10 +120,11 @@ BLanguage::Direction() const
}
const char *
const char*
BLanguage::GetString(uint32 id) const
{
if (id < B_LANGUAGE_STRINGS_BASE || id > B_LANGUAGE_STRINGS_BASE + B_NUM_LANGUAGE_STRINGS)
if (id < B_LANGUAGE_STRINGS_BASE
|| id > B_LANGUAGE_STRINGS_BASE + B_NUM_LANGUAGE_STRINGS)
return NULL;
return fStrings[id - B_LANGUAGE_STRINGS_BASE];
@ -134,30 +132,84 @@ BLanguage::GetString(uint32 id) const
status_t
BLanguage::GetName(BString* name)
BLanguage::GetName(BString& name) const
{
BMessage preferredLanguage;
be_locale_roster->GetPreferredLanguages(&preferredLanguage);
BString appLanguage;
preferredLanguage.FindString("language", 0, &appLanguage);
UnicodeString s;
fICULocale->getDisplayName(Locale(appLanguage), s);
BStringByteSink converter(name);
s.toUTF8(converter);
UnicodeString string;
fICULocale->getDisplayName(*fICULocale, string);
name.Truncate(0);
BStringByteSink converter(&name);
string.toUTF8(converter);
return B_OK;
}
status_t
BLanguage::GetTranslatedName(BString& name) const
{
BMessage preferredLanguage;
be_locale_roster->GetPreferredLanguages(&preferredLanguage);
BString appLanguage;
preferredLanguage.FindString("language", 0, &appLanguage);
UnicodeString string;
fICULocale->getDisplayName(Locale(appLanguage), string);
name.Truncate(0);
BStringByteSink converter(&name);
string.toUTF8(converter);
return B_OK;
}
const char*
BLanguage::Code()
BLanguage::Code() const
{
return fICULocale->getLanguage();
}
bool
BLanguage::IsCountry()
const char*
BLanguage::Country() const
{
return *(fICULocale->getCountry()) != '\0';
const char* country = fICULocale->getCountry();
if (country == NULL || country[0] == '\0')
return NULL;
return country;
}
const char*
BLanguage::Variant() const
{
const char* variant = fICULocale->getVariant();
if (variant == NULL || variant[0] == '\0')
return NULL;
return variant;
}
const char*
BLanguage::ID() const
{
return fICULocale->getName();
}
bool
BLanguage::IsCountrySpecific() const
{
return Country() != NULL;
}
bool
BLanguage::IsVariant() const
{
return Variant() != NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2004, Haiku. All rights reserved.
* Copyright 2003-2010, Haiku. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -37,8 +37,35 @@
#include <unicode/locid.h>
/*
* several attributes/resource-IDs used within the Locale Kit:
*/
static const char *kPriorityAttr = "ADDON:priority";
const char *BLocaleRoster::kCatLangAttr = "BEOS:LOCALE_LANGUAGE";
// name of catalog language, lives in every catalog file
const char *BLocaleRoster::kCatSigAttr = "BEOS:LOCALE_SIGNATURE";
// catalog signature, lives in every catalog file
const char *BLocaleRoster::kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT";
// catalog fingerprint, may live in catalog file
const char *BLocaleRoster::kCatManagerMimeType
= "application/x-vnd.Be.locale.catalog-manager";
// signature of catalog managing app
const char *BLocaleRoster::kCatEditorMimeType
= "application/x-vnd.Be.locale.catalog-editor";
// signature of catalog editor app
const char *BLocaleRoster::kEmbeddedCatAttr = "BEOS:LOCALE_EMBEDDED_CATALOG";
// attribute which contains flattened data of embedded catalog
// this may live in an app- or add-on-file
int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
// a unique value used to identify the resource (=> embedded CAtalog DAta)
// which contains flattened data of embedded catalog.
// this may live in an app- or add-on-file
typedef BCatalogAddOn *(*InstantiateCatalogFunc)(const char *name,
const char *language, uint32 fingerprint);
@ -47,7 +74,7 @@ typedef BCatalogAddOn *(*CreateCatalogFunc)(const char *name,
typedef BCatalogAddOn *(*InstantiateEmbeddedCatalogFunc)(
entry_ref *appOrAddOnRef);
typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*,
const char*, int32);
@ -211,7 +238,7 @@ RosterData::RosterData()
Locale::setDefault(icuLocale,icuError);
assert(icuError == U_ZERO_ERROR);
fPreferredLanguages.RemoveName("language");
for (int i = 0; settingsMessage.FindString("language", i,
for (int i = 0; settingsMessage.FindString("language", i,
&langName) == B_OK; i++) {
fPreferredLanguages.AddString("language", langName);
}
@ -310,7 +337,7 @@ RosterData::InitializeCatalogAddOns()
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
// add-on has no priority-attribute yet, so we load it
// to fetch the priority from the corresponding
// symbol...
BString fullAddOnPath(addOnFolderName);
@ -385,34 +412,9 @@ RosterData::CleanupCatalogAddOns()
}
/*
* several attributes/resource-IDs used within the Locale Kit:
*/
const char *BLocaleRoster::kCatLangAttr = "BEOS:LOCALE_LANGUAGE";
// name of catalog language, lives in every catalog file
const char *BLocaleRoster::kCatSigAttr = "BEOS:LOCALE_SIGNATURE";
// catalog signature, lives in every catalog file
const char *BLocaleRoster::kCatFingerprintAttr = "BEOS:LOCALE_FINGERPRINT";
// catalog fingerprint, may live in catalog file
// #pragma mark - BLocaleRoster
const char *BLocaleRoster::kCatManagerMimeType
= "application/x-vnd.Be.locale.catalog-manager";
// signature of catalog managing app
const char *BLocaleRoster::kCatEditorMimeType
= "application/x-vnd.Be.locale.catalog-editor";
// signature of catalog editor app
const char *BLocaleRoster::kEmbeddedCatAttr = "BEOS:LOCALE_EMBEDDED_CATALOG";
// attribute which contains flattened data of embedded catalog
// this may live in an app- or add-on-file
int32 BLocaleRoster::kEmbeddedCatResId = 0xCADA;
// a unique value used to identify the resource (=> embedded CAtalog DAta)
// which contains flattened data of embedded catalog.
// this may live in an app- or add-on-file
/*
* BLocaleRoster, the exported interface to the locale roster data:
*/
BLocaleRoster::BLocaleRoster()
{
}
@ -473,17 +475,23 @@ BLocaleRoster::GetDefaultCountry(BCountry **country) const
status_t
BLocaleRoster::GetLanguage(BLanguage **language, BString languageCode) const
BLocaleRoster::GetLanguage(const char* languageCode,
BLanguage** _language) const
{
if (!language)
if (_language == NULL || languageCode == NULL || languageCode[0] == '\0')
return B_BAD_VALUE;
*language = new(std::nothrow) BLanguage(languageCode);
BLanguage* language = new(std::nothrow) BLanguage(languageCode);
if (language == NULL)
return B_NO_MEMORY;
*_language = language;
return B_OK;
}
void
BLocaleRoster::SetDefaultCountry(BCountry * newDefault) const
BLocaleRoster::SetDefaultCountry(BCountry* newDefault) const
{
gRosterData.fCountryCodeName = newDefault->Code();
newDefault->DateFormat(gRosterData.fCountryDateFormat, true);
@ -491,7 +499,7 @@ BLocaleRoster::SetDefaultCountry(BCountry * newDefault) const
status_t
BLocaleRoster::GetPreferredLanguages(BMessage *languages) const
BLocaleRoster::GetPreferredLanguages(BMessage* languages) const
{
if (!languages)
return B_BAD_VALUE;
@ -548,7 +556,7 @@ BLocaleRoster::GetInstalledCatalogs(BMessage * languageList, const char* sigPatt
{
if (languageList == NULL)
return B_BAD_VALUE;
int32 count = gRosterData.fCatalogAddOnInfos.CountItems();
for (int32 i = 0; i < count; ++i) {
BCatalogAddOnInfo *info
@ -556,11 +564,11 @@ BLocaleRoster::GetInstalledCatalogs(BMessage * languageList, const char* sigPatt
if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc)
continue;
info->fLanguagesFunc(languageList, sigPattern, langPattern,
fingerprint);
}
return B_OK;
}

View File

@ -9,16 +9,15 @@ Preference Locale :
Locale.cpp
LocaleWindow.cpp
TimeFormatSettingsView.cpp
: be liblocale.so $(TARGET_LIBSTDC++) $(TARGET_LIBSUPC++) libicu-common.so
libicu-data.so libshared.a
: Locale.rdef
;
;
DoCatalogs Locale # application name
: x-vnd.Haiku-Locale # app MIME signature
: # sources to extract the keys from
DoCatalogs Locale : x-vnd.Haiku-Locale :
LanguageListView.cpp
Locale.cpp
LocaleWindow.cpp
TimeFormatSettingsView.cpp
;

View File

@ -5,6 +5,7 @@
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Adrien Destugues <pulkomandy@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Oliver Tappe <zooey@hirschkaefer.de>
*/
@ -17,31 +18,46 @@
#include <Bitmap.h>
#include <Country.h>
#include "Locale.h"
#include <Catalog.h>
#include <Window.h>
#define MAX_DRAG_HEIGHT 200.0
#define ALPHA 170
#define TEXT_OFFSET 5.0
#define TR_CONTEXT "LanguageListView"
LanguageListItem::LanguageListItem(const char* text, const char* code)
LanguageListItem::LanguageListItem(const char* text, const char* id,
const char* code)
:
BStringItem(text),
fLanguageCode(code)
fID(id),
fCode(code)
{
// TODO: should probably keep the BCountry as a member of the class
BCountry myCountry(code);
BRect bounds(0, 0, 15, 15);
fIcon = new(std::nothrow) BBitmap(bounds, B_RGBA32);
if (fIcon && myCountry.GetIcon(fIcon) != B_OK) {
BCountry country(id);
fIcon = new(std::nothrow) BBitmap(BRect(0, 0, 15, 15), B_RGBA32);
if (fIcon != NULL && country.GetIcon(fIcon) != B_OK) {
delete fIcon;
fIcon = NULL;
}
}
LanguageListItem::LanguageListItem(const LanguageListItem& other)
:
BStringItem(other.Text()),
fID(other.ID()),
fCode(other.Code()),
fIcon(NULL)
{
if (other.fIcon != NULL)
fIcon = new BBitmap(*other.fIcon);
}
LanguageListItem::~LanguageListItem()
{
delete fIcon;
@ -51,10 +67,8 @@ LanguageListItem::~LanguageListItem()
void
LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
{
rgb_color kHighlight = { 140,140,140,0 };
rgb_color kBlack = { 0,0,0,0 };
BRect r(frame);
rgb_color kHighlight = {140, 140, 140, 0};
rgb_color kBlack = {0, 0, 0, 0};
if (IsSelected() || complete) {
rgb_color color;
@ -64,33 +78,43 @@ LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
color = owner->ViewColor();
owner->SetHighColor(color);
owner->SetLowColor(color);
owner->FillRect(r);
owner->FillRect(frame);
owner->SetHighColor(kBlack);
} else
owner->SetLowColor(owner->ViewColor());
frame.left += 4;
BRect iconFrame(frame);
iconFrame.Set(iconFrame.left, iconFrame.top+1, iconFrame.left+15,
iconFrame.top+16);
iconFrame.Set(iconFrame.left, iconFrame.top + 1, iconFrame.left + 15,
iconFrame.top + 16);
if (fIcon && fIcon->IsValid()) {
if (fIcon != NULL && fIcon->IsValid()) {
owner->SetDrawingMode(B_OP_OVER);
owner->DrawBitmap(fIcon, iconFrame);
owner->SetDrawingMode(B_OP_COPY);
}
frame.left += 16 * (OutlineLevel() + 1);
owner->SetHighColor(kBlack);
BString text = Text();
if (IsEnabled())
owner->SetHighColor(kBlack);
else {
owner->SetHighColor(tint_color(owner->LowColor(), B_DARKEN_3_TINT));
text += " (";
text += B_TRANSLATE("already chosen");
text += ")";
}
BFont font = be_plain_font;
font_height finfo;
font.GetHeight(&finfo);
owner->SetFont(&font);
owner->MovePenTo(frame.left+8, frame.top + ((frame.Height() - (finfo.ascent
+ finfo.descent + finfo.leading)) / 2) + (finfo.ascent
+ finfo.descent) - 1);
owner->DrawString(Text());
// TODO: the position is unnecessarily complicated, and not correct either
owner->MovePenTo(frame.left + 8, frame.top
+ (frame.Height() - (finfo.ascent + finfo.descent + finfo.leading)) / 2
+ (finfo.ascent + finfo.descent) - 1);
owner->DrawString(text.String());
}
@ -100,14 +124,66 @@ LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete)
LanguageListView::LanguageListView(const char* name, list_view_type type)
:
BOutlineListView(name, type),
fMsgPrefLanguagesChanged(new BMessage(kMsgPrefLanguagesChanged))
fDeleteMessage(NULL),
fDragMessage(NULL)
{
}
LanguageListView::~LanguageListView()
{
delete fMsgPrefLanguagesChanged;
}
LanguageListItem*
LanguageListView::ItemForLanguageID(const char* id, int32* _index) const
{
for (int32 index = 0; index < FullListCountItems(); index++) {
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
if (item->ID() == id) {
if (_index != NULL)
*_index = index;
return item;
}
}
return NULL;
}
LanguageListItem*
LanguageListView::ItemForLanguageCode(const char* code, int32* _index) const
{
for (int32 index = 0; index < FullListCountItems(); index++) {
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
if (item->Code() == code) {
if (_index != NULL)
*_index = index;
return item;
}
}
return NULL;
}
void
LanguageListView::SetDeleteMessage(BMessage* message)
{
delete fDeleteMessage;
fDeleteMessage = message;
}
void
LanguageListView::SetDragMessage(BMessage* message)
{
delete fDragMessage;
fDragMessage = message;
}
@ -119,302 +195,141 @@ LanguageListView::AttachedToWindow()
}
void
LanguageListView::MoveItems(BList& items, int32 index)
{
// TODO : only allow moving top level item around other top level
// or sublevels within the same top level
DeselectAll();
// collect all items that must be moved (adding subitems as necessary)
int32 count = items.CountItems();
BList itemsToBeMoved;
for (int32 i = 0; i < count; i++) {
BListItem* item = (BListItem*)items.ItemAt(i);
itemsToBeMoved.AddItem(item);
if (item->OutlineLevel() == 0) {
// add all subitems, as they need to be moved, too
int32 subItemCount = CountItemsUnder(item, true);
for (int subIndex = 0; subIndex < subItemCount ; subIndex++)
itemsToBeMoved.AddItem(ItemUnderAt(item, true, subIndex));
}
}
// now remove all the items backwards (in order to remove children before
// their parent), decreasing target index if we are removing items before
// it
count = itemsToBeMoved.CountItems();
for (int32 i = count - 1; i >= 0; i--) {
BListItem* item = (BListItem*)itemsToBeMoved.ItemAt(i);
int32 removeIndex = FullListIndexOf(item);
if (RemoveItem(item)) {
if (removeIndex < index)
index--;
}
}
// finally add all the items at the given index
for (int32 i = 0; i < count; i++) {
BListItem* item = (BListItem*)itemsToBeMoved.ItemAt(i);
if (AddItem(item, index))
index++;
else
delete item;
}
}
void
LanguageListView::MessageReceived(BMessage* message)
{
if (message->what == 'DRAG') {
if (message->WasDropped() && _AcceptsDragMessage(message)) {
// Someone just dropped something on us
LanguageListView* list = NULL;
if (message->FindPointer("list", (void**)&list) == B_OK) {
// It comes from a list
int32 count = CountItems();
if (fDropIndex < 0 || fDropIndex > count)
fDropIndex = count;
BMessage dragMessage(*message);
dragMessage.AddInt32("drop_index", fDropIndex);
dragMessage.AddPointer("drop_target", this);
if (list == this) {
// It comes from ourselves : move the item around in the list
BList items;
int32 index;
for (int32 i = 0;
message->FindInt32("index", i, &index) == B_OK; i++) {
if (BListItem* item = FullListItemAt(index))
items.AddItem((void*)item);
}
if (items.CountItems() > 0) {
// There is something to move
LanguageListItem* parent = static_cast<LanguageListItem*>(
Superitem(static_cast<LanguageListItem*>(
items.FirstItem())));
if (parent) {
// item has a parent - it should then stay
// below it
if (Superitem(FullListItemAt(fDropIndex - 1)) == parent
|| FullListItemAt(fDropIndex - 1) == parent)
MoveItems(items, fDropIndex);
} else {
// item is top level and should stay so.
if (Superitem(FullListItemAt(fDropIndex - 1)) == NULL)
MoveItems(items, fDropIndex);
else {
int itemCount = CountItemsUnder(
FullListItemAt(fDropIndex), true);
MoveItems(items, FullListIndexOf(Superitem(
FullListItemAt(fDropIndex - 1))
+ itemCount));
}
}
}
fDropIndex = -1;
} else {
// It comes from another list : move it here
// ensure we always drop things at top-level and not
// in the middle of another outline
if (Superitem(FullListItemAt(fDropIndex))) {
// Item has a parent
fDropIndex = FullListIndexOf(Superitem(FullListItemAt(
fDropIndex)));
}
// Item is now a top level one - we must insert just below its
// last child
fDropIndex += CountItemsUnder(FullListItemAt(fDropIndex), true)
+ 1;
int32 indexCount;
type_code dummy;
if (message->GetInfo("index", &dummy, &indexCount) == B_OK) {
for (int32 i = indexCount - 1; i >= 0; i--) {
int32 index;
if (message->FindInt32("index", i, &index) == B_OK)
MoveItemFrom(list, index, fDropIndex);
}
}
fDropIndex = -1;
}
Invoke(fMsgPrefLanguagesChanged);
}
Invoke(&dragMessage);
} else
BOutlineListView::MessageReceived(message);
}
void
LanguageListView::MoveItemFrom(BOutlineListView* origin, int32 index,
int32 dropSpot)
{
// Check that the node we are going to move is a top-level one.
// If not, we want its parent instead
LanguageListItem* itemToMove = static_cast<LanguageListItem*>(
origin->Superitem(origin->FullListItemAt(index)));
if (itemToMove == NULL) {
itemToMove = static_cast<LanguageListItem*>(
origin->FullListItemAt(index));
if (itemToMove == NULL)
return;
} else
index = origin->FullListIndexOf(itemToMove);
// collect all items that must be moved (adding subitems as necessary)
BList itemsToBeMoved;
itemsToBeMoved.AddItem(itemToMove);
// add all subitems, as they need to be moved, too
int32 subItemCount = origin->CountItemsUnder(itemToMove, true);
for (int32 subIndex = 0; subIndex < subItemCount; subIndex++) {
itemsToBeMoved.AddItem(origin->ItemUnderAt(itemToMove, true,
subIndex));
}
// now remove all items from origin in reverse order (to remove the children
// before the parent) ...
// TODO: using RemoveItem() on the parent will delete the subitems, which
// may be a bug, actually.
int32 itemCount = itemsToBeMoved.CountItems();
for (int32 i = itemCount - 1; i >= 0; i--)
origin->RemoveItem(index + i);
// ... and add all the items to this list
AddList(&itemsToBeMoved, dropSpot);
}
bool
LanguageListView::InitiateDrag(BPoint point, int32 index, bool)
LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
bool /*wasSelected*/)
{
bool success = false;
if (fDragMessage == NULL)
return false;
BListItem* item = FullListItemAt(CurrentSelection(0));
if (!item) {
if (item == NULL) {
// workaround for a timing problem
Select(index);
item = FullListItemAt(index);
// TODO: this should support extending the selection
item = ItemAt(dragIndex);
Select(dragIndex);
}
if (item) {
// create drag message
BMessage msg('DRAG');
msg.AddPointer("list", (void*)(this));
// first selection round, consider only superitems
int32 index;
for (int32 i = 0; (index = FullListCurrentSelection(i)) >= 0; i++) {
BListItem* item = FullListItemAt(index);
if (item == NULL)
return false;
if (item->OutlineLevel() == 0)
msg.AddInt32("index", index);
}
if (!msg.HasInt32("index")) {
// second selection round, consider only subitems of the same
// (i.e. the first) parent
BListItem* seenSuperItem = NULL;
for (int32 i = 0; (index = FullListCurrentSelection(i)) >= 0; i++) {
BListItem* item = FullListItemAt(index);
if (item == NULL)
return false;
if (item->OutlineLevel() != 0) {
BListItem* superItem = Superitem(item);
if (seenSuperItem == NULL)
seenSuperItem = superItem;
if (superItem == seenSuperItem)
msg.AddInt32("index", index);
else
break;
}
}
}
if (item == NULL)
return false;
// figure out drag rect
float width = Bounds().Width();
BRect dragRect(0.0, 0.0, width, -1.0);
// figure out, how many items fit into our bitmap
bool fade = false;
int32 numItems;
int32 currIndex;
BListItem* item;
for (numItems = 0;
msg.FindInt32("index", numItems, &currIndex) == B_OK
&& (item = FullListItemAt(currIndex)) != NULL; numItems++) {
dragRect.bottom += ceilf(item->Height()) + 1.0;
if (dragRect.Height() > MAX_DRAG_HEIGHT) {
fade = true;
dragRect.bottom = MAX_DRAG_HEIGHT;
numItems++;
break;
}
// create drag message
BMessage message = *fDragMessage;
message.AddPointer("listview", this);
for (int32 i = 0;; i++) {
int32 index = FullListCurrentSelection(i);
if (index < 0)
break;
message.AddInt32("index", index);
}
// figure out drag rect
BRect dragRect(0.0, 0.0, Bounds().Width(), -1.0);
int32 numItems = 0;
bool fade = false;
// figure out, how many items fit into our bitmap
for (int32 i = 0, index; message.FindInt32("index", i, &index) == B_OK;
i++) {
BListItem* item = FullListItemAt(index);
if (item == NULL)
break;
dragRect.bottom += ceilf(item->Height()) + 1.0;
numItems++;
if (dragRect.Height() > MAX_DRAG_HEIGHT) {
dragRect.bottom = MAX_DRAG_HEIGHT;
fade = true;
break;
}
BBitmap* dragBitmap = new BBitmap(dragRect, B_RGB32, true);
if (dragBitmap && dragBitmap->IsValid()) {
BView* v = new BView(dragBitmap->Bounds(), "helper", B_FOLLOW_NONE,
B_WILL_DRAW);
dragBitmap->AddChild(v);
dragBitmap->Lock();
BRect itemBounds(dragRect) ;
itemBounds.bottom = 0.0;
// let all selected items, that fit into our drag_bitmap, draw
for (int32 i = 0; i < numItems; i++) {
int32 index = msg.FindInt32("index", i);
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
if (itemBounds.bottom > dragRect.bottom)
itemBounds.bottom = dragRect.bottom;
item->DrawItem(v, itemBounds);
itemBounds.top = itemBounds.bottom + 1.0;
}
// make a black frame arround the edge
v->SetHighColor(0, 0, 0, 255);
v->StrokeRect(v->Bounds());
v->Sync();
}
uint8* bits = (uint8*)dragBitmap->Bits();
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
int32 bpr = dragBitmap->BytesPerRow();
BBitmap* dragBitmap = new BBitmap(dragRect, B_RGB32, true);
if (dragBitmap->IsValid()) {
BView* view = new BView(dragBitmap->Bounds(), "helper", B_FOLLOW_NONE,
B_WILL_DRAW);
dragBitmap->AddChild(view);
dragBitmap->Lock();
BRect itemBounds(dragRect) ;
itemBounds.bottom = 0.0;
// let all selected items, that fit into our drag_bitmap, draw
for (int32 i = 0; i < numItems; i++) {
int32 index = message.FindInt32("index", i);
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
if (itemBounds.bottom > dragRect.bottom)
itemBounds.bottom = dragRect.bottom;
item->DrawItem(view, itemBounds);
itemBounds.top = itemBounds.bottom + 1.0;
}
// make a black frame arround the edge
view->SetHighColor(0, 0, 0, 255);
view->StrokeRect(view->Bounds());
view->Sync();
if (fade) {
for (int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
for (int32 y = height - ALPHA / 2; y < height;
y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = (height - y) << 1;
}
} else {
for (int32 y = 0; y < height; y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
uint8* bits = (uint8*)dragBitmap->Bits();
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
int32 bpr = dragBitmap->BytesPerRow();
if (fade) {
for (int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
for (int32 y = height - ALPHA / 2; y < height;
y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = (height - y) << 1;
}
dragBitmap->Unlock();
} else {
delete dragBitmap;
dragBitmap = NULL;
for (int32 y = 0; y < height; y++, bits += bpr) {
uint8* line = bits + 3;
for (uint8* end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
}
if (dragBitmap)
DragMessage(&msg, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0));
else
DragMessage(&msg, dragRect.OffsetToCopy(point), this);
success = true;
dragBitmap->Unlock();
} else {
delete dragBitmap;
dragBitmap = NULL;
}
return success;
if (dragBitmap != NULL)
DragMessage(&message, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0));
else
DragMessage(&message, dragRect.OffsetToCopy(point), this);
return true;
}
void
LanguageListView::MouseMoved(BPoint where, uint32 transit, const BMessage* msg)
LanguageListView::MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
if (msg && msg->what == 'DRAG') {
if (dragMessage != NULL && _AcceptsDragMessage(dragMessage)) {
switch (transit) {
case B_ENTERED_VIEW:
case B_INSIDE_VIEW:
@ -455,5 +370,26 @@ LanguageListView::MouseMoved(BPoint where, uint32 transit, const BMessage* msg)
}
}
} else
BOutlineListView::MouseMoved(where, transit, msg);
BOutlineListView::MouseMoved(where, transit, dragMessage);
}
void
LanguageListView::KeyDown(const char* bytes, int32 numBytes)
{
if (bytes[0] == B_DELETE && fDeleteMessage != NULL) {
Invoke(fDeleteMessage);
return;
}
BOutlineListView::KeyDown(bytes, numBytes);
}
bool
LanguageListView::_AcceptsDragMessage(const BMessage* message) const
{
LanguageListView* sourceView = NULL;
return message != NULL
&& message->FindPointer("listview", (void**)&sourceView) == B_OK;
}

View File

@ -5,6 +5,7 @@
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Adrien Destugues <pulkomandy@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Oliver Tappe <zooey@hirschkaefer.de>
*/
#ifndef LANGUAGE_LIST_VIEW_H
@ -19,15 +20,19 @@
class LanguageListItem : public BStringItem {
public:
LanguageListItem(const char* text,
const char* code);
const char* id, const char* code);
LanguageListItem(const LanguageListItem& other);
virtual ~LanguageListItem();
const BString& LanguageCode() { return fLanguageCode; }
void DrawItem(BView* owner, BRect frame,
const BString& ID() const { return fID; }
const BString& Code() const { return fCode; }
virtual void DrawItem(BView* owner, BRect frame,
bool complete = false);
private:
BString fLanguageCode;
BString fID;
BString fCode;
BBitmap* fIcon;
};
@ -38,18 +43,29 @@ public:
list_view_type type);
virtual ~LanguageListView();
bool InitiateDrag(BPoint point, int32 index,
LanguageListItem* ItemForLanguageID(const char* code,
int32* _index = NULL) const;
LanguageListItem* ItemForLanguageCode(const char* code,
int32* _index = NULL) const;
void SetDeleteMessage(BMessage* message);
void SetDragMessage(BMessage* message);
virtual bool InitiateDrag(BPoint point, int32 index,
bool wasSelected);
void MouseMoved(BPoint where, uint32 transit,
const BMessage* msg);
void MoveItems(BList& items, int32 index);
void MoveItemFrom(BOutlineListView* origin, int32 index,
int32 dropSpot = 0);
void AttachedToWindow();
void MessageReceived (BMessage* message);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
virtual void KeyDown(const char* bytes, int32 numBytes);
private:
bool _AcceptsDragMessage(const BMessage* message) const;
private:
int32 fDropIndex;
BMessage* fMsgPrefLanguagesChanged;
BMessage* fDeleteMessage;
BMessage* fDragMessage;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LOCALE_H
@ -11,13 +11,7 @@
extern const char* kSignature;
static const uint32 kMsgCountrySelection = 'csel';
static const uint32 kMsgSettingsChanged = 'SeCh';
static const uint32 kMsgPrefLanguagesChanged = 'lang';
static const uint32 kMsgLangInvoked = 'laiv';
static const uint32 kMsgPrefLangInvoked = 'pliv';
static const uint32 kMsgDefaults = 'dflt';
static const uint32 kMsgRevert = 'revt';
#endif /* LOCALE_H */

View File

@ -15,6 +15,7 @@
#include <Application.h>
#include <Button.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <GroupLayout.h>
#include <LayoutBuilder.h>
#include <Locale.h>
@ -23,6 +24,7 @@
#include <ScrollView.h>
#include <StringView.h>
#include <TabView.h>
#include <UnicodeChar.h>
#include <ICUWrapper.h>
@ -35,6 +37,18 @@
#define TR_CONTEXT "Locale Preflet Window"
static const uint32 kMsgLanguageInvoked = 'LaIv';
static const uint32 kMsgLanguageDragged = 'LaDr';
static const uint32 kMsgPreferredLanguageInvoked = 'PLIv';
static const uint32 kMsgPreferredLanguageDragged = 'PLDr';
static const uint32 kMsgPreferredLanguageDeleted = 'PLDl';
static const uint32 kMsgCountrySelection = 'csel';
static const uint32 kMsgDefaults = 'dflt';
static const uint32 kMsgRevert = 'revt';
static const uint32 kMsgPreferredLanguagesChanged = 'lang';
static int
compare_typed_list_items(const BListItem* _a, const BListItem* _b)
{
@ -50,26 +64,19 @@ compare_typed_list_items(const BListItem* _a, const BListItem* _b)
LocaleWindow::LocaleWindow()
:
BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_NOT_RESIZABLE
| B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS
| B_QUIT_ON_WINDOW_CLOSE),
fMsgPrefLanguagesChanged(new BMessage(kMsgPrefLanguagesChanged))
BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE
| B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
{
BCountry* defaultCountry;
be_locale_roster->GetDefaultCountry(&defaultCountry);
SetLayout(new BGroupLayout(B_HORIZONTAL));
BButton* button = new BButton(B_TRANSLATE("Defaults"),
new BMessage(kMsgDefaults));
fRevertButton = new BButton(B_TRANSLATE("Revert"),
new BMessage(kMsgRevert));
fRevertButton->SetEnabled(false);
float spacing = be_control_look->DefaultItemSpacing();
BTabView* tabView = new BTabView("tabview");
BView* languageTab = new BView(B_TRANSLATE("Language"), B_WILL_DRAW);
languageTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
BGroupView* languageTab = new BGroupView(B_TRANSLATE("Language"),
B_HORIZONTAL, spacing);
// first list: available languages
fLanguageListView = new LanguageListView("available",
@ -77,34 +84,48 @@ LocaleWindow::LocaleWindow()
BScrollView* scrollView = new BScrollView("scroller", fLanguageListView,
B_WILL_DRAW | B_FRAME_EVENTS, false, true);
fLanguageListView->SetInvocationMessage(new BMessage(kMsgLangInvoked));
fLanguageListView->SetInvocationMessage(new BMessage(kMsgLanguageInvoked));
fLanguageListView->SetDragMessage(new BMessage(kMsgLanguageDragged));
// Fill the language list from the LocaleRoster data
BMessage installedLanguages;
if (be_locale_roster->GetInstalledLanguages(&installedLanguages) == B_OK) {
BString currentLanguageCode;
BString currentLanguageName;
BString currentID;
LanguageListItem* lastAddedCountryItem = NULL;
for (int i = 0; installedLanguages.FindString("langs",
i, &currentLanguageCode) == B_OK; i++) {
for (int i = 0; installedLanguages.FindString("langs", i, &currentID)
== B_OK; i++) {
// Now get an human-readable, localized name for each language
BLanguage* currentLanguage;
be_locale_roster->GetLanguage(&currentLanguage,
currentLanguageCode.String());
be_locale_roster->GetLanguage(currentID.String(),
&currentLanguage);
currentLanguageName.Truncate(0);
currentLanguage->GetName(&currentLanguageName);
BString name;
currentLanguage->GetName(name);
LanguageListItem* item = new LanguageListItem(currentLanguageName,
currentLanguageCode.String());
if (currentLanguage->IsCountry()) {
// TODO: as long as the app_server doesn't support font overlays,
// use the translated name if problematic characters are used...
const char* string = name.String();
while (uint32 code = BUnicodeChar::FromUTF8(&string)) {
if (code > 1424) {
currentLanguage->GetTranslatedName(name);
break;
}
}
LanguageListItem* item = new LanguageListItem(name,
currentID.String(), currentLanguage->Code());
if (currentLanguage->IsCountrySpecific()
&& lastAddedCountryItem != NULL
&& lastAddedCountryItem->Code() == item->Code()) {
fLanguageListView->AddUnder(item, lastAddedCountryItem);
} else {
// This is a language without country, add it at top-level
// This is a language variant, add it at top-level
fLanguageListView->AddItem(item);
item->SetExpanded(false);
lastAddedCountryItem = item;
if (!currentLanguage->IsCountrySpecific()) {
item->SetExpanded(false);
lastAddedCountryItem = item;
}
}
delete currentLanguage;
@ -112,12 +133,12 @@ LocaleWindow::LocaleWindow()
fLanguageListView->FullListSortItems(compare_typed_list_items);
} else {
BAlert* myAlert = new BAlert("Error",
BAlert* alert = new BAlert("Error",
B_TRANSLATE("Unable to find the available languages! You can't "
"use this preflet!"),
B_TRANSLATE("OK"), NULL, NULL,
B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
myAlert->Go();
alert->Go();
}
// Second list: active languages
@ -126,40 +147,23 @@ LocaleWindow::LocaleWindow()
BScrollView* scrollViewEnabled = new BScrollView("scroller",
fPreferredListView, B_WILL_DRAW | B_FRAME_EVENTS, false, true);
fPreferredListView->SetInvocationMessage(new BMessage(kMsgPrefLangInvoked));
fPreferredListView->SetInvocationMessage(
new BMessage(kMsgPreferredLanguageInvoked));
fPreferredListView->SetDeleteMessage(
new BMessage(kMsgPreferredLanguageDeleted));
fPreferredListView->SetDragMessage(
new BMessage(kMsgPreferredLanguageDragged));
// get the preferred languages from the Settings. Move them here from
// the other list.
BMessage msg;
be_locale_roster->GetPreferredLanguages(&msg);
BString langCode;
for (int index = 0; msg.FindString("language", index, &langCode) == B_OK;
index++) {
for (int listPos = 0; LanguageListItem* item
= static_cast<LanguageListItem*>
(fLanguageListView->FullListItemAt(listPos));
listPos++) {
if (langCode == item->LanguageCode()) {
// We found the item we were looking for, now move it to
// the other list along with all its children
static_cast<LanguageListView*>(fPreferredListView)
->MoveItemFrom(fLanguageListView,
fLanguageListView->FullListIndexOf(item),
fLanguageListView->CountItems());
}
}
}
languageTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 10)
.AddGroup(B_VERTICAL, 10)
BLayoutBuilder::Group<>(languageTab)
.AddGroup(B_VERTICAL, spacing)
.Add(new BStringView("", B_TRANSLATE("Available languages")))
.Add(scrollView)
.End()
.AddGroup(B_VERTICAL, 10)
.AddGroup(B_VERTICAL, spacing)
.Add(new BStringView("", B_TRANSLATE("Preferred languages")))
.Add(scrollViewEnabled)
.End()
.View());
.SetInsets(spacing, spacing, spacing, spacing);
BView* countryTab = new BView(B_TRANSLATE("Country"), B_WILL_DRAW);
countryTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
@ -183,48 +187,56 @@ LocaleWindow::LocaleWindow()
countryFullName.toUTF8(sink);
LanguageListItem* item
= new LanguageListItem(string, currentLocale[index].getName());
= new LanguageListItem(string, currentLocale[index].getName(),
NULL);
listView->AddItem(item);
if (!strcmp(currentLocale[index].getName(), defaultCountry->Code()))
listView->Select(listView->CountItems() - 1);
}
// TODO: find a real solution intead of this hack
listView->SetExplicitMinSize(BSize(300, B_SIZE_UNSET));
listView->SetExplicitMinSize(
BSize(25 * be_plain_font->Size(), B_SIZE_UNSET));
fFormatView = new FormatView(defaultCountry);
countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, 5)
countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, spacing)
.AddGroup(B_VERTICAL, 3)
.Add(scrollView)
.End()
.Add(fFormatView)
.View()
);
.SetInsets(spacing, spacing, spacing, spacing));
listView->ScrollToSelection();
tabView->AddTab(languageTab);
tabView->AddTab(countryTab);
BLayoutBuilder::Group<>(this)
.AddGroup(B_VERTICAL, 3)
.Add(tabView)
.AddGroup(B_HORIZONTAL, 3)
.Add(button)
.Add(fRevertButton)
.AddGlue()
.End()
.SetInsets(5, 5, 5, 5)
.End();
BButton* button = new BButton(B_TRANSLATE("Defaults"),
new BMessage(kMsgDefaults));
#if 0
fRevertButton = new BButton(B_TRANSLATE("Revert"),
new BMessage(kMsgRevert));
fRevertButton->SetEnabled(false);
#endif
BLayoutBuilder::Group<>(this, B_VERTICAL, spacing)
.Add(tabView)
.AddGroup(B_HORIZONTAL, spacing)
.Add(button)
// .Add(fRevertButton)
.AddGlue()
.End()
.SetInsets(spacing, spacing, spacing, spacing)
.End();
_UpdatePreferredFromLocaleRoster();
CenterOnScreen();
}
LocaleWindow::~LocaleWindow()
{
delete fMsgPrefLanguagesChanged;
}
@ -233,30 +245,86 @@ LocaleWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgDefaults:
// TODO
_Defaults();
break;
case kMsgRevert:
// TODO
break;
case kMsgPrefLanguagesChanged:
case kMsgLanguageDragged:
{
BMessage update(kMsgSettingsChanged);
int index = 0;
while (index < fPreferredListView->FullListCountItems()) {
// only include subitems : we can guess the superitem
// from them anyway
if (fPreferredListView->Superitem(
fPreferredListView->FullListItemAt(index)) != NULL) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fPreferredListView->FullListItemAt(index));
update.AddString("language", item->LanguageCode());
}
index++;
void* target = NULL;
if (message->FindPointer("drop_target", &target) != B_OK
|| target != fPreferredListView)
break;
// Add from available languages to preferred languages
int32 dropIndex;
if (message->FindInt32("drop_index", &dropIndex) != B_OK)
dropIndex = fPreferredListView->CountItems();
int32 index = 0;
for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
i++) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fLanguageListView->FullListItemAt(index));
_InsertPreferredLanguage(item, dropIndex++);
}
break;
}
case kMsgLanguageInvoked:
{
int32 index = 0;
for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
i++) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fLanguageListView->ItemAt(index));
_InsertPreferredLanguage(item);
}
break;
}
case kMsgPreferredLanguageDragged:
{
void* target = NULL;
if (fPreferredListView->CountItems() == 1
|| message->FindPointer("drop_target", &target) != B_OK)
break;
if (target == fPreferredListView) {
// change ordering
int32 dropIndex = message->FindInt32("drop_index");
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK
&& dropIndex != index) {
BListItem* item = fPreferredListView->RemoveItem(index);
if (dropIndex > index)
index--;
fPreferredListView->AddItem(item, dropIndex);
_PreferredLanguagesChanged();
}
break;
}
// supposed to fall through - remove item
}
case kMsgPreferredLanguageDeleted:
case kMsgPreferredLanguageInvoked:
{
if (fPreferredListView->CountItems() == 1)
break;
// Remove from preferred languages
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK) {
delete fPreferredListView->RemoveItem(index);
_PreferredLanguagesChanged();
if (message->what == kMsgPreferredLanguageDeleted)
fPreferredListView->Select(index);
}
fLanguageListView->FullListSortItems(compare_typed_list_items);
be_app_messenger.SendMessage(&update);
break;
}
@ -274,42 +342,14 @@ LocaleWindow::MessageReceived(BMessage* message)
LanguageListItem* item = static_cast<LanguageListItem*>
(countryList->ItemAt(countryList->CurrentSelection()));
BMessage newMessage(kMsgSettingsChanged);
newMessage.AddString("country", item->LanguageCode());
newMessage.AddString("country", item->ID());
be_app_messenger.SendMessage(&newMessage);
BCountry* country = new BCountry(item->LanguageCode());
BCountry* country = new BCountry(item->ID());
fFormatView->SetCountry(country);
break;
}
case kMsgLangInvoked:
{
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK) {
LanguageListItem* listItem = static_cast<LanguageListItem*>
(fLanguageListView->RemoveItem(index));
fPreferredListView->AddItem(listItem);
fPreferredListView->Invoke(fMsgPrefLanguagesChanged);
}
break;
}
case kMsgPrefLangInvoked:
{
if (fPreferredListView->CountItems() == 1)
break;
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK) {
LanguageListItem* listItem = static_cast<LanguageListItem*>
(fPreferredListView->RemoveItem(index));
fLanguageListView->AddItem(listItem);
fLanguageListView->FullListSortItems(compare_typed_list_items);
fPreferredListView->Invoke(fMsgPrefLanguagesChanged);
}
break;
}
default:
BWindow::MessageReceived(message);
break;
@ -317,11 +357,142 @@ LocaleWindow::MessageReceived(BMessage* message)
}
void
LocaleWindow::FrameMoved(BPoint newPosition)
bool
LocaleWindow::QuitRequested()
{
BMessage update(kMsgSettingsChanged);
update.AddPoint("window_location", newPosition);
update.AddPoint("window_location", Frame().LeftTop());
be_app_messenger.SendMessage(&update);
return true;
}
void
LocaleWindow::_PreferredLanguagesChanged()
{
BMessage update(kMsgSettingsChanged);
int index = 0;
while (index < fPreferredListView->FullListCountItems()) {
// only include subitems: we can guess the superitem
// from them anyway
LanguageListItem* item = static_cast<LanguageListItem*>(
fPreferredListView->FullListItemAt(index));
if (item != NULL)
update.AddString("language", item->ID());
index++;
}
be_app_messenger.SendMessage(&update);
_EnableDisableLanguages();
}
void
LocaleWindow::_EnableDisableLanguages()
{
DisableUpdates();
for (int32 i = 0; i < fLanguageListView->FullListCountItems(); i++) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fLanguageListView->FullListItemAt(i));
bool enable = fPreferredListView->ItemForLanguageID(item->ID()) == NULL;
if (item->IsEnabled() != enable) {
item->SetEnabled(enable);
int32 visibleIndex = fLanguageListView->IndexOf(item);
if (visibleIndex >= 0) {
if (!enable)
fLanguageListView->Deselect(visibleIndex);
fLanguageListView->InvalidateItem(visibleIndex);
}
}
}
EnableUpdates();
}
//! Get the preferred languages from the settings.
void
LocaleWindow::_UpdatePreferredFromLocaleRoster()
{
DisableUpdates();
// Delete all existing items
for (int32 index = fPreferredListView->CountItems(); index-- > 0; ) {
delete fPreferredListView->ItemAt(index);
}
fPreferredListView->MakeEmpty();
// Add new ones from the locale roster
BMessage preferredLanguages;
be_locale_roster->GetPreferredLanguages(&preferredLanguages);
BString languageID;
for (int32 index = 0; preferredLanguages.FindString("language", index,
&languageID) == B_OK; index++) {
int32 listIndex;
LanguageListItem* item
= fLanguageListView->ItemForLanguageID(languageID.String(),
&listIndex);
if (item != NULL) {
// We found the item we were looking for, now copy it to
// the other list
fPreferredListView->AddItem(new LanguageListItem(*item));
}
}
_EnableDisableLanguages();
EnableUpdates();
}
void
LocaleWindow::_InsertPreferredLanguage(LanguageListItem* item, int32 atIndex)
{
if (item == NULL || fPreferredListView->ItemForLanguageID(
item->ID().String()) != NULL)
return;
if (atIndex == -1)
atIndex = fPreferredListView->CountItems();
BLanguage* language = NULL;
be_locale_roster->GetLanguage(item->Code(), &language);
LanguageListItem* baseItem = NULL;
if (language != NULL) {
baseItem = fPreferredListView->ItemForLanguageCode(language->Code(),
&atIndex);
delete language;
}
DisableUpdates();
fPreferredListView->AddItem(new LanguageListItem(*item), atIndex);
// Replace other languages with the same base
if (baseItem != NULL) {
fPreferredListView->RemoveItem(baseItem);
delete baseItem;
}
_PreferredLanguagesChanged();
EnableUpdates();
}
void
LocaleWindow::_Defaults()
{
BMessage update(kMsgSettingsChanged);
update.AddString("language", "en");
be_app_messenger.SendMessage(&update);
_UpdatePreferredFromLocaleRoster();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2005-2010, Axel Dörfler, axeld@pinc-software.de.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LOCALE_WINDOW_H
@ -8,27 +8,37 @@
#include <Window.h>
class BButton;
class BListView;
class BOutlineListView;
class FormatView;
class LanguageListItem;
class LanguageListView;
class LocaleWindow : public BWindow {
public:
LocaleWindow();
~LocaleWindow();
virtual ~LocaleWindow();
virtual void MessageReceived(BMessage* message);
virtual void FrameMoved(BPoint newPosition);
virtual bool QuitRequested();
private:
void _PreferredLanguagesChanged();
void _EnableDisableLanguages();
void _UpdatePreferredFromLocaleRoster();
void _InsertPreferredLanguage(LanguageListItem* item,
int32 atIndex = -1);
void _Defaults();
private:
BButton* fRevertButton;
BOutlineListView* fLanguageListView;
BOutlineListView* fPreferredListView;
LanguageListView* fLanguageListView;
LanguageListView* fPreferredListView;
FormatView* fFormatView;
BMessage* fMsgPrefLanguagesChanged;
};
#endif // LOCALE_WINDOW_H