1743 lines
39 KiB
C++
1743 lines
39 KiB
C++
|
////////////////////////////////////////////////////////////////////////////////
|
|||
|
//
|
|||
|
// File: ListView.cpp
|
|||
|
//
|
|||
|
// Description: BListView represents a one-dimensional list view.
|
|||
|
//
|
|||
|
// Copyright 2001, Ulrich Wimboeck
|
|||
|
//
|
|||
|
////////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include "ListView.h"
|
|||
|
#include <Region.h>
|
|||
|
#include <Window.h>
|
|||
|
#include <ClassInfo.h>
|
|||
|
#include <iostream>
|
|||
|
#include <ScrollView.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
struct track_data
|
|||
|
{
|
|||
|
} ;
|
|||
|
|
|||
|
/**
|
|||
|
* Initializes the new BListView. The frame, name, resizingMode, and flags
|
|||
|
* arguments are identical to those declared for the BView class and are
|
|||
|
* passed unchanged to the BView constructor.
|
|||
|
*
|
|||
|
* The list type can be either:
|
|||
|
* B_SINGLE_SELECTION_LIST
|
|||
|
* The user can select only one item in the list at a time. This is the
|
|||
|
* default setting.
|
|||
|
* B_MULTIPLE_SELECTION_LIST
|
|||
|
* The user can select any number of items by holding down an Option
|
|||
|
* key (for discontinuous selections) or a Shift key (for contiguous
|
|||
|
* selections).
|
|||
|
*/
|
|||
|
BListView::BListView(BRect frame, const char *name,
|
|||
|
list_view_type type /* = B_SINGLE_SELECTION_LIST */,
|
|||
|
uint32 resizeMask /* = B_FOLLOW_LEFT | B_FOLLOW_TOP */,
|
|||
|
uint32 flags /* = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE */)
|
|||
|
: BView(frame, name, resizeMask, flags)
|
|||
|
{
|
|||
|
InitObject(type) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BListView::BListView(BMessage* data)
|
|||
|
: BView(data)
|
|||
|
{
|
|||
|
// if the pointer is null the object should be initialized anyway
|
|||
|
if (data == NULL) {
|
|||
|
InitObject(B_SINGLE_SELECTION_LIST) ;
|
|||
|
return ;
|
|||
|
}
|
|||
|
|
|||
|
{
|
|||
|
if (data->FindInt32("_lv_type", fListType) != B_OK)
|
|||
|
fList = B_SINGLE_SELECTION_LIST ;
|
|||
|
|
|||
|
// first check if a selection message is included in the messgage
|
|||
|
// if there is one allocate memory for it and get it.
|
|||
|
type_code code ;
|
|||
|
|
|||
|
if (data->GetInfo("_2nd_msg", &code) == B_OK )
|
|||
|
{
|
|||
|
if (code == B_MESSAGE_TYPE)
|
|||
|
{
|
|||
|
fSelectMessage = new BMessage() ;
|
|||
|
data->FindMessage("_msg", fSelectMessage) ;
|
|||
|
BInvoker::SetMessage(fSelectMessage) ;
|
|||
|
|
|||
|
// set the fSelectMessage back to NULL
|
|||
|
fSelectMessage = NULL ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// check if there is an invokation message stored
|
|||
|
// in the archiv and set it
|
|||
|
if (data->GetInfo("_msg", &code) == B_OK )
|
|||
|
{
|
|||
|
if (code == B_MESSAGE_TYPE)
|
|||
|
{
|
|||
|
fSelectMessage = new BMessage() ;
|
|||
|
data->FindMessage("_msg", fSelectMessage) ;
|
|||
|
}
|
|||
|
else {
|
|||
|
fSelectMessage = NULL ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int32 count ;
|
|||
|
|
|||
|
// add the item archivied in the message if it was a deep copy
|
|||
|
if (data->GetInfo("_l_items", &code, &count) == B_OK)
|
|||
|
{
|
|||
|
if (code == B_MESSAGE_TYPE)
|
|||
|
{
|
|||
|
BMessage msg ;
|
|||
|
BArchivable* unarchived ;
|
|||
|
BListItem* item ;
|
|||
|
|
|||
|
for (int32 i = 0 ; i < count ; ++i)
|
|||
|
{
|
|||
|
data->FindMessage("_l_items", i, &msg) ;
|
|||
|
unarchived = instantiate_object(data) ;
|
|||
|
item = dynamic_cast<BListItem*>(unarchived) ;
|
|||
|
|
|||
|
if (item != NULL) {
|
|||
|
AddItem(item) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Frees the selection and invocation messages, if any, and any memory
|
|||
|
* allocated to hold the list of items, but not the items themselves.
|
|||
|
*/
|
|||
|
BListView::~BListView()
|
|||
|
{
|
|||
|
// Remove all pointers from the list
|
|||
|
fList.MakeEmpty() ;
|
|||
|
|
|||
|
// delete the select message if there is one
|
|||
|
// the invocation message is deleted by the destructor of BInvoker
|
|||
|
if (fSelectMessage != NULL)
|
|||
|
{
|
|||
|
delete fSelectMessage ;
|
|||
|
fSelectMessage = NULL ;
|
|||
|
}
|
|||
|
|
|||
|
if (fTrack != NULL)
|
|||
|
{
|
|||
|
delete fTrack ;
|
|||
|
fTrack = NULL ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns a new BListView object, allocated by new and created
|
|||
|
* with the version of the constructor that takes a BMessage
|
|||
|
* archive. However, if the archive message doesn't contain
|
|||
|
* data for a BListView object, this function returns NULL.
|
|||
|
*
|
|||
|
* @param data Pointer to a BMessge object containing the data
|
|||
|
* of an archieved BListView object.
|
|||
|
*/
|
|||
|
BArchivable*
|
|||
|
BListView::Instantiate(BMessage* data)
|
|||
|
{
|
|||
|
if (validate_instantiation(data, "BListView"))
|
|||
|
return new BListView(data) ;
|
|||
|
|
|||
|
return NULL ;
|
|||
|
}
|
|||
|
|
|||
|
status_t
|
|||
|
BListView::Archive(BMessage* data, bool deep /* = true */) const
|
|||
|
{
|
|||
|
if (!data)
|
|||
|
return B_ERROR ;
|
|||
|
|
|||
|
BView::Archive(data, deep) ;
|
|||
|
|
|||
|
data->AddString("class", "BListView") ;
|
|||
|
data->AddInt32("_lv_type", fListType) ;
|
|||
|
|
|||
|
if (fSelectMessage) {
|
|||
|
data->AddMessage("_msg", fSelectMessage) ;
|
|||
|
}
|
|||
|
|
|||
|
if (BInvoker::Message()) {
|
|||
|
data->AddMessage("_2nd_msg", BInvoker::Message()) ;
|
|||
|
}
|
|||
|
|
|||
|
if (deep)
|
|||
|
{
|
|||
|
BMessage* msg ;
|
|||
|
|
|||
|
for (int i = 0 ; i < fList.CountItems() ; ++i)
|
|||
|
{
|
|||
|
msg = new BMessage() ;
|
|||
|
ItemAt(i)->Archive(msg, deep) ;
|
|||
|
data->AddMessage("_l_items", msg) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return B_OK ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Calls upon every item in the updateRect area of the view to draw itself.
|
|||
|
* Draw() is called for you whenever the list view is to be updated or
|
|||
|
* redisplayed; you don't need to call it yourself. You also don't need to
|
|||
|
* reimplement it; to change the way items are drawn, define a new version
|
|||
|
* of DrawItem() in a class derived from BListItem.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::Draw(BRect updateRect)
|
|||
|
{
|
|||
|
SetHighColor(0, 0 ,0) ;
|
|||
|
|
|||
|
if (!fList.IsEmpty())
|
|||
|
{
|
|||
|
// Find the first and the last item which has to be updated
|
|||
|
float tmp = 0 ;
|
|||
|
int32 firstIndex = 0 ;
|
|||
|
|
|||
|
for ( ; firstIndex < fList.CountItems() ; ++firstIndex)
|
|||
|
{
|
|||
|
float help = (ItemAt(firstIndex))->Height() ;
|
|||
|
tmp += help ;
|
|||
|
if (tmp >= updateRect.top)
|
|||
|
break ;
|
|||
|
}
|
|||
|
|
|||
|
int32 lastIndex = firstIndex ;
|
|||
|
|
|||
|
for (; lastIndex < fList.CountItems() ; ++lastIndex)
|
|||
|
{
|
|||
|
//Draw the item
|
|||
|
BRect rect(Bounds());
|
|||
|
rect.top = tmp - ItemAt(lastIndex)->Height() ;
|
|||
|
rect.bottom = tmp ;
|
|||
|
rect.right = 2000 ;
|
|||
|
|
|||
|
// BRegion region ;
|
|||
|
// region.Include(rect) ;
|
|||
|
|
|||
|
// ConstrainClippingRegion(®ion) ;
|
|||
|
ItemAt(lastIndex)->DrawItem(this, rect);//, true) ;
|
|||
|
|
|||
|
if (tmp >= updateRect.bottom)
|
|||
|
break ;
|
|||
|
|
|||
|
tmp += ItemAt(lastIndex)->Height() ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::MessageReceived(BMessage *msg)
|
|||
|
{
|
|||
|
switch (msg->what)
|
|||
|
{
|
|||
|
// scripting stuff
|
|||
|
case B_GET_SUPPORTED_SUITES:
|
|||
|
{
|
|||
|
BMessage reply(B_REPLY) ;
|
|||
|
reply.AddString("suites", "suite/vnd.Be-list-view") ;
|
|||
|
msg->SendReply(&reply) ;
|
|||
|
break ;
|
|||
|
}
|
|||
|
case B_COUNT_PROPERTIES:
|
|||
|
{
|
|||
|
BMessage reply(B_REPLY) ;
|
|||
|
reply.AddInt32("result", fList.CountItems()) ;
|
|||
|
msg->SendReply(&reply) ;
|
|||
|
break ;
|
|||
|
}
|
|||
|
case B_EXECUTE_PROPERTY:
|
|||
|
break ;
|
|||
|
case B_GET_PROPERTY:
|
|||
|
break ;
|
|||
|
case B_SET_PROPERTY:
|
|||
|
break ;
|
|||
|
case B_MOUSE_WHEEL_CHANGED:
|
|||
|
break ;
|
|||
|
}
|
|||
|
|
|||
|
BView::MessageReceived(msg) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Responds to B_MOUSE_DOWN messages by selecting items, invoking them
|
|||
|
* (if the mouse-down event is the second of a double-click), and
|
|||
|
* autoscrolling the list (when the user drags with a mouse button down).
|
|||
|
* This function also calls InitiateDrag() to give derived classes the
|
|||
|
* opportunity to drag items. You can implement that function; you shouldn't
|
|||
|
* override (or call) this one.
|
|||
|
*/
|
|||
|
// The docu says shift key and option key like Windows but it does not.
|
|||
|
void
|
|||
|
BListView::MouseDown(BPoint where)
|
|||
|
{
|
|||
|
int32 index = IndexOf(where) ;
|
|||
|
|
|||
|
if (index >= 0)
|
|||
|
{
|
|||
|
bool extend = false ;
|
|||
|
|
|||
|
if ((fListType == B_MULTIPLE_SELECTION_LIST) && (modifiers() & B_SHIFT_KEY))
|
|||
|
extend = true ;
|
|||
|
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
Select(index, extend) ;
|
|||
|
else {
|
|||
|
ItemAt(index)->Deselect() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MakeFocus() ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Permits the user to operate the list using the following keys:
|
|||
|
*
|
|||
|
* Up Arrow and Down Arrow
|
|||
|
* Select the items that are immediately before and immediately after
|
|||
|
* the currently selected item.
|
|||
|
*
|
|||
|
* Page Up and Page Down
|
|||
|
* Select the items that are one viewful above and below the currently
|
|||
|
* selected item—or the first and last items if there's no item a viewful away.
|
|||
|
*
|
|||
|
* Home and End
|
|||
|
* Select the first and last items in the list.
|
|||
|
*
|
|||
|
* Enter and the space bar
|
|||
|
* Invoke the current selection.
|
|||
|
*
|
|||
|
* This function also incorporates the inherited BView version so that the
|
|||
|
* Tab key can navigate to another view. KeyDown() is called to report
|
|||
|
* B_KEY_DOWN messages when the BListView is the focus view of the active
|
|||
|
* window; you shouldn't call it yourself.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::KeyDown(const char *bytes, int32 numBytes)
|
|||
|
{
|
|||
|
switch (*bytes)
|
|||
|
{
|
|||
|
// pressing the home key the first item in the list is selected
|
|||
|
// and made visible
|
|||
|
case B_HOME:
|
|||
|
{
|
|||
|
if (CountItems() > 0)
|
|||
|
{
|
|||
|
Select(0) ;
|
|||
|
ScrollToSelection() ;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
// if the end key is pressed the last entry is selected and
|
|||
|
// made visible
|
|||
|
case B_END:
|
|||
|
{
|
|||
|
if (CountItems() > 0)
|
|||
|
{
|
|||
|
Select(CountItems() - 1) ;
|
|||
|
ScrollToSelection() ;
|
|||
|
}
|
|||
|
break ;
|
|||
|
}
|
|||
|
// select the item above the first selected one
|
|||
|
case B_UP_ARROW:
|
|||
|
if (fFirstSelected > 0)
|
|||
|
{
|
|||
|
Select(fFirstSelected - 1) ;
|
|||
|
ScrollToSelection() ;
|
|||
|
}
|
|||
|
break ;
|
|||
|
// select the item below the last one
|
|||
|
case B_DOWN_ARROW:
|
|||
|
if ((fFirstSelected >= 0) && (fLastSelected < (fList.CountItems() - 1)))
|
|||
|
{
|
|||
|
Select(fLastSelected + 1) ;
|
|||
|
ScrollToSelection() ;
|
|||
|
}
|
|||
|
break ;
|
|||
|
case B_PAGE_UP:
|
|||
|
{
|
|||
|
BRect bounds(Bounds()) ;
|
|||
|
BPoint top(bounds.left, bounds.top) ;
|
|||
|
int32 index = IndexOf(top) ;
|
|||
|
|
|||
|
if (index >= 0)
|
|||
|
{
|
|||
|
BRect frame(ItemFrame(index)) ;
|
|||
|
|
|||
|
if ((frame.bottom - (bounds.bottom - bounds.top)) >= 0)
|
|||
|
ScrollTo(bounds.left, frame.bottom - (bounds.bottom - bounds.top)) ;
|
|||
|
else
|
|||
|
ScrollTo(bounds.left, 0) ;
|
|||
|
}
|
|||
|
|
|||
|
break ;
|
|||
|
}
|
|||
|
case B_PAGE_DOWN:
|
|||
|
{
|
|||
|
BRect bounds(Bounds()) ;
|
|||
|
BPoint bottom(bounds.left, bounds.bottom) ;
|
|||
|
int32 index = IndexOf(bottom) ;
|
|||
|
|
|||
|
if (index >= 0)
|
|||
|
{
|
|||
|
BRect frame(ItemFrame(index)) ;
|
|||
|
float height ;
|
|||
|
GetPreferredSize(NULL, &height) ;
|
|||
|
|
|||
|
if ((bounds.bottom - bounds.top + frame.top) <= height)
|
|||
|
{
|
|||
|
ScrollTo(bounds.left, frame.top) ;
|
|||
|
}
|
|||
|
else {
|
|||
|
ScrollTo(bounds.left, height - (bounds.bottom - bounds.top)) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
// both, the space bar and the return key invoke the current selection
|
|||
|
case B_SPACE:
|
|||
|
case B_RETURN:
|
|||
|
{
|
|||
|
if (fFirstSelected >= 0)
|
|||
|
{
|
|||
|
Invoke() ;
|
|||
|
}
|
|||
|
break ;
|
|||
|
}
|
|||
|
}
|
|||
|
BView::KeyDown(bytes, numBytes) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Overrides the BView version of MakeFocus() to draw an indication that
|
|||
|
* the BListView has become the focus for keyboard events when the
|
|||
|
* focused flag is true, and to remove that indication when the flag is false.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::MakeFocus(bool state /* = true */)
|
|||
|
{
|
|||
|
if (state != IsFocus())
|
|||
|
{
|
|||
|
BView::MakeFocus(state) ;
|
|||
|
}
|
|||
|
|
|||
|
// if the list view is target of a scroll view
|
|||
|
// the border of the scroll view needs to be set to the
|
|||
|
// correct state
|
|||
|
if (fScrollView != NULL)
|
|||
|
{
|
|||
|
fScrollView->SetBorderHighlighted(state) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Updates the on-screen display in response to a notification that
|
|||
|
* the BListView's frame rectangle has been resized. In particular,
|
|||
|
* this function looks for a vertical scroll bar that's a sibling of
|
|||
|
* the BListView. It adjusts this scroll bar to reflect the way the
|
|||
|
* list view was resized, under the assumption that it must have the
|
|||
|
* BListView as its target.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::FrameResized(float newWidth, float newHeight)
|
|||
|
{
|
|||
|
// set the range of the scroll bars of the scroll view
|
|||
|
FixupScrollBar() ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::TargetedByScrollView(BScrollView *scroller)
|
|||
|
{
|
|||
|
// if (fScrollView != NULL)
|
|||
|
{
|
|||
|
// delete fScrollView ;
|
|||
|
}
|
|||
|
|
|||
|
fScrollView = scroller ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::ScrollTo(BPoint where)
|
|||
|
{
|
|||
|
BView::ScrollTo(where) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds an item to the BListView at the end of the list. If necessary,
|
|||
|
* additional memory is allocated to accommodate the new item.
|
|||
|
* Adding an item never removes an item already in the list.
|
|||
|
* If the supplied pointer is NULL the function returns false. Otherwise,
|
|||
|
* it returns true.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::AddItem(BListItem *item)
|
|||
|
{
|
|||
|
// check if the supplied pointer is NULL
|
|||
|
bool bReturn = (item != NULL) ;
|
|||
|
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
if (bReturn = fList.AddItem(static_cast<void*>(item)))
|
|||
|
{
|
|||
|
// If the view is already attached to a view the item needs to be updated
|
|||
|
if (Parent() != NULL)
|
|||
|
{
|
|||
|
BFont font ;
|
|||
|
GetFont(&font) ;
|
|||
|
item->Update(this, &font) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// The new item needs to be drawn if visible
|
|||
|
InvalidateItem(fList.CountItems() - 1) ;
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds an item to the BListView at index. If necessary, additional memory is
|
|||
|
* allocated to accommodate the new item.
|
|||
|
* Adding an item never removes an item already in the list. If the item is
|
|||
|
* added at an index that's already occupied, items currently in the list are
|
|||
|
* bumped down one slot to make room.
|
|||
|
* If index is out of range (greater than the current item count, or less than zero), this function fails and returns false. Otherwise, it returns
|
|||
|
* true
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::AddItem(BListItem *item, int32 atIndex)
|
|||
|
{
|
|||
|
bool bReturn(item != NULL) ;
|
|||
|
|
|||
|
// If successful invalidate all items starting at atIndex
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
if (bReturn = fList.AddItem(static_cast<void*>(item), atIndex))
|
|||
|
{
|
|||
|
if (Parent() != NULL)
|
|||
|
{
|
|||
|
BFont font ;
|
|||
|
GetFont(&font) ;
|
|||
|
item->Update(this, &font) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// The new item needs to drawn if visible
|
|||
|
InvalidateFrom(atIndex) ;
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds the contents of another list to this BListView. The items from
|
|||
|
* the BList are appended to the end of the list.
|
|||
|
* If the supplied pointer or one of the pointers within the list is NULL,
|
|||
|
* the function fails and returns false. If successful, it returns true.
|
|||
|
* The BListView doesn't check to be sure that all the items it adds from the
|
|||
|
* list are pointers to BListItem objects. It assumes that they are; if the
|
|||
|
* assumption is false, the program will crash.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::AddList(BList* newItems)
|
|||
|
{
|
|||
|
bool bReturn(newItems != NULL) ;
|
|||
|
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
for (int32 index = 0 ; index < newItems->CountItems() ; ++index)
|
|||
|
{
|
|||
|
if (newItems->ItemAt(index) == NULL)
|
|||
|
{
|
|||
|
bReturn = false ;
|
|||
|
break ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
int32 index = CountItems() ;
|
|||
|
fList.AddList(newItems) ;
|
|||
|
InvalidateFrom(index) ;
|
|||
|
|
|||
|
if (Parent() != NULL)
|
|||
|
{
|
|||
|
BFont font ;
|
|||
|
GetFont(&font) ;
|
|||
|
|
|||
|
for (int32 index = CountItems() - fList.CountItems() ;
|
|||
|
index < CountItems() ; ++index)
|
|||
|
{
|
|||
|
ItemAt(index)->Update(this, &font) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Adds the contents of another list to this BListView. The items from the
|
|||
|
* BList are inserted at index.
|
|||
|
* If the supplied pointer or one of the pointers within the list is NULL or
|
|||
|
* the index is out of range, the function, fails and returns false.
|
|||
|
* If successful, it returns true.
|
|||
|
* The BListView doesn't check to be sure that all the items it adds from
|
|||
|
* the list are pointers to BListItem objects. It assumes that they are; if the
|
|||
|
* assumption is false, the program will crash.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::AddList(BList *newItems, int32 atIndex)
|
|||
|
{
|
|||
|
bool bReturn(newItems != NULL) ;
|
|||
|
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
for (int32 index = 0 ; index < newItems->CountItems() ; ++index)
|
|||
|
{
|
|||
|
if (newItems->ItemAt(index) == NULL)
|
|||
|
{
|
|||
|
bReturn = false ;
|
|||
|
break ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
fList.AddList(newItems, atIndex) ;
|
|||
|
InvalidateFrom(atIndex) ;
|
|||
|
|
|||
|
if (Parent() != NULL)
|
|||
|
{
|
|||
|
BFont font ;
|
|||
|
GetFont(&font) ;
|
|||
|
|
|||
|
for (int32 index = CountItems() - fList.CountItems() ;
|
|||
|
index < CountItems() ; ++index)
|
|||
|
{
|
|||
|
ItemAt(index)->Update(this, &font) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Removes a single item from the BListView. If passed an index,
|
|||
|
* it removes the item at that index and returns it. If there's no
|
|||
|
* item at the index, it returns NULL. If passed an item, this
|
|||
|
* function looks for that particular item in the list, removes it,
|
|||
|
* and returns true. If it can't find the item, it returns false.
|
|||
|
* If the item is in the list more than once, this function removes
|
|||
|
* only its first occurrence.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::RemoveItem(BListItem* item)
|
|||
|
{
|
|||
|
bool bReturn = false ;
|
|||
|
// Remember the position of the item
|
|||
|
int32 index = IndexOf(item) ;
|
|||
|
bReturn = fList.RemoveItem(static_cast<void*>(item)) ;
|
|||
|
|
|||
|
// update all items with a higher index than the removed item
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
for ( ; index < fList.CountItems() ; ++index)
|
|||
|
{
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
BListItem*
|
|||
|
BListView::RemoveItem(int32 index)
|
|||
|
{
|
|||
|
BListItem* item = static_cast<BListItem*>(fList.RemoveItem(index)) ;
|
|||
|
|
|||
|
// update all items with a higher index than the removed item
|
|||
|
if (item != NULL)
|
|||
|
{
|
|||
|
for ( ; index < fList.CountItems() ; ++index)
|
|||
|
{
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return item ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::RemoveItems(int32 index, int32 count)
|
|||
|
{
|
|||
|
bool bReturn = fList.RemoveItems(index, count) ;
|
|||
|
|
|||
|
// update all items with a higher index than the last removed item
|
|||
|
if (bReturn)
|
|||
|
{
|
|||
|
for ( ; index < fList.CountItems() ; ++index)
|
|||
|
{
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return bReturn ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* These functions set, and return information about, the message that
|
|||
|
* a BListView sends whenever a new item is selected. They're exact
|
|||
|
* counterparts to the functions described above under SetInvocationMessage(),
|
|||
|
* except that the selection message is sent whenever an item in the list
|
|||
|
* is selected, rather than when invoked. It's more common to take action
|
|||
|
* (to initiate a message) when invoking an item than when selecting one.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::SetSelectionMessage(BMessage *message)
|
|||
|
{
|
|||
|
if (fSelectMessage != NULL)
|
|||
|
{
|
|||
|
delete fSelectMessage ;
|
|||
|
}
|
|||
|
|
|||
|
fSelectMessage = message ;
|
|||
|
}
|
|||
|
|
|||
|
BMessage*
|
|||
|
BListView::SelectionMessage() const
|
|||
|
{
|
|||
|
return fSelectMessage ;
|
|||
|
}
|
|||
|
|
|||
|
uint32
|
|||
|
BListView::SelectionCommand() const
|
|||
|
{
|
|||
|
if (fSelectMessage)
|
|||
|
return fSelectMessage->what ;
|
|||
|
else
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::SetInvocationMessage(BMessage *message)
|
|||
|
{
|
|||
|
BInvoker::SetMessage(message) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* These functions set and return information about the BMessage
|
|||
|
* that the BListView sends when currently selected items are invoked.
|
|||
|
* SetInvocationMessage() assigns message to the BListView, freeing
|
|||
|
* any message previously assigned. The message becomes the responsibility
|
|||
|
* of the BListView object and will be freed only when it's replaced by
|
|||
|
* another message or the BListView is freed; you shouldn't free it
|
|||
|
* yourself.
|
|||
|
* Passing a NULL pointer to this function deletes the current message
|
|||
|
* without replacing it.
|
|||
|
* When sending the message, the Invoke() function makes a copy of it
|
|||
|
* and adds two pieces of relevant information—"when" the message is
|
|||
|
* sent and the "source" BListView. These names should not be used for
|
|||
|
* any data that you add to the invocation message.
|
|||
|
* InvocationMessage() returns a pointer to the BMessage and
|
|||
|
* InvocationCommand() returns its what data member. The message
|
|||
|
* belongs to the BListView; it can be altered by adding or removing
|
|||
|
* data, but it shouldn't be deleted. To get rid of the current message,
|
|||
|
* pass a NULL pointer to SetInvocationMessage().
|
|||
|
*/
|
|||
|
BMessage*
|
|||
|
BListView::InvocationMessage() const
|
|||
|
{
|
|||
|
return BInvoker::Message() ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
uint32
|
|||
|
BListView::InvocationCommand() const
|
|||
|
{
|
|||
|
return BInvoker::Command() ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* These functions set and return the list type—whether or not
|
|||
|
* it permits multiple selections. The list_view_type must be either
|
|||
|
* B_SINGLE_SELECTION_LIST or B_MULTIPLE_SELECTION_LIST. The type
|
|||
|
* is first set when the BListView is constructed.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::SetListType(list_view_type type)
|
|||
|
{
|
|||
|
if (type != fListType)
|
|||
|
{
|
|||
|
// When the type is changed from B_MULTIPLE_SELECTION_LIST to
|
|||
|
// B_SINGLE_SELECTION_LIST all selected items will be deselcted.
|
|||
|
if (fListType == B_MULTIPLE_SELECTION_LIST)
|
|||
|
{
|
|||
|
for (int32 item = fFirstSelected ; item <= fLastSelected ; ++item)
|
|||
|
{
|
|||
|
if (ItemAt(item)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(item)->Deselect() ;
|
|||
|
InvalidateItem(item) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
fListType = type ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
list_view_type
|
|||
|
BListView::ListType() const
|
|||
|
{
|
|||
|
return fListType ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* This function returns the BListItem at index in the list, or NULL if the
|
|||
|
* list is empty.
|
|||
|
* The function does not alter the contents of the list—they don't remove the returned
|
|||
|
* item.
|
|||
|
*/
|
|||
|
BListItem*
|
|||
|
BListView::ItemAt(int32 index) const
|
|||
|
{
|
|||
|
return static_cast<BListItem*>(fList.ItemAt(index)) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the index where a particular item whose display rectangle
|
|||
|
* includes a particular point—is located in the list.
|
|||
|
* To determine whether an item lies at the specified point, only
|
|||
|
* the y-coordinate value of the point is considered.
|
|||
|
* If the item isn't in the list or the y-coordinate of the point
|
|||
|
* doesn't intersect with the data rectangle of the BListView, the return
|
|||
|
* value will be a negative number.
|
|||
|
*/
|
|||
|
int32
|
|||
|
BListView::IndexOf(BPoint point) const
|
|||
|
{
|
|||
|
float tmp = 0 ;
|
|||
|
|
|||
|
for (int32 index = 0 ; index < fList.CountItems() ; ++index)
|
|||
|
{
|
|||
|
tmp += ItemAt(index)->Height() ;
|
|||
|
|
|||
|
if (point.y < tmp)
|
|||
|
{
|
|||
|
return index ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return -1 ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the index where a particular item is located in the list.
|
|||
|
* If the item is in the list more than once, the index returned will
|
|||
|
* be the position of its first occurrence.
|
|||
|
* If the item isn't in the list of the BListView, the return value
|
|||
|
* will be a negative number.
|
|||
|
*/
|
|||
|
int32
|
|||
|
BListView::IndexOf(BListItem *item) const
|
|||
|
{
|
|||
|
return fList.IndexOf(static_cast<void*>(item)) ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* This function returns the very first in the list, or NULL if the list is empty.
|
|||
|
* The function does not alter the contents of the list—they don't remove the returned
|
|||
|
* item.
|
|||
|
*/
|
|||
|
BListItem*
|
|||
|
BListView::FirstItem() const
|
|||
|
{
|
|||
|
return static_cast<BListItem*>(fList.FirstItem()) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* This function returns the very last in the list, or NULL if the list is empty.
|
|||
|
* The function does not alter the contents of the list—they don't remove the returned
|
|||
|
* item.
|
|||
|
*/
|
|||
|
|
|||
|
BListItem*
|
|||
|
BListView::LastItem() const
|
|||
|
{
|
|||
|
return static_cast<BListItem*>(fList.FirstItem()) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns true if item is in the list, and false if not.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::HasItem(BListItem *item) const
|
|||
|
{
|
|||
|
return fList.HasItem(static_cast<void*>(item)) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the number of BListItems currently in the list.
|
|||
|
*/
|
|||
|
int32
|
|||
|
BListView::CountItems() const
|
|||
|
{
|
|||
|
return fList.CountItems() ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* MakeEmpty() empties the BListView of all its items, without freeing
|
|||
|
* the BListItem objects.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::MakeEmpty()
|
|||
|
{
|
|||
|
// Remove all items from the list
|
|||
|
fList.MakeEmpty() ;
|
|||
|
fFirstSelected = -1 ;
|
|||
|
|
|||
|
// update the list view
|
|||
|
Invalidate() ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* IsEmpty() returns true if the list is empty (if it contains no items),
|
|||
|
* and false otherwise.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::IsEmpty() const
|
|||
|
{
|
|||
|
return fList.IsEmpty() ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Calls the func function once for each item in the BListView.
|
|||
|
* BListItems are visited in order, beginning with the first one in
|
|||
|
* the list (index 0) and ending with the last.
|
|||
|
* If a call to func returns true, the iteration is stopped, even
|
|||
|
* if some items have not yet been visited.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::DoForEach(bool (*func)(BListItem *))
|
|||
|
{
|
|||
|
fList.DoForEach(reinterpret_cast<bool (*)(void*)>(func)) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Calls the func function once for each item in the BListView.
|
|||
|
* BListItems are visited in order, beginning with the first one in
|
|||
|
* the list (index 0) and ending with the last.
|
|||
|
* If a call to func returns true, the iteration is stopped, even
|
|||
|
* if some items have not yet been visited.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::DoForEach(bool (*func)(BListItem *, void *), void* parameter)
|
|||
|
{
|
|||
|
fList.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func), parameter) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns a pointer to the BListView's list of BListItems. You can index
|
|||
|
* directly into the list of items if you're certain that the index is in range:
|
|||
|
* BListItem *item = Items()[index] ;
|
|||
|
*
|
|||
|
* Although the practice is discouraged, you can also step through the list
|
|||
|
* of items by incrementing the list pointer that Items() returns. Be aware
|
|||
|
* that the list isn't null-terminated—you have to detect the end of the
|
|||
|
* list by some other means. The simplest method is to count items:
|
|||
|
*
|
|||
|
* BListItem **ptr = myListView->Items() ;
|
|||
|
*
|
|||
|
* for ( long i = myListView->CountItems(); i > 0; i-- )
|
|||
|
* {
|
|||
|
* . . .
|
|||
|
* *ptr++ ;
|
|||
|
* }
|
|||
|
*
|
|||
|
* You should never use the items pointer to alter the contents of the list.
|
|||
|
*/
|
|||
|
const BListItem**
|
|||
|
BListView::Items() const
|
|||
|
{
|
|||
|
return reinterpret_cast<const BListItem**>(fList.Items()) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Invalidates the item at index so that an update message will
|
|||
|
* be sent forcing the BListView to redraw it.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::InvalidateItem(int32 index)
|
|||
|
{
|
|||
|
if (index <= fList.CountItems())
|
|||
|
{
|
|||
|
// Invalidate the rectangle of the list item
|
|||
|
Invalidate(Bounds() | ItemFrame(index)) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::ScrollToSelection()
|
|||
|
{
|
|||
|
if (fFirstSelected != -1)
|
|||
|
{
|
|||
|
float tmp = 0 ;
|
|||
|
int32 index = 0 ;
|
|||
|
|
|||
|
for ( ; index < fFirstSelected ; ++index)
|
|||
|
{
|
|||
|
tmp += ItemAt(index)->Height() ;
|
|||
|
}
|
|||
|
|
|||
|
BRect rect (Bounds()) ;
|
|||
|
|
|||
|
if (tmp < rect.top)
|
|||
|
{
|
|||
|
ScrollTo(0, tmp) ;
|
|||
|
}
|
|||
|
else if ((tmp + ItemAt(index)->Height()) > rect.bottom)
|
|||
|
{
|
|||
|
ScrollTo(0, tmp + ItemAt(index)->Height() - (rect.bottom - rect.top)) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Selects the item at the index
|
|||
|
* if extend is false all former selections will be removed
|
|||
|
* if extend is true the
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::Select(int32 index, bool extend /* = false */)
|
|||
|
{
|
|||
|
// The index must be in range
|
|||
|
if (index < fList.CountItems() && (index >= 0))
|
|||
|
{
|
|||
|
// Deselect all selected items
|
|||
|
if ((fFirstSelected != -1) && (!extend))
|
|||
|
{
|
|||
|
for (int32 item = fFirstSelected ; item <= fLastSelected ; ++item)
|
|||
|
{
|
|||
|
if ((ItemAt(item)->IsSelected()) && (item != index))
|
|||
|
{
|
|||
|
ItemAt(item)->Deselect() ;
|
|||
|
InvalidateItem(item) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// No item is selected any more
|
|||
|
fFirstSelected = -1 ;
|
|||
|
}
|
|||
|
|
|||
|
if (fFirstSelected == -1)
|
|||
|
{
|
|||
|
fFirstSelected = index ;
|
|||
|
fLastSelected = index ;
|
|||
|
}
|
|||
|
else if (index < fFirstSelected)
|
|||
|
fFirstSelected = index ;
|
|||
|
else if (index > fLastSelected)
|
|||
|
fLastSelected = index ;
|
|||
|
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(index)->Select() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
|
|||
|
SelectionChanged() ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::Select(int32 from, int32 to, bool extend /* = false */)
|
|||
|
{
|
|||
|
if ((from <= to) && (to < fList.CountItems()))
|
|||
|
{
|
|||
|
// Deselect all current selected items
|
|||
|
if (!extend)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
for (int32 index = from ; index <= to ; ++index)
|
|||
|
{
|
|||
|
ItemAt(index)->Select() ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns true if the item at index is currently selected, and false if it's not.
|
|||
|
* It also returns false if the index is not in the range an therefoe does not
|
|||
|
* exist.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::IsItemSelected(int32 index) const
|
|||
|
{
|
|||
|
if ((fFirstSelected >= 0) && (index >= fFirstSelected) && (index <= fLastSelected))
|
|||
|
return ItemAt(index)->IsSelected() ;
|
|||
|
|
|||
|
return false ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the index of a currently selected item in the list, or
|
|||
|
* a negative number if no item is selected.
|
|||
|
* The domain of the index passed as an argument is the current set
|
|||
|
* of selected items; the first selected item is at index 0, the second
|
|||
|
* at index 1, and so on, even if the selection is not contiguous. The
|
|||
|
* domain of the returned index is the set of all items in the list.
|
|||
|
*
|
|||
|
* To get all currently selected items, increment the passed index until
|
|||
|
* the function returns a negative number.
|
|||
|
*/
|
|||
|
int32
|
|||
|
BListView::CurrentSelection(int32 index /* = 0 */) const
|
|||
|
{
|
|||
|
if ((index >= 0) && (fFirstSelected >= 0))
|
|||
|
{
|
|||
|
for (int32 count = (fFirstSelected > index ? fFirstSelected : index) ;
|
|||
|
count <= fLastSelected ; ++count)
|
|||
|
{
|
|||
|
if (ItemAt(count)->IsSelected())
|
|||
|
{
|
|||
|
--index ;
|
|||
|
|
|||
|
if (index == 0)
|
|||
|
{
|
|||
|
return count ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return -1 ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Augments the BInvoker version of Invoke() to add three pieces of information
|
|||
|
* to each message the BListView sends:
|
|||
|
*
|
|||
|
* "when" - B_INT64_TYPE
|
|||
|
* When the message is sent, as measured by the number of microseconds
|
|||
|
* since 12:00:00 AM 1970.
|
|||
|
*
|
|||
|
* "source" - B_POINTER_TYPE
|
|||
|
* A pointer to the BListView object.
|
|||
|
*
|
|||
|
* "index" - B_INT32_TYPE
|
|||
|
* An array containing the index of every selected item.
|
|||
|
*
|
|||
|
* This function is called to send both the selection message and the
|
|||
|
* invocation message. It can also be called from application code. The default
|
|||
|
* target of the message (established by AttachedToWindow()) is the BWindow
|
|||
|
* where the BListView is located.
|
|||
|
* What it means to "invoke" selected items depends entirely on the
|
|||
|
* invocation BMessage and the receiver's response to it. This function does
|
|||
|
* nothing but send the message.
|
|||
|
*/
|
|||
|
|
|||
|
// check if it is done in the right way
|
|||
|
status_t
|
|||
|
BListView::Invoke(BMessage* msg /* = NULL */)
|
|||
|
{
|
|||
|
return BInvoker::Invoke(msg) ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* This function deselects all the items.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::DeselectAll()
|
|||
|
{
|
|||
|
if (fFirstSelected != -1)
|
|||
|
{
|
|||
|
for (int32 index = fFirstSelected ; index <= fLastSelected ; ++index)
|
|||
|
{
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(index)->Deselect() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* This function deselects all the items except those from index start through
|
|||
|
* index finish.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::DeselectExcept(int32 except_from, int32 except_to)
|
|||
|
{
|
|||
|
// if no item is selected -> nothing to do
|
|||
|
if ((fFirstSelected != -1) && (except_from <= except_to))
|
|||
|
{
|
|||
|
for (int32 index = fFirstSelected ; index < except_from ; ++index)
|
|||
|
{
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(index)->Deselect() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
for (int32 index = except_to + 1 ; index <= fLastSelected ; ++index)
|
|||
|
{
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(index)->Deselect() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SelectionChanged() ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* These functions deselect the item at index.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::Deselect(int32 index)
|
|||
|
{
|
|||
|
if (fFirstSelected != -1)
|
|||
|
{
|
|||
|
if ((index < fLastSelected) && (index >= fFirstSelected))
|
|||
|
{
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
{
|
|||
|
ItemAt(index)->Deselect() ;
|
|||
|
InvalidateItem(index) ;
|
|||
|
SelectionChanged() ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Implemented by derived class
|
|||
|
void
|
|||
|
BListView::SelectionChanged()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::SortItems(int (*cmp)(const void *, const void *))
|
|||
|
{
|
|||
|
fList.SortItems(cmp) ;
|
|||
|
Invalidate() ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* These functions bottleneck through DoMiscellaneous() */
|
|||
|
bool
|
|||
|
BListView::SwapItems(int32 a, int32 b)
|
|||
|
{
|
|||
|
bool success = true ;
|
|||
|
|
|||
|
if ((a >= 0) && (a < fList.CountItems()) && (b >= 0) && (b < fList.CountItems()))
|
|||
|
{
|
|||
|
// just swap if a is not b
|
|||
|
if (a != b)
|
|||
|
{
|
|||
|
// ToDo chack if it is done correct
|
|||
|
BListItem* item = RemoveItem(a) ;
|
|||
|
AddItem(item, b - 1) ;
|
|||
|
item = RemoveItem(b) ;
|
|||
|
AddItem(item, a) ;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
success = false ;
|
|||
|
}
|
|||
|
|
|||
|
return success ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* MoveItem() moves the item located at the index from to the index
|
|||
|
* specified by the to argument.
|
|||
|
* This function returns true if the requested operation is
|
|||
|
* completed successfully, or false if the operation failed (for example,
|
|||
|
* if a specified index is out of range).
|
|||
|
*/
|
|||
|
|
|||
|
// Is redraw neccessary????
|
|||
|
bool
|
|||
|
BListView::MoveItem(int32 from, int32 to)
|
|||
|
{
|
|||
|
bool success = true ;
|
|||
|
|
|||
|
if ((to >= 0) && (to < fList.CountItems()))
|
|||
|
{
|
|||
|
// no move required if from would be to
|
|||
|
if (from != to)
|
|||
|
{
|
|||
|
BListItem* item = RemoveItem(from) ;
|
|||
|
|
|||
|
if (item != NULL)
|
|||
|
AddItem(item, to - 1) ;
|
|||
|
else
|
|||
|
success = false ;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
success = false ;
|
|||
|
}
|
|||
|
|
|||
|
return success ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::ReplaceItem(int32 index, BListItem* item)
|
|||
|
{
|
|||
|
bool success = true ;
|
|||
|
|
|||
|
// otherwise the "new" item would be deleted
|
|||
|
if (ItemAt(index) != item)
|
|||
|
{
|
|||
|
BListItem* old = RemoveItem(index) ;
|
|||
|
|
|||
|
if (old != NULL)
|
|||
|
{
|
|||
|
AddItem(item, index) ;
|
|||
|
delete old ;
|
|||
|
}
|
|||
|
// In this case the index is not in the range
|
|||
|
else {
|
|||
|
success = false ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return success ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Sets up the BListView and makes the BWindow to which it has become
|
|||
|
* attached the target for the messages it sends when items are selected
|
|||
|
* or invoked—provided another target hasn't already been set. In addition,
|
|||
|
* this function calls Update() for each item in the list to give it a
|
|||
|
* chance to adjust its layout. The BListView's vertical scroll bar is
|
|||
|
* also adjusted.
|
|||
|
* This function is called for you when the BListView becomes part of a
|
|||
|
* window's view hierarchy.
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::AttachedToWindow()
|
|||
|
{
|
|||
|
// If no target is set the window to which the ListView is attached will
|
|||
|
// become the target
|
|||
|
if (BInvoker::Target() == NULL)
|
|||
|
{
|
|||
|
BInvoker::SetTarget(BView::Window()) ;
|
|||
|
}
|
|||
|
|
|||
|
// call the update function of all items in the list
|
|||
|
for (int32 index = 0 ; index < fList.CountItems() ; ++index)
|
|||
|
{
|
|||
|
BFont font ;
|
|||
|
BView::GetFont(&font) ;
|
|||
|
ItemAt(index)->Update(this, &font) ;
|
|||
|
|
|||
|
if (fWidth < ItemAt(index)->Width())
|
|||
|
fWidth = ItemAt(index)->Width() ;
|
|||
|
}
|
|||
|
|
|||
|
// Adjust the ScrollBars.
|
|||
|
FixupScrollBar() ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::FrameMoved(BPoint new_position)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Returns the frame rectangle of the BListItem at index. The rectangle is stated
|
|||
|
* in the coordinate system of the BListView and defines the area where the item
|
|||
|
* is drawn. Items can differ in height, (but all have the same width ??).
|
|||
|
*/
|
|||
|
BRect
|
|||
|
BListView::ItemFrame(int32 index)
|
|||
|
{
|
|||
|
BRect rect ;
|
|||
|
|
|||
|
if ((index < fList.CountItems()) && (index >= 0))
|
|||
|
{
|
|||
|
rect.left = 0 ;
|
|||
|
|
|||
|
for (int32 item = 0 ; item < index ; ++item)
|
|||
|
{
|
|||
|
rect.top += ItemAt(item)->Height() ;
|
|||
|
}
|
|||
|
|
|||
|
rect.bottom = rect.top + ItemAt(index)->Height() ;
|
|||
|
rect.right = Bounds().right ;
|
|||
|
}
|
|||
|
|
|||
|
return rect ;
|
|||
|
}
|
|||
|
|
|||
|
BHandler*
|
|||
|
BListView::ResolveSpecifier(BMessage *msg, int32 index,
|
|||
|
BMessage *specifier, int32 form,
|
|||
|
const char *property)
|
|||
|
{
|
|||
|
return NULL ;
|
|||
|
}
|
|||
|
|
|||
|
status_t
|
|||
|
BListView::GetSupportedSuites(BMessage *data)
|
|||
|
{
|
|||
|
return B_OK ;
|
|||
|
}
|
|||
|
|
|||
|
status_t
|
|||
|
BListView::Perform(perform_code d, void *arg)
|
|||
|
{
|
|||
|
return B_OK ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::WindowActivated(bool state)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::MouseUp(BPoint pt)
|
|||
|
{
|
|||
|
int32 index = IndexOf(pt) ;
|
|||
|
|
|||
|
if ((index > 0) && (fListType == B_MULTIPLE_SELECTION_LIST) && ((modifiers() & B_SHIFT_KEY)))
|
|||
|
{
|
|||
|
if (!ItemAt(index)->IsSelected())
|
|||
|
Deselect(index) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::DetachedFromWindow()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Implemented by derived classes to permit users to drag items.
|
|||
|
* This function is called from the BListView's MouseDown() function;
|
|||
|
* it should initiate the drag-and-drop operation and return true,
|
|||
|
* or refuse to do so and return false. By default, it always
|
|||
|
* returns false.
|
|||
|
* The point that's passed to InitiateDrag() is the same as the
|
|||
|
* point passed to MouseDown(); it's where the cursor was located
|
|||
|
* when the user pressed the mouse button. The index of the item
|
|||
|
* under the cursor (the item that would be dragged) is passed as the
|
|||
|
* second argument, and the wasSelected flag indicates whether or
|
|||
|
* not the item was selected before the mouse button went down.
|
|||
|
*
|
|||
|
* A BListView allows users to autoscroll the list by holding the
|
|||
|
* mouse button down and dragging outside its frame rectangle. If a
|
|||
|
* derived class implements InitiateDrag() to drag an item each time
|
|||
|
* the user moves the mouse with a button down, it will hide this
|
|||
|
* autoscrolling behavior. Therefore, derived classes typically
|
|||
|
* permit users to drag items only if they're already selected (if
|
|||
|
* wasSelected is true). In other words, it takes two mouse-down events
|
|||
|
* to drag an item—one to select it and one to begin dragging it.
|
|||
|
*/
|
|||
|
bool
|
|||
|
BListView::InitiateDrag(BPoint pt, int32 itemIndex, bool initialySelected)
|
|||
|
{
|
|||
|
return false ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::ResizeToPreferred()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::GetPreferredSize(float* width, float* height)
|
|||
|
{
|
|||
|
if (height != NULL)
|
|||
|
{
|
|||
|
*height = 0 ;
|
|||
|
|
|||
|
for (int32 index = 0 ; index < CountItems() ; ++index)
|
|||
|
{
|
|||
|
*height += ItemAt(index)->Height() ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (width != NULL)
|
|||
|
*width = 0 ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::AllAttached()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::AllDetached()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
// protected!
|
|||
|
|
|||
|
bool
|
|||
|
BListView::DoMiscellaneous(MiscCode code, MiscData* data)
|
|||
|
{
|
|||
|
switch(code)
|
|||
|
{
|
|||
|
case B_NO_OP:
|
|||
|
break;
|
|||
|
|
|||
|
case B_REPLACE_OP:
|
|||
|
data->replace.index ;
|
|||
|
data->replace.item ;
|
|||
|
break ;
|
|||
|
|
|||
|
case B_MOVE_OP:
|
|||
|
data->move.from ;
|
|||
|
data->move.to ;
|
|||
|
break ;
|
|||
|
|
|||
|
case B_SWAP_OP:
|
|||
|
data->swap.a ;
|
|||
|
data->swap.b ;
|
|||
|
break ;
|
|||
|
}
|
|||
|
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
/*----- Private or reserved -----------------------------------------*/
|
|||
|
|
|||
|
void
|
|||
|
BListView::InitObject(list_view_type type)
|
|||
|
{
|
|||
|
fList.MakeEmpty() ;
|
|||
|
fListType = type ;
|
|||
|
fFirstSelected = -1 ;
|
|||
|
/*
|
|||
|
int32 fLastSelected;
|
|||
|
int32 fAnchorIndex;
|
|||
|
*/
|
|||
|
fWidth = 0 ;
|
|||
|
fSelectMessage = NULL ;
|
|||
|
fScrollView = NULL ;
|
|||
|
fTrack = NULL ;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Updates the scroll bars if the list view is targetted by a scroll view
|
|||
|
*/
|
|||
|
void
|
|||
|
BListView::FixupScrollBar()
|
|||
|
{
|
|||
|
// set the range of the scroll bars of the scroll view
|
|||
|
if (fScrollView != NULL)
|
|||
|
{
|
|||
|
BScrollBar* bar ;
|
|||
|
float height ;
|
|||
|
float width ;
|
|||
|
BRect bounds(Bounds()) ;
|
|||
|
|
|||
|
GetPreferredSize(&width, &height) ;
|
|||
|
height -= (bounds.bottom - bounds.top) ;
|
|||
|
width -= (bounds.right - bounds.left) ;
|
|||
|
|
|||
|
if (height < 0)
|
|||
|
height = 0 ;
|
|||
|
|
|||
|
if (width < 0)
|
|||
|
width = 0 ;
|
|||
|
|
|||
|
if ((bar = fScrollView->ScrollBar(B_HORIZONTAL)) != NULL)
|
|||
|
{
|
|||
|
bar->SetRange(0, width) ;
|
|||
|
bar->SetSteps(ItemAt(0)->Height(), bounds.bottom - bounds.top) ;
|
|||
|
}
|
|||
|
|
|||
|
if ((bar = fScrollView->ScrollBar(B_VERTICAL)) != NULL)
|
|||
|
{
|
|||
|
bar->SetRange(0, height) ;
|
|||
|
bar->SetSteps(ItemAt(0)->Height(), bounds.bottom - bounds.top) ;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::InvalidateFrom(int32 index)
|
|||
|
{
|
|||
|
if ((index >= 0) && (index < CountItems()))
|
|||
|
{
|
|||
|
BRect frame(ItemFrame(index)) ;
|
|||
|
|
|||
|
for (++index ; index < fList.CountItems() ; ++index)
|
|||
|
frame.bottom += ItemAt(index)->Height() ;
|
|||
|
|
|||
|
// build the rect which needs an update
|
|||
|
BRect bounds(Bounds()) ;
|
|||
|
frame = frame & bounds ;
|
|||
|
frame = frame | bounds ;
|
|||
|
Invalidate(frame) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
inline status_t
|
|||
|
BListView::PostMsg(BMessage* msg)
|
|||
|
{
|
|||
|
return BInvoker::Invoke(msg) ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::FontChanged()
|
|||
|
{
|
|||
|
// all items need to be updated
|
|||
|
for (int32 i = 0 ; i < fList.CountItems() ; ++i)
|
|||
|
{
|
|||
|
ItemAt(i)->Update(this, NULL) ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
int32
|
|||
|
BListView::RangeCheck(int32 index)
|
|||
|
{
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::_Select(int32 index, bool extend)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::_Select(int32 from, int32 to, bool extend)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::_Deselect(int32 index)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::Deselect(int32 from, int32 to)
|
|||
|
{
|
|||
|
for ( ; (from <= to) && (from < fList.CountItems()) ; ++from)
|
|||
|
{
|
|||
|
ItemAt(from)->Deselect() ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::_DeselectAll(int32 except_from, int32 except_to)
|
|||
|
{
|
|||
|
for (int32 i = 0 ; i < CountItems() ; ++i)
|
|||
|
{
|
|||
|
if (i == except_from)
|
|||
|
{
|
|||
|
i = except_to ;
|
|||
|
if (i >= CountItems())
|
|||
|
break ;
|
|||
|
}
|
|||
|
|
|||
|
ItemAt(i)->Deselect() ;
|
|||
|
}
|
|||
|
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::PerformDelayedSelect()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::TryInitiateDrag(BPoint where)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
int32
|
|||
|
BListView::CalcFirstSelected(int32 after)
|
|||
|
{
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
int32
|
|||
|
BListView::CalcLastSelected(int32 before)
|
|||
|
{
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::DrawItem(BListItem* item, BRect itemRect,
|
|||
|
bool complete /* = false */)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::DoSwapItems(int32 a, int32 b)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::DoMoveItem(int32 from, int32 to)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
bool
|
|||
|
BListView::DoReplaceItem(int32 index, BListItem* item)
|
|||
|
{
|
|||
|
return true ;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::RescanSelection(int32 from, int32 to)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::DoMouseUp(BPoint where)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
BListView::DoMouseMoved(BPoint where)
|
|||
|
{
|
|||
|
}
|