Author: axeld Date: 2010-05-07 19:38:40 +0200 (Fri, 07 May 2010) New Revision: 36727 Changeset: http://dev.haiku-os.org/changeset/36727/haiku Ticket: http://dev.haiku-os.org/ticket/5896 Modified: haiku/trunk/headers/os/locale/Language.h haiku/trunk/headers/os/locale/LocaleRoster.h haiku/trunk/src/kits/locale/Language.cpp haiku/trunk/src/kits/locale/LocaleRoster.cpp haiku/trunk/src/preferences/locale/Jamfile haiku/trunk/src/preferences/locale/LanguageListView.cpp haiku/trunk/src/preferences/locale/LanguageListView.h haiku/trunk/src/preferences/locale/Locale.h haiku/trunk/src/preferences/locale/LocaleWindow.cpp haiku/trunk/src/preferences/locale/LocaleWindow.h Log: * 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. Modified: haiku/trunk/headers/os/locale/Language.h =================================================================== --- haiku/trunk/headers/os/locale/Language.h 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/headers/os/locale/Language.h 2010-05-07 17:38:40 UTC (rev 36727) @@ -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 @@ 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_ Modified: haiku/trunk/headers/os/locale/LocaleRoster.h =================================================================== --- haiku/trunk/headers/os/locale/LocaleRoster.h 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/headers/os/locale/LocaleRoster.h 2010-05-07 17:38:40 UTC (rev 36727) @@ -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 @@ namespace BPrivate { class EditableCatalog; -}; +} enum { B_LOCALE_CHANGED = '_LCC', @@ -25,7 +29,6 @@ class BLocaleRoster { - public: BLocaleRoster(); ~BLocaleRoster(); @@ -42,7 +45,8 @@ 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 *); Modified: haiku/trunk/src/kits/locale/Language.cpp =================================================================== --- haiku/trunk/src/kits/locale/Language.cpp 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/src/kits/locale/Language.cpp 2010-05-07 17:38:40 UTC (rev 36727) @@ -80,10 +80,7 @@ }; -// #pragma mark - - - -BLanguage::BLanguage(const char *language) +BLanguage::BLanguage(const char* language) : fDirection(B_LEFT_TO_RIGHT) { @@ -123,10 +120,11 @@ } -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 @@ status_t -BLanguage::GetName(BString* name) +BLanguage::GetName(BString& name) const { + 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 s; - fICULocale->getDisplayName(Locale(appLanguage), s); - BStringByteSink converter(name); - s.toUTF8(converter); + + 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(); } +const char* +BLanguage::Country() const +{ + 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::IsCountry() +BLanguage::IsCountrySpecific() const { - return *(fICULocale->getCountry()) != '\0'; + return Country() != NULL; } + + +bool +BLanguage::IsVariant() const +{ + return Variant() != NULL; +} Modified: haiku/trunk/src/kits/locale/LocaleRoster.cpp =================================================================== --- haiku/trunk/src/kits/locale/LocaleRoster.cpp 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/src/kits/locale/LocaleRoster.cpp 2010-05-07 17:38:40 UTC (rev 36727) @@ -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 *(*InstantiateEmbeddedCatalogFunc)( entry_ref *appOrAddOnRef); - + typedef status_t (*GetAvailableLanguagesFunc)(BMessage*, const char*, const char*, int32); @@ -211,7 +238,7 @@ 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 @@ 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 @@ } -/* - * 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 @@ 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 @@ status_t -BLocaleRoster::GetPreferredLanguages(BMessage *languages) const +BLocaleRoster::GetPreferredLanguages(BMessage* languages) const { if (!languages) return B_BAD_VALUE; @@ -548,7 +556,7 @@ { 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 @@ if (!info->MakeSureItsLoaded() || !info->fLanguagesFunc) continue; - + info->fLanguagesFunc(languageList, sigPattern, langPattern, fingerprint); } - + return B_OK; } Modified: haiku/trunk/src/preferences/locale/Jamfile =================================================================== --- haiku/trunk/src/preferences/locale/Jamfile 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/src/preferences/locale/Jamfile 2010-05-07 17:38:40 UTC (rev 36727) @@ -9,16 +9,15 @@ 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 ; - Modified: haiku/trunk/src/preferences/locale/LanguageListView.cpp =================================================================== --- haiku/trunk/src/preferences/locale/LanguageListView.cpp 2010-05-07 17:30:31 UTC (rev 36726) +++ haiku/trunk/src/preferences/locale/LanguageListView.cpp 2010-05-07 17:38:40 UTC (rev 36727) @@ -5,6 +5,7 @@ * Authors: * Stephan Aßmus <superstippi@xxxxxx> * Adrien Destugues <pulkomandy@xxxxxxxxx> + * Axel Dörfler, axeld@xxxxxxxxxxxxxxxx * Oliver Tappe <zooey@xxxxxxxxxxxxxxx> */ @@ -17,31 +18,46 @@ #include <Bitmap.h> #include <Country.h> +#include <Catalog.h> +#include <Window.h> -#include "Locale.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,11 +67,9 @@ void LanguageListItem::DrawItem(BView* owner, BRect frame, bool complete) { - rgb_color kHighlight = { 140,140,140,0 }; - rgb_color kBlack = { 0,0,0,0 }; + rgb_color kHighlight = {140, 140, 140, 0}; + rgb_color kBlack = {0, 0, 0, 0}; - BRect r(frame); - if (IsSelected() || complete) { rgb_color color; if (IsSelected()) @@ -64,33 +78,43 @@ 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,321 +124,212 @@ LanguageListView::LanguageListView(const char* name, list_view_type type) : BOutlineListView(name, type), - fMsgPrefLanguagesChanged(new BMessage(kMsgPrefLanguagesChanged)) + fDeleteMessage(NULL), + fDragMessage(NULL) { } LanguageListView::~LanguageListView() { - delete fMsgPrefLanguagesChanged; } -void -LanguageListView::AttachedToWindow() +LanguageListItem* +LanguageListView::ItemForLanguageID(const char* id, int32* _index) const { - BOutlineListView::AttachedToWindow(); - ScrollToSelection(); + 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; } -void -LanguageListView::MoveItems(BList& items, int32 index) +LanguageListItem* +LanguageListView::ItemForLanguageCode(const char* code, int32* _index) const { - // TODO : only allow moving top level item around other top level - // or sublevels within the same top level + for (int32 index = 0; index < FullListCountItems(); index++) { + LanguageListItem* item + = static_cast<LanguageListItem*>(FullListItemAt(index)); - 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)); + if (item->Code() == code) { + if (_index != NULL) + *_index = index; + return item; } } - // 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; - } + return NULL; } void -LanguageListView::MessageReceived(BMessage* message) +LanguageListView::SetDeleteMessage(BMessage* message) { - if (message->what == 'DRAG') { - // 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; + delete fDeleteMessage; + fDeleteMessage = message; +} - 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 +void +LanguageListView::SetDragMessage(BMessage* message) +{ + delete fDragMessage; + fDragMessage = message; +} - // 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); - } - } else - BOutlineListView::MessageReceived(message); +void +LanguageListView::AttachedToWindow() +{ + BOutlineListView::AttachedToWindow(); + ScrollToSelection(); } void -LanguageListView::MoveItemFrom(BOutlineListView* origin, int32 index, - int32 dropSpot) +LanguageListView::MessageReceived(BMessage* message) { - // 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); + if (message->WasDropped() && _AcceptsDragMessage(message)) { + // Someone just dropped something on us + BMessage dragMessage(*message); + dragMessage.AddInt32("drop_index", fDropIndex); + dragMessage.AddPointer("drop_target", this); - // 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); + Invoke(&dragMessage); + } else + BOutlineListView::MessageReceived(message); } 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 (item == NULL) + return false; + + // 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; } - 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; - } - } - } + } - // 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; - } + 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; } - 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(); + // make a black frame arround the edge + view->SetHighColor(0, 0, 0, 255); + view->StrokeRect(view->Bounds()); + view->Sync(); - uint8* bits = (uint8*)dragBitmap->Bits(); - int32 height = (int32)dragBitmap->Bounds().Height() + 1; - int32 width = (int32)dragBitmap->Bounds().Width() + 1; - int32 bpr = dragBitmap->BytesPerRow(); + 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; - } - } 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; - } + if (fade) { [... truncated: 805 lines follow ...]