Separate LanguageListView from LocaleWindow as it was occupying more than half of the file and will grow even more soon.

No functionnal change.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36307 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues 2010-04-15 17:48:31 +00:00
parent 2272ecea26
commit 5e7931beaa
4 changed files with 386 additions and 355 deletions

View File

@ -5,6 +5,7 @@ UsePrivateHeaders locale ;
UsePrivateHeaders shared ;
Preference Locale :
LanguageListView.cpp
Locale.cpp
LocaleWindow.cpp
TimeFormatSettingsView.cpp

View File

@ -0,0 +1,323 @@
/*
* Copyright 2010, Adrien Destugues, pulkomandy@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LanguageListView.h"
#include "Locale.h"
#include <Bitmap.h>
#define MAX_DRAG_HEIGHT 200.0
#define ALPHA 170
#define TEXT_OFFSET 5.0
LanguageListItem::LanguageListItem(const char* text, const char* code)
:
BStringItem(text),
fLanguageCode(code)
{
}
LanguageListView::LanguageListView(const char* name, list_view_type type)
:
BOutlineListView(name, type),
fMsgPrefLanguagesChanged(new BMessage(kMsgPrefLanguagesChanged))
{
}
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();
// 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;
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--) {
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)) {
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
index++;
} else
delete item;
}
}
void LanguageListView::MessageReceived (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
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; 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
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
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),false) + 1;
int32 index;
for (int32 i = 0; message->FindInt32("index", i, &index)
== B_OK; i++) {
MoveItemFrom(list,index,fDropIndex);
fDropIndex++;
}
fDropIndex = -1;
}
Invoke(fMsgPrefLanguagesChanged);
}
} 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 his parent instead
LanguageListItem* itemToMove = static_cast<LanguageListItem*>(
origin->Superitem(origin->FullListItemAt(index)));
if (itemToMove == NULL) {
itemToMove = static_cast<LanguageListItem*>(
origin->FullListItemAt(index));
} 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<LanguageListItem*>(
origin->ItemUnderAt(itemToMove, true, i));
this->AddUnder(new LanguageListItem(*subItem),newItem);
}
origin->RemoveItem(index);
// This will also remove the children
}
bool
LanguageListView::InitiateDrag(BPoint point, int32 index, bool)
{
bool success = false;
BListItem* item = FullListItemAt(CurrentSelection(0));
if (!item) {
// workarround a timing problem
Select(index);
item = FullListItemAt(index);
}
if (item) {
// create drag message
BMessage msg('DRAG');
msg.AddPointer("list",(void*)(this));
int32 index;
for (int32 i = 0; (index = FullListCurrentSelection(i)) >= 0; i++) {
msg.AddInt32("index", index);
}
// 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;
for (numItems = 0; BListItem* item = FullListItemAt(CurrentSelection(numItems));
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 && dragBitmap->IsValid()) {
if (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 = FullListCurrentSelection(i);
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
if (itemBounds.bottom > dragRect.bottom)
itemBounds.bottom = dragRect.bottom;
item->DrawItem(v, itemBounds);
itemBounds.top = itemBounds.bottom + 1.0;
}
// make a black frame arround the edge
v->SetHighColor(0, 0, 0, 255);
v->StrokeRect(v->Bounds());
v->Sync();
uint8* bits = (uint8*)dragBitmap->Bits();
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
int32 bpr = dragBitmap->BytesPerRow();
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;
}
}
dragBitmap->Unlock();
}
} else {
delete dragBitmap;
dragBitmap = NULL;
}
if (dragBitmap)
DragMessage(&msg, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0));
else
DragMessage(&msg, dragRect.OffsetToCopy(point), this);
success = true;
}
return success;
}
void
LanguageListView::MouseMoved(BPoint where, uint32 transit, const BMessage* msg)
{
if (msg && (msg->what == 'DRAG')) {
switch (transit) {
case B_ENTERED_VIEW:
case B_INSIDE_VIEW: {
// set drop target through virtual function
// offset where by half of item height
BRect r = ItemFrame(0);
where.y += r.Height() / 2.0;
int32 index = FullListIndexOf(where);
if (index < 0)
index = FullListCountItems();
if (fDropIndex != index) {
fDropIndex = index;
if (fDropIndex >= 0) {
int32 count = FullListCountItems();
if (fDropIndex == count) {
BRect r;
if (FullListItemAt(count - 1)) {
r = ItemFrame(count - 1);
r.top = r.bottom;
r.bottom = r.top + 1.0;
} else {
r = Bounds();
r.bottom--;
// compensate for scrollbars moved slightly
// out of window
}
} else {
BRect r = ItemFrame(fDropIndex);
r.top--;
r.bottom = r.top + 1.0;
}
}
}
break;
}
}
} else {
BOutlineListView::MouseMoved(where, transit, msg);
}
}

View File

@ -0,0 +1,61 @@
#ifndef __LANGUAGE_LIST_VIEW_H
#define __LANGUAGE_LIST_VIEW_H
#include <OutlineListView.h>
#include <StringItem.h>
#include <String.h>
class LanguageListItem: public BStringItem
{
public:
LanguageListItem(const char* text, const char* code);
LanguageListItem(const LanguageListItem& other)
:
BStringItem(other.Text()),
fLanguageCode(other.fLanguageCode)
{}
~LanguageListItem() {};
const inline BString LanguageCode() { return fLanguageCode; }
private:
const BString fLanguageCode;
};
static int
compare_list_items(const void* _a, const void* _b)
{
LanguageListItem* a = *(LanguageListItem**)_a;
LanguageListItem* b = *(LanguageListItem**)_b;
return strcasecmp(a->Text(), b->Text());
}
class LanguageListView: public BOutlineListView
{
public:
LanguageListView(const char* name, list_view_type type);
~LanguageListView() { delete fMsgPrefLanguagesChanged; }
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()
{
BOutlineListView::AttachedToWindow();
ScrollToSelection();
}
void MessageReceived (BMessage* message);
private:
int32 fDropIndex;
BMessage* fMsgPrefLanguagesChanged;
};
#endif

View File

@ -6,19 +6,18 @@
#include "Locale.h"
#include "LocaleWindow.h"
#include "LanguageListView.h"
#include <iostream>
#include <Alert.h>
#include <Application.h>
#include <Bitmap.h>
#include <Button.h>
#include <Catalog.h>
#include <GroupLayout.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <LocaleRoster.h>
#include <OutlineListView.h>
#include <Screen.h>
#include <ScrollView.h>
#include <StringView.h>
@ -33,359 +32,6 @@
#define TR_CONTEXT "Locale Preflet Window"
#define MAX_DRAG_HEIGHT 200.0
#define ALPHA 170
#define TEXT_OFFSET 5.0
class LanguageListItem: public BStringItem
{
public:
LanguageListItem(const char* text, const char* code)
:
BStringItem(text),
fLanguageCode(code)
{}
LanguageListItem(const LanguageListItem& other)
:
BStringItem(other.Text()),
fLanguageCode(other.fLanguageCode)
{}
~LanguageListItem() {};
const inline BString LanguageCode() { return fLanguageCode; }
private:
const BString fLanguageCode;
};
static int
compare_list_items(const void* _a, const void* _b)
{
LanguageListItem* a = *(LanguageListItem**)_a;
LanguageListItem* b = *(LanguageListItem**)_b;
return strcasecmp(a->Text(), b->Text());
}
class LanguageListView: public BOutlineListView
{
public:
LanguageListView(const char* name, list_view_type type)
:
BOutlineListView(name, type),
fMsgPrefLanguagesChanged(new BMessage(kMsgPrefLanguagesChanged))
{}
~LanguageListView() { delete fMsgPrefLanguagesChanged; }
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()
{
BOutlineListView::AttachedToWindow();
ScrollToSelection();
}
void MessageReceived (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
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; 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
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
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),false) + 1;
int32 index;
for (int32 i = 0; message->FindInt32("index", i, &index)
== B_OK; i++) {
MoveItemFrom(list,index,fDropIndex);
fDropIndex++;
}
fDropIndex = -1;
}
Invoke(fMsgPrefLanguagesChanged);
}
} else BOutlineListView::MessageReceived(message);
}
private:
int32 fDropIndex;
BMessage* fMsgPrefLanguagesChanged;
};
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();
// 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;
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--) {
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)) {
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
index++;
} else
delete item;
}
}
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 his parent instead
LanguageListItem* itemToMove = static_cast<LanguageListItem*>(
origin->Superitem(origin->FullListItemAt(index)));
if (itemToMove == NULL) {
itemToMove = static_cast<LanguageListItem*>(
origin->FullListItemAt(index));
} 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<LanguageListItem*>(
origin->ItemUnderAt(itemToMove, true, i));
this->AddUnder(new LanguageListItem(*subItem),newItem);
}
origin->RemoveItem(index);
// This will also remove the children
}
bool
LanguageListView::InitiateDrag(BPoint point, int32 index, bool)
{
bool success = false;
BListItem* item = FullListItemAt(CurrentSelection(0));
if (!item) {
// workarround a timing problem
Select(index);
item = FullListItemAt(index);
}
if (item) {
// create drag message
BMessage msg('DRAG');
msg.AddPointer("list",(void*)(this));
int32 index;
for (int32 i = 0; (index = FullListCurrentSelection(i)) >= 0; i++) {
msg.AddInt32("index", index);
}
// 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;
for (numItems = 0; BListItem* item = FullListItemAt(CurrentSelection(numItems));
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 && dragBitmap->IsValid()) {
if (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 = FullListCurrentSelection(i);
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
if (itemBounds.bottom > dragRect.bottom)
itemBounds.bottom = dragRect.bottom;
item->DrawItem(v, itemBounds);
itemBounds.top = itemBounds.bottom + 1.0;
}
// make a black frame arround the edge
v->SetHighColor(0, 0, 0, 255);
v->StrokeRect(v->Bounds());
v->Sync();
uint8* bits = (uint8*)dragBitmap->Bits();
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
int32 bpr = dragBitmap->BytesPerRow();
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;
}
}
dragBitmap->Unlock();
}
} else {
delete dragBitmap;
dragBitmap = NULL;
}
if (dragBitmap)
DragMessage(&msg, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0));
else
DragMessage(&msg, dragRect.OffsetToCopy(point), this);
success = true;
}
return success;
}
void
LanguageListView::MouseMoved(BPoint where, uint32 transit, const BMessage* msg)
{
if (msg && (msg->what == 'DRAG')) {
switch (transit) {
case B_ENTERED_VIEW:
case B_INSIDE_VIEW: {
// set drop target through virtual function
// offset where by half of item height
BRect r = ItemFrame(0);
where.y += r.Height() / 2.0;
int32 index = FullListIndexOf(where);
if (index < 0)
index = FullListCountItems();
if (fDropIndex != index) {
fDropIndex = index;
if (fDropIndex >= 0) {
int32 count = FullListCountItems();
if (fDropIndex == count) {
BRect r;
if (FullListItemAt(count - 1)) {
r = ItemFrame(count - 1);
r.top = r.bottom;
r.bottom = r.top + 1.0;
} else {
r = Bounds();
r.bottom--;
// compensate for scrollbars moved slightly
// out of window
}
} else {
BRect r = ItemFrame(fDropIndex);
r.top--;
r.bottom = r.top + 1.0;
}
}
}
break;
}
}
} else {
BOutlineListView::MouseMoved(where, transit, msg);
}
}
LocaleWindow::LocaleWindow()