diff --git a/src/preferences/locale/LanguageListView.cpp b/src/preferences/locale/LanguageListView.cpp index 6d0501178a..4776f272a5 100644 --- a/src/preferences/locale/LanguageListView.cpp +++ b/src/preferences/locale/LanguageListView.cpp @@ -5,6 +5,7 @@ * Authors: * Stephan Aßmus * Adrien Destugues + * Oliver Tappe */ #include "LanguageListView.h" @@ -39,15 +40,6 @@ LanguageListItem::LanguageListItem(const char* text, const char* code) } -LanguageListItem::LanguageListItem(const LanguageListItem& other) - : - BStringItem(other.Text()), - fLanguageCode(other.fLanguageCode), - fIcon(other.fIcon ? new(std::nothrow) BBitmap(other.fIcon) : NULL) -{ -} - - LanguageListItem::~LanguageListItem() { delete fIcon; @@ -131,31 +123,40 @@ LanguageListView::MoveItems(BList& items, int32 index) // or sublevels within the same top level DeselectAll(); - // we remove the items while we look at them, the insertion index is - // decreaded when the items index is lower, so that we insert at the right - // spot after removal - BList removedItems; + + // collect all items that must be moved (adding subitems as necessary) int32 count = items.CountItems(); - // We loop in the reverse way so we can remove childs before their parents - for (int32 i = count - 1; i >= 0; i--) { + BList itemsToBeMoved; + for (int32 i = 0; i < count; i++) { BListItem* item = (BListItem*)items.ItemAt(i); - int32 removeIndex = IndexOf(item); - // TODO : remove all childs before removing the item itself, or else - // they will be lost forever - if (RemoveItem(item) && removedItems.AddItem((void*)item, 0)) { + 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--; } - // else ??? -> blow up } - for (int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt(i); - i++) { - if (AddItem(item, index)) { - // after we're done, the newly inserted items will be selected - Select(index, true); - // next items will be inserted after this one + + // 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 + else delete item; } } @@ -168,12 +169,12 @@ void LanguageListView::MessageReceived (BMessage* message) 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; + if (list == this) { // It comes from ourselves : move the item around in the list - int32 count = CountItems(); - if (fDropIndex < 0 || fDropIndex > count) - fDropIndex = count; - BList items; int32 index; for (int32 i = 0; @@ -209,9 +210,6 @@ void LanguageListView::MessageReceived (BMessage* message) fDropIndex = -1; } else { // It comes from another list : move it here - int32 count = CountItems(); - if (fDropIndex < 0 || fDropIndex > count) - fDropIndex = count; // ensure we always drop things at top-level and not // in the middle of another outline @@ -223,14 +221,17 @@ void LanguageListView::MessageReceived (BMessage* message) // Item is now a top level one - we must insert just below its // last child - fDropIndex += CountItemsUnder(FullListItemAt(fDropIndex),false) + fDropIndex += CountItemsUnder(FullListItemAt(fDropIndex), true) + 1; - int32 index; - for (int32 i = 0; - message->FindInt32("index", i, &index) == B_OK; i++) { - MoveItemFrom(list, index, fDropIndex); - fDropIndex++; + 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; @@ -247,27 +248,36 @@ 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 his parent instead + // 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)); + itemToMove = static_cast( + origin->FullListItemAt(index)); + if (itemToMove == NULL) + return; } else index = origin->FullListIndexOf(itemToMove); - int itemCount = origin->CountItemsUnder(itemToMove, true); - LanguageListItem* newItem = new LanguageListItem(*itemToMove); - this->AddItem(newItem, dropSpot); - newItem->SetExpanded(itemToMove->IsExpanded()); - - for (int i = 0; i < itemCount ; i++) { - LanguageListItem* subItem = static_cast( - origin->ItemUnderAt(itemToMove, true, i)); - this->AddUnder(new LanguageListItem(*subItem), newItem); + // 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)); } - origin->RemoveItem(index); - // This will also remove the children + + // 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); } @@ -277,7 +287,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 index, bool) bool success = false; BListItem* item = FullListItemAt(CurrentSelection(0)); if (!item) { - // workarround a timing problem + // workaround for a timing problem Select(index); item = FullListItemAt(index); } @@ -285,18 +295,46 @@ LanguageListView::InitiateDrag(BPoint point, int32 index, bool) // 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++) - msg.AddInt32("index", 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; + } + } + } + // 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 - int32 numItems; bool fade = false; + int32 numItems; + int32 currIndex; + BListItem* item; for (numItems = 0; - BListItem* item = FullListItemAt(CurrentSelection(numItems)); - numItems++) { + 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; @@ -315,7 +353,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 index, bool) itemBounds.bottom = 0.0; // let all selected items, that fit into our drag_bitmap, draw for (int32 i = 0; i < numItems; i++) { - int32 index = FullListCurrentSelection(i); + int32 index = msg.FindInt32("index", i); LanguageListItem* item = static_cast(FullListItemAt(index)); itemBounds.bottom = itemBounds.top + ceilf(item->Height()); diff --git a/src/preferences/locale/LanguageListView.h b/src/preferences/locale/LanguageListView.h index c243b2613f..81ca8aec30 100644 --- a/src/preferences/locale/LanguageListView.h +++ b/src/preferences/locale/LanguageListView.h @@ -5,6 +5,7 @@ * Authors: * Stephan Aßmus * Adrien Destugues + * Oliver Tappe */ #ifndef __LANGUAGE_LIST_VIEW_H #define __LANGUAGE_LIST_VIEW_H @@ -19,7 +20,6 @@ class LanguageListItem : public BStringItem { public: LanguageListItem(const char* text, const char* code); - LanguageListItem(const LanguageListItem& other); virtual ~LanguageListItem(); const BString& LanguageCode() { return fLanguageCode; } diff --git a/src/preferences/locale/Locale.cpp b/src/preferences/locale/Locale.cpp index b4ac1d2221..101105e7d0 100644 --- a/src/preferences/locale/Locale.cpp +++ b/src/preferences/locale/Locale.cpp @@ -109,10 +109,8 @@ void Settings::UpdateFrom(BMessage* message) { BPoint point; - if (message->FindPoint("window_location", &point) == B_OK) { - fMessage.RemoveName("window_location"); - fMessage.AddPoint("window_location", point); - } + if (message->FindPoint("window_location", &point) == B_OK) + fMessage.ReplacePoint("window_location", point); BString langName; // We make sure there is at least one string before erasing the previous @@ -127,10 +125,9 @@ Settings::UpdateFrom(BMessage* message) } } - if (message->FindString("country",&langName) == B_OK) + if (message->FindString("country", &langName) == B_OK) fMessage.ReplaceString("country", langName); - fUpdated = true; } diff --git a/src/preferences/locale/LocaleWindow.cpp b/src/preferences/locale/LocaleWindow.cpp index 25c2fffc88..4902575cf7 100644 --- a/src/preferences/locale/LocaleWindow.cpp +++ b/src/preferences/locale/LocaleWindow.cpp @@ -43,6 +43,15 @@ compare_list_items(const void* _a, const void* _b) } +static int +compare_typed_list_items(const BListItem* _a, const BListItem* _b) +{ + LanguageListItem* a = *(LanguageListItem**)_a; + LanguageListItem* b = *(LanguageListItem**)_b; + return strcasecmp(a->Text(), b->Text()); +} + + LocaleWindow::LocaleWindow() : BWindow(BRect(0, 0, 0, 0), "Locale", B_TITLED_WINDOW, B_NOT_RESIZABLE @@ -84,7 +93,7 @@ LocaleWindow::LocaleWindow() for (int i = 0; installedLanguages.FindString("langs", i, ¤tLanguageCode) == B_OK; i++) { - // Now get an human-readable, loacalized name for each language + // Now get an human-readable, localized name for each language // TODO: sort them using collators. BLanguage* currentLanguage; be_locale_roster->GetLanguage(¤tLanguage, @@ -101,11 +110,17 @@ LocaleWindow::LocaleWindow() // This is a language without country, add it at top-level fLanguageListView->AddItem(si); si->SetExpanded(false); + if (lastAddedLanguage != NULL) { + fLanguageListView->SortItemsUnder(lastAddedLanguage, + true, compare_typed_list_items); + } lastAddedLanguage = si; } delete currentLanguage; } + fLanguageListView->SortItemsUnder(lastAddedLanguage, true, + compare_typed_list_items); fLanguageListView->SortItems(compare_list_items); // see previous comment on sort using collators @@ -133,9 +148,8 @@ LocaleWindow::LocaleWindow() BMessage msg; be_locale_roster->GetPreferredLanguages(&msg); BString langCode; - for (int index = 0; msg.FindString("language", index, &langCode) - == B_OK; - index++) { + for (int index = 0; + msg.FindString("language", index, &langCode) == B_OK; index++) { for (int listPos = 0; LanguageListItem* lli = static_cast (fLanguageListView->FullListItemAt(listPos)); @@ -144,8 +158,9 @@ LocaleWindow::LocaleWindow() // 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(lli)); + ->MoveItemFrom(fLanguageListView, + fLanguageListView->FullListIndexOf(lli), + fLanguageListView->CountItems()); } } } @@ -247,22 +262,21 @@ LocaleWindow::MessageReceived(BMessage* message) case kMsgPrefLanguagesChanged: { - 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) { - update.AddString("language", - static_cast - (fPreferredListView->FullListItemAt(index)) - -> LanguageCode()); - } - index++; + 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) { + update.AddString("language", static_cast( + fPreferredListView->FullListItemAt(index)) + ->LanguageCode()); } - be_app_messenger.SendMessage(&update); + index++; + } + fLanguageListView->SortItems(compare_list_items); + be_app_messenger.SendMessage(&update); break; } @@ -293,8 +307,7 @@ LocaleWindow::MessageReceived(BMessage* message) = static_cast (fLanguageListView->RemoveItem(index)); fPreferredListView->AddItem(listItem); - fPreferredListView - ->Invoke(fMsgPrefLanguagesChanged); + fPreferredListView->Invoke(fMsgPrefLanguagesChanged); } break; } @@ -312,8 +325,7 @@ LocaleWindow::MessageReceived(BMessage* message) fLanguageListView->AddItem(listItem); fLanguageListView->SortItems(compare_list_items); // see previous comment on sort using collators - fPreferredListView - ->Invoke(fMsgPrefLanguagesChanged); + fPreferredListView->Invoke(fMsgPrefLanguagesChanged); } break; }