diff --git a/headers/os/locale/Language.h b/headers/os/locale/Language.h index b1fdda0d6f..490397cd89 100644 --- a/headers/os/locale/Language.h +++ b/headers/os/locale/Language.h @@ -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 #include #include -#include // 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_ diff --git a/headers/os/locale/LocaleRoster.h b/headers/os/locale/LocaleRoster.h index 36ab22cd15..3e72f02042 100644 --- a/headers/os/locale/LocaleRoster.h +++ b/headers/os/locale/LocaleRoster.h @@ -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 *); diff --git a/src/kits/locale/Language.cpp b/src/kits/locale/Language.cpp index 21cca77c9c..de537e7a70 100644 --- a/src/kits/locale/Language.cpp +++ b/src/kits/locale/Language.cpp @@ -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; } diff --git a/src/kits/locale/LocaleRoster.cpp b/src/kits/locale/LocaleRoster.cpp index b332692d33..73eec7caba 100644 --- a/src/kits/locale/LocaleRoster.cpp +++ b/src/kits/locale/LocaleRoster.cpp @@ -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 +/* + * 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; } diff --git a/src/preferences/locale/Jamfile b/src/preferences/locale/Jamfile index c8028acc2b..9f601fd6d4 100644 --- a/src/preferences/locale/Jamfile +++ b/src/preferences/locale/Jamfile @@ -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 ; - diff --git a/src/preferences/locale/LanguageListView.cpp b/src/preferences/locale/LanguageListView.cpp index cefa61037e..d3f4597a74 100644 --- a/src/preferences/locale/LanguageListView.cpp +++ b/src/preferences/locale/LanguageListView.cpp @@ -5,6 +5,7 @@ * Authors: * Stephan Aßmus * Adrien Destugues + * Axel Dörfler, axeld@pinc-software.de * Oliver Tappe */ @@ -17,31 +18,46 @@ #include #include - -#include "Locale.h" +#include +#include #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(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(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( - Superitem(static_cast( - 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( - origin->Superitem(origin->FullListItemAt(index))); - if (itemToMove == NULL) { - itemToMove = static_cast( - 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(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(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; } diff --git a/src/preferences/locale/LanguageListView.h b/src/preferences/locale/LanguageListView.h index 026940a970..03fc8ee6b9 100644 --- a/src/preferences/locale/LanguageListView.h +++ b/src/preferences/locale/LanguageListView.h @@ -5,6 +5,7 @@ * Authors: * Stephan Aßmus * Adrien Destugues + * Axel Dörfler, axeld@pinc-software.de * Oliver Tappe */ #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; }; diff --git a/src/preferences/locale/Locale.h b/src/preferences/locale/Locale.h index 300cf51ea7..c90a9b352e 100644 --- a/src/preferences/locale/Locale.h +++ b/src/preferences/locale/Locale.h @@ -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 */ diff --git a/src/preferences/locale/LocaleWindow.cpp b/src/preferences/locale/LocaleWindow.cpp index 30b13edf0a..1c3d8c9ddb 100644 --- a/src/preferences/locale/LocaleWindow.cpp +++ b/src/preferences/locale/LocaleWindow.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include @@ -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, ¤tLanguageCode) == B_OK; i++) { + for (int i = 0; installedLanguages.FindString("langs", i, ¤tID) + == B_OK; i++) { // Now get an human-readable, localized name for each language BLanguage* currentLanguage; - be_locale_roster->GetLanguage(¤tLanguage, - currentLanguageCode.String()); + be_locale_roster->GetLanguage(currentID.String(), + ¤tLanguage); - currentLanguageName.Truncate(0); - currentLanguage->GetName(¤tLanguageName); + 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 - (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(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( - 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( + 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( + 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 (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 - (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 - (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( + 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( + 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(); +} diff --git a/src/preferences/locale/LocaleWindow.h b/src/preferences/locale/LocaleWindow.h index ad9d74c03a..a17b031857 100644 --- a/src/preferences/locale/LocaleWindow.h +++ b/src/preferences/locale/LocaleWindow.h @@ -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 + 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