007ed8c58b
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3538 a95241bf-73f2-0310-859d-f6bbb57e9c96
1395 lines
33 KiB
C++
1395 lines
33 KiB
C++
//------------------------------------------------------------------------------
|
|
// Copyright (c) 2001-2002, OpenBeOS
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal in the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// File Name: ListView.cpp
|
|
// Author: Ulrich Wimboeck
|
|
// Marc Flerackers (mflerackers@androme.be)
|
|
// Description: BListView represents a one-dimensional list view.
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Standard Includes -----------------------------------------------------------
|
|
|
|
// System Includes -------------------------------------------------------------
|
|
#include <ListView.h>
|
|
#include <ScrollBar.h>
|
|
#include <ScrollView.h>
|
|
#include <support/Errors.h>
|
|
#include <PropertyInfo.h>
|
|
#include <Window.h>
|
|
|
|
// Project Includes ------------------------------------------------------------
|
|
|
|
// Local Includes --------------------------------------------------------------
|
|
|
|
// Local Defines ---------------------------------------------------------------
|
|
|
|
// Globals ---------------------------------------------------------------------
|
|
static property_info prop_list[] =
|
|
{
|
|
{ "Item", { B_COUNT_PROPERTIES, 0 }, { B_DIRECT_SPECIFIER, 0 },
|
|
"Returns the number of BListItems currently in the list." },
|
|
{ "Item", { B_EXECUTE_PROPERTY, 0 }, { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER,
|
|
B_RANGE_SPECIFIER, B_REVERSE_RANGE_SPECIFIER, 0 },
|
|
"Select and invoke the specified items, first removing any existing selection." },
|
|
{ "Selection", { B_COUNT_PROPERTIES, 0 }, { B_DIRECT_SPECIFIER, 0 },
|
|
"Returns int32 count of items in the selection." },
|
|
{ "Selection", { B_EXECUTE_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 },
|
|
"Invoke items in selection." },
|
|
{ "Selection", { B_GET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 },
|
|
"Returns int32 indices of all items in the selection." },
|
|
{ "Selection", { B_SET_PROPERTY, 0 }, { B_INDEX_SPECIFIER, B_REVERSE_INDEX_SPECIFIER,
|
|
B_RANGE_SPECIFIER, B_REVERSE_RANGE_SPECIFIER, 0 },
|
|
"Extends current selection or deselects specified items. Boolean field \"data\" "
|
|
"chooses selection or deselection." },
|
|
{ "Selection", { B_SET_PROPERTY, 0 }, { B_DIRECT_SPECIFIER, 0 },
|
|
"Select or deselect all items in the selection. Boolean field \"data\" chooses "
|
|
"selection or deselection." },
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
BListView::BListView(BRect frame, const char *name, list_view_type type,
|
|
uint32 resizingMode, uint32 flags)
|
|
: BView(frame, name, resizingMode, flags)
|
|
{
|
|
InitObject(type);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListView::BListView(BMessage *archive)
|
|
: BView(archive)
|
|
{
|
|
int32 listType;
|
|
|
|
archive->FindInt32("_lv_type", &listType);
|
|
fListType = (list_view_type)listType;
|
|
|
|
fFirstSelected = -1;
|
|
fLastSelected = -1;
|
|
fAnchorIndex = -1;
|
|
|
|
fSelectMessage = NULL;
|
|
fScrollView = NULL;
|
|
fTrack = NULL;
|
|
|
|
fWidth = Bounds().Width();
|
|
|
|
int32 i = 0;
|
|
BMessage subData;
|
|
|
|
while (archive->FindMessage("_l_items", i++, &subData))
|
|
{
|
|
BArchivable *object = instantiate_object(&subData);
|
|
|
|
if (!object)
|
|
continue;
|
|
|
|
BListItem *item = dynamic_cast<BListItem*>(object);
|
|
|
|
if (!item)
|
|
continue;
|
|
|
|
AddItem(item);
|
|
}
|
|
|
|
if (archive->HasMessage("_msg"))
|
|
{
|
|
BMessage *invokationMessage = new BMessage;
|
|
|
|
archive->FindMessage("_msg", invokationMessage);
|
|
SetInvocationMessage(invokationMessage);
|
|
}
|
|
|
|
if (archive->HasMessage("_2nd_msg"))
|
|
{
|
|
BMessage *selectionMessage = new BMessage;
|
|
|
|
archive->FindMessage("_2nd_msg", selectionMessage);
|
|
SetSelectionMessage(selectionMessage);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListView::~BListView()
|
|
{
|
|
SetSelectionMessage(NULL);
|
|
|
|
if (fSelectMessage)
|
|
delete fSelectMessage;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BArchivable *BListView::Instantiate(BMessage *archive)
|
|
{
|
|
if (validate_instantiation(archive, "BListView"))
|
|
return new BListView(archive);
|
|
else
|
|
return NULL;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
status_t BListView::Archive(BMessage *archive, bool deep) const
|
|
{
|
|
BView::Archive ( archive, deep );
|
|
|
|
archive->AddInt32("_lv_type", fListType);
|
|
|
|
if (deep)
|
|
{
|
|
int32 i = 0;
|
|
BListItem *item;
|
|
|
|
while ((item = ItemAt(i++)))
|
|
{
|
|
BMessage subData;
|
|
|
|
if (item->Archive(&subData, true) != B_OK)
|
|
continue;
|
|
|
|
archive->AddMessage("_l_items", &subData);
|
|
}
|
|
}
|
|
|
|
if (InvocationMessage())
|
|
archive->AddMessage("_msg", InvocationMessage());
|
|
|
|
if (fSelectMessage)
|
|
archive->AddMessage("_2nd_msg", fSelectMessage);
|
|
|
|
return B_OK;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::Draw(BRect updateRect)
|
|
{
|
|
for (int i = 0; i < CountItems(); i++)
|
|
{
|
|
BRect item_frame = ItemFrame(i);
|
|
|
|
if (item_frame.Intersects(updateRect))
|
|
DrawItem(((BListItem*)ItemAt(i)), item_frame);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MessageReceived ( BMessage *msg )
|
|
{
|
|
switch ( msg->what )
|
|
{
|
|
case B_COUNT_PROPERTIES:
|
|
case B_EXECUTE_PROPERTY:
|
|
case B_GET_PROPERTY:
|
|
case B_SET_PROPERTY:
|
|
{
|
|
BPropertyInfo propInfo ( prop_list );
|
|
BMessage specifier;
|
|
const char *property;
|
|
|
|
if ( msg->GetCurrentSpecifier ( NULL, &specifier ) != B_OK ||
|
|
specifier.FindString ( "property", &property ) != B_OK )
|
|
return;
|
|
|
|
switch ( propInfo.FindMatch ( msg, 0, &specifier, msg->what, property ) )
|
|
{
|
|
case B_ERROR:
|
|
BView::MessageReceived ( msg );
|
|
break;
|
|
|
|
case 0:
|
|
{
|
|
BMessage reply ( B_REPLY );
|
|
|
|
reply.AddInt32 ( "result", CountItems () );
|
|
reply.AddInt32 ( "error", B_OK );
|
|
|
|
msg->SendReply ( &reply );
|
|
break;
|
|
}
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
{
|
|
BMessage reply ( B_REPLY );
|
|
|
|
int32 count = 0;
|
|
|
|
for ( int32 i = 0; i < CountItems (); i++ )
|
|
if ( ItemAt ( i )->IsSelected () )
|
|
count++;
|
|
|
|
reply.AddInt32 ( "result", count );
|
|
reply.AddInt32 ( "error", B_OK );
|
|
|
|
msg->SendReply ( &reply );
|
|
break;
|
|
}
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
{
|
|
BMessage reply ( B_REPLY );
|
|
|
|
for ( int32 i = 0; i < CountItems (); i++ )
|
|
if ( ItemAt ( i )->IsSelected () )
|
|
reply.AddInt32 ( "result", i );
|
|
|
|
reply.AddInt32 ( "error", B_OK );
|
|
|
|
msg->SendReply ( &reply );
|
|
break;
|
|
}
|
|
case 5:
|
|
break;
|
|
case 6:
|
|
{
|
|
BMessage reply ( B_REPLY );
|
|
|
|
bool select;
|
|
|
|
msg->FindBool ( "data", &select );
|
|
|
|
if ( select )
|
|
Select ( 0, CountItems () - 1, false );
|
|
else
|
|
DeselectAll ();
|
|
|
|
reply.AddInt32 ( "error", B_OK );
|
|
|
|
msg->SendReply ( &reply );
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case B_SELECT_ALL:
|
|
{
|
|
Select(0, CountItems() - 1, false);
|
|
break;
|
|
}
|
|
default:
|
|
BView::MessageReceived(msg);
|
|
}
|
|
|
|
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MouseDown(BPoint point)
|
|
{
|
|
if (!IsFocus())
|
|
{
|
|
MakeFocus();
|
|
Sync();
|
|
Window()->UpdateIfNeeded();
|
|
}
|
|
|
|
int index = IndexOf(point);
|
|
|
|
if (index > -1)
|
|
{
|
|
BMessage *message = Looper()->CurrentMessage();
|
|
int32 clicks;
|
|
int32 modifiers;
|
|
|
|
message->FindInt32("clicks", &clicks);
|
|
message->FindInt32("modifiers", &modifiers);
|
|
|
|
bool extend = false;
|
|
|
|
if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers & B_CONTROL_KEY))
|
|
extend = true;
|
|
|
|
if (clicks == 2)
|
|
{
|
|
if (!ItemAt(index)->IsSelected())
|
|
Select(index, extend);
|
|
Invoke();
|
|
}
|
|
if (!InitiateDrag(point, index, IsItemSelected(index)))
|
|
{
|
|
if (CurrentSelection() == -1 || (!ItemAt(index)->IsSelected() &&
|
|
!(modifiers & B_SHIFT_KEY)))
|
|
fAnchorIndex = index;
|
|
|
|
if (modifiers & B_SHIFT_KEY)
|
|
Select(fAnchorIndex, index, extend);
|
|
else
|
|
{
|
|
if (!ItemAt(index)->IsSelected())
|
|
Select(index, extend);
|
|
else
|
|
{
|
|
ItemAt(index)->Deselect();
|
|
InvalidateItem(index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: InitiateDrag
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::KeyDown(const char *bytes, int32 numBytes)
|
|
{
|
|
switch ( bytes[0] )
|
|
{
|
|
case B_UP_ARROW:
|
|
{
|
|
if (fFirstSelected == -1)
|
|
break;
|
|
|
|
bool extend = false;
|
|
|
|
if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY))
|
|
extend = true;
|
|
|
|
Select (fFirstSelected - 1, extend);
|
|
|
|
ScrollToSelection ();
|
|
|
|
break;
|
|
}
|
|
case B_DOWN_ARROW:
|
|
{
|
|
if (fFirstSelected == -1)
|
|
break;
|
|
|
|
bool extend = false;
|
|
|
|
if (fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY))
|
|
extend = true;
|
|
|
|
Select (fLastSelected + 1, extend);
|
|
|
|
ScrollToSelection ();
|
|
|
|
break;
|
|
}
|
|
case B_HOME:
|
|
{
|
|
Select ( 0, fListType == B_MULTIPLE_SELECTION_LIST );
|
|
|
|
ScrollToSelection ();
|
|
|
|
break;
|
|
}
|
|
case B_END:
|
|
{
|
|
Select ( CountItems () - 1, fListType == B_MULTIPLE_SELECTION_LIST );
|
|
|
|
ScrollToSelection ();
|
|
|
|
break;
|
|
}
|
|
case B_RETURN:
|
|
case B_SPACE:
|
|
{
|
|
Invoke ();
|
|
|
|
break;
|
|
}
|
|
default:
|
|
BView::KeyDown ( bytes, numBytes );
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MakeFocus(bool focused)
|
|
{
|
|
if (IsFocus() == focused)
|
|
return;
|
|
|
|
BView::MakeFocus(focused);
|
|
|
|
if (fScrollView)
|
|
fScrollView->SetBorderHighlighted(focused);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::FrameResized(float width, float height)
|
|
{
|
|
// TODO
|
|
FixupScrollBar();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::TargetedByScrollView(BScrollView *view)
|
|
{
|
|
fScrollView = view;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::ScrollTo(BPoint point)
|
|
{
|
|
BView::ScrollTo(point);
|
|
fWidth = Bounds().right;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::AddItem(BListItem *item, int32 index)
|
|
{
|
|
if (!fList.AddItem(item, index))
|
|
return false;
|
|
|
|
if (fFirstSelected != -1 && index < fFirstSelected)
|
|
fFirstSelected++;
|
|
|
|
if (fLastSelected != -1 && index < fLastSelected)
|
|
fLastSelected++;
|
|
|
|
if (Window())
|
|
{
|
|
BFont font;
|
|
GetFont(&font);
|
|
|
|
item->Update(this, &font);
|
|
|
|
FixupScrollBar();
|
|
InvalidateFrom(index);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::AddItem(BListItem *item)
|
|
{
|
|
if (!fList.AddItem(item))
|
|
return false;
|
|
|
|
if (Window())
|
|
{
|
|
BFont font;
|
|
GetFont(&font);
|
|
|
|
item->Update(this, &font);
|
|
|
|
FixupScrollBar();
|
|
InvalidateItem(CountItems() - 1);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::AddList(BList *list, int32 index)
|
|
{
|
|
if (!fList.AddList(list, index))
|
|
return false;
|
|
|
|
int32 count = fList.CountItems();
|
|
|
|
if (fFirstSelected != -1 && index < fFirstSelected)
|
|
fFirstSelected += count;
|
|
|
|
if (fLastSelected != -1 && index < fLastSelected)
|
|
fLastSelected += count;
|
|
|
|
if (Window())
|
|
{
|
|
BFont font;
|
|
GetFont(&font);
|
|
|
|
int32 i = 0;
|
|
while(BListItem *item = (BListItem*)list->ItemAt(i))
|
|
{
|
|
item->Update(this, &font);
|
|
i++;
|
|
}
|
|
|
|
FixupScrollBar();
|
|
Invalidate(); // TODO
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::AddList(BList *list)
|
|
{
|
|
return AddList(list, CountItems());
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListItem *BListView::RemoveItem(int32 index)
|
|
{
|
|
BListItem *item = ItemAt(index);
|
|
|
|
if (!item)
|
|
return NULL;
|
|
|
|
if (item->IsSelected())
|
|
Deselect(index);
|
|
|
|
if(!fList.RemoveItem(item))
|
|
return item;
|
|
|
|
if (fFirstSelected != -1 && index < fFirstSelected)
|
|
fFirstSelected--;
|
|
|
|
if (fLastSelected != -1 && index < fLastSelected)
|
|
fLastSelected--;
|
|
|
|
InvalidateFrom(index);
|
|
FixupScrollBar();
|
|
|
|
return item;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::RemoveItem(BListItem *item)
|
|
{
|
|
return RemoveItem(IndexOf(item)) != NULL;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::RemoveItems(int32 index, int32 count)
|
|
{
|
|
if (index >= CountItems())
|
|
index = -1;
|
|
|
|
if (index < 0)
|
|
return false;
|
|
|
|
while (count--)
|
|
RemoveItem(index);
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::SetSelectionMessage(BMessage *message)
|
|
{
|
|
if (fSelectMessage)
|
|
delete fSelectMessage;
|
|
|
|
fSelectMessage = message;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::SetInvocationMessage(BMessage *message)
|
|
{
|
|
BInvoker::SetMessage(message);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BMessage *BListView::InvocationMessage() const
|
|
{
|
|
return BInvoker::Message();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
uint32 BListView::InvocationCommand() const
|
|
{
|
|
return BInvoker::Command();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BMessage *BListView::SelectionMessage() const
|
|
{
|
|
return fSelectMessage;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
uint32 BListView::SelectionCommand() const
|
|
{
|
|
if (fSelectMessage)
|
|
return fSelectMessage->what;
|
|
else
|
|
return 0;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::SetListType(list_view_type type)
|
|
{
|
|
if (fListType == B_MULTIPLE_SELECTION_LIST &&
|
|
type == B_SINGLE_SELECTION_LIST)
|
|
DeselectAll();
|
|
|
|
fListType = type;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
list_view_type BListView::ListType() const
|
|
{
|
|
return fListType;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListItem *BListView::ItemAt(int32 index) const
|
|
{
|
|
return (BListItem*)fList.ItemAt(index);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::IndexOf(BListItem *item) const
|
|
{
|
|
return fList.IndexOf(item);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::IndexOf(BPoint point) const
|
|
{
|
|
float y = 0.0f;
|
|
|
|
for (int i = 0; i < fList.CountItems(); i++)
|
|
{
|
|
y += ItemAt(i)->Height();
|
|
|
|
if ( point.y < y )
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListItem *BListView::FirstItem() const
|
|
{
|
|
return (BListItem*)fList.FirstItem();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BListItem *BListView::LastItem() const
|
|
{
|
|
return (BListItem*)fList.LastItem();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::HasItem(BListItem *item) const
|
|
{
|
|
return fList.HasItem(item);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::CountItems() const
|
|
{
|
|
return fList.CountItems();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MakeEmpty()
|
|
{
|
|
_DeselectAll(-1, -1);
|
|
fList.MakeEmpty();
|
|
//virtual(&int32[2])
|
|
Invalidate();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::IsEmpty() const
|
|
{
|
|
return fList.IsEmpty();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DoForEach(bool (*func)(BListItem *))
|
|
{
|
|
fList.DoForEach(reinterpret_cast<bool (*)(void*)>(func));
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DoForEach(bool (*func)(BListItem *, void *), void *arg )
|
|
{
|
|
fList.DoForEach(reinterpret_cast<bool (*)(void*, void*)>(func), arg);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
const BListItem **BListView::Items() const
|
|
{
|
|
return (const BListItem**)fList.Items();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::InvalidateItem(int32 index)
|
|
{
|
|
Invalidate(Bounds() & ItemFrame(index));
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::ScrollToSelection ()
|
|
{
|
|
BRect item_frame = ItemFrame ( CurrentSelection ( 0 ) );
|
|
|
|
if ( Bounds ().Intersects ( item_frame.InsetByCopy ( 0.0f, 2.0f ) ) )
|
|
return;
|
|
|
|
if ( item_frame.top < Bounds ().top )
|
|
ScrollTo ( 0, item_frame.top );
|
|
else
|
|
ScrollTo ( 0, item_frame.bottom - Bounds ().Height () );
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::Select(int32 index, bool extend)
|
|
{
|
|
_Select(index, extend);
|
|
|
|
SelectionChanged();
|
|
InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::Select(int32 start, int32 finish, bool extend)
|
|
{
|
|
_Select(start, finish, extend);
|
|
|
|
SelectionChanged();
|
|
InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::IsItemSelected(int32 index) const
|
|
{
|
|
BListItem *item = ItemAt(index);
|
|
|
|
if (item)
|
|
return item->IsSelected();
|
|
else
|
|
return false;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::CurrentSelection(int32 index) const
|
|
{
|
|
if (fFirstSelected == -1)
|
|
return -1;
|
|
|
|
if (index == 0)
|
|
return fFirstSelected;
|
|
|
|
for (int32 i = fFirstSelected; i <= fLastSelected; i++)
|
|
{
|
|
if (ItemAt(i)->IsSelected())
|
|
{
|
|
if (index == 0)
|
|
return i;
|
|
|
|
index--;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
status_t BListView::Invoke(BMessage *message)
|
|
{
|
|
bool notify = false;
|
|
uint32 kind = InvokeKind(¬ify);
|
|
|
|
BMessage clone(kind);
|
|
status_t err = B_BAD_VALUE;
|
|
|
|
if (!message && !notify)
|
|
message = Message();
|
|
|
|
if (!message)
|
|
{
|
|
if (!IsWatched())
|
|
return err;
|
|
}
|
|
else
|
|
clone = *message;
|
|
|
|
clone.AddInt64("when", (int64)system_time());
|
|
clone.AddPointer("source", this);
|
|
clone.AddMessenger("be:sender", BMessenger(this));
|
|
|
|
if (fListType == B_SINGLE_SELECTION_LIST)
|
|
clone.AddInt32("index", fFirstSelected);
|
|
else
|
|
{
|
|
for (int32 i = fFirstSelected; i <= fLastSelected; i++)
|
|
{
|
|
if (ItemAt(i)->IsSelected())
|
|
clone.AddInt32("index", i);
|
|
}
|
|
}
|
|
|
|
if (message)
|
|
err = BInvoker::Invoke(&clone);
|
|
|
|
// TODO: assynchronous messaging
|
|
// SendNotices(kind, &clone);
|
|
|
|
return err;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DeselectAll()
|
|
{
|
|
if (fFirstSelected == -1)
|
|
return;
|
|
|
|
for (int32 index = fFirstSelected; index <= fLastSelected; ++index)
|
|
{
|
|
if (!ItemAt(index)->IsSelected())
|
|
{
|
|
ItemAt(index)->Deselect();
|
|
InvalidateItem(index);
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DeselectExcept(int32 start, int32 finish)
|
|
{
|
|
if (fFirstSelected == -1 || finish < start)
|
|
return;
|
|
|
|
int32 index;
|
|
|
|
for (index = fFirstSelected; index < start; ++index)
|
|
{
|
|
if (!ItemAt(index)->IsSelected())
|
|
{
|
|
ItemAt(index)->Deselect();
|
|
InvalidateItem(index);
|
|
}
|
|
}
|
|
for (index = finish + 1; index <= fLastSelected; ++index)
|
|
{
|
|
if (!ItemAt(index)->IsSelected())
|
|
{
|
|
ItemAt(index)->Deselect();
|
|
InvalidateItem(index);
|
|
}
|
|
}
|
|
|
|
SelectionChanged();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::Deselect(int32 index)
|
|
{
|
|
if (_Deselect(index))
|
|
{
|
|
SelectionChanged();
|
|
InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::SelectionChanged()
|
|
{
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::SortItems(int (*cmp)(const void *, const void *))
|
|
{
|
|
if (_DeselectAll(-1, -1))
|
|
{
|
|
SelectionChanged();
|
|
InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED);
|
|
}
|
|
|
|
fList.SortItems(cmp);
|
|
Invalidate();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::SwapItems(int32 a, int32 b)
|
|
{
|
|
MiscData data;
|
|
|
|
data.swap.a = a;
|
|
data.swap.b = b;
|
|
|
|
return DoMiscellaneous(B_SWAP_OP, &data);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::MoveItem(int32 from, int32 to)
|
|
{
|
|
MiscData data;
|
|
|
|
data.move.from = from;
|
|
data.move.to = to;
|
|
|
|
return DoMiscellaneous(B_MOVE_OP, &data);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::ReplaceItem(int32 index, BListItem *item)
|
|
{
|
|
MiscData data;
|
|
|
|
data.replace.index = index;
|
|
data.replace.item = item;
|
|
|
|
return DoMiscellaneous(B_REPLACE_OP, &data);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::AttachedToWindow()
|
|
{
|
|
BView::AttachedToWindow();
|
|
FontChanged();
|
|
|
|
if (!Messenger().IsValid())
|
|
SetTarget(Window(), NULL);
|
|
|
|
FixupScrollBar();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::FrameMoved(BPoint new_position)
|
|
{
|
|
BView::FrameMoved(new_position);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BRect BListView::ItemFrame(int32 index)
|
|
{
|
|
BRect frame(0, 0, Bounds().Width(), -1);
|
|
|
|
if (index < 0 || index >= CountItems())
|
|
return frame;
|
|
|
|
for (int32 i = 0; i <= index; i++)
|
|
{
|
|
frame.top = frame.bottom + 1;
|
|
frame.bottom += (float)ceil(ItemAt(i)->Height());
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
BHandler *BListView::ResolveSpecifier(BMessage *msg, int32 index,
|
|
BMessage *specifier, int32 form,
|
|
const char *property)
|
|
{
|
|
BPropertyInfo propInfo(prop_list);
|
|
|
|
if (propInfo.FindMatch(msg, 0, specifier, form, property) < 0)
|
|
return BView::ResolveSpecifier(msg, index, specifier, form, property);
|
|
|
|
// TODO: msg->AddInt32("_match_code_", );
|
|
|
|
return this;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
status_t BListView::GetSupportedSuites( BMessage *data )
|
|
{
|
|
data->AddString("suites", "suite/vnd.Be-list-view");
|
|
data->AddFlat("messages", &BPropertyInfo(prop_list));
|
|
|
|
return BView::GetSupportedSuites(data);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
status_t BListView::Perform(perform_code d, void *arg)
|
|
{
|
|
return BView::Perform(d, arg);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::WindowActivated(bool state)
|
|
{
|
|
BView::WindowActivated(state);
|
|
|
|
if (IsFocus())
|
|
Draw(Bounds());
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MouseUp(BPoint pt)
|
|
{
|
|
if (fWidth == 0)
|
|
return;
|
|
|
|
DoMouseMoved(pt);
|
|
DoMouseUp(pt);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::MouseMoved(BPoint pt, uint32 code, const BMessage *msg)
|
|
{
|
|
if (fTrack == NULL)
|
|
return;
|
|
|
|
if (TryInitiateDrag(pt))
|
|
return;
|
|
|
|
DoMouseMoved(pt);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DetachedFromWindow()
|
|
{
|
|
BView::DetachedFromWindow();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::InitiateDrag(BPoint point, int32 index, bool wasSelected)
|
|
{
|
|
return false;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::ResizeToPreferred()
|
|
{
|
|
BView::ResizeToPreferred();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::GetPreferredSize(float *width, float *height)
|
|
{
|
|
BView::GetPreferredSize(width, height);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::AllAttached()
|
|
{
|
|
BView::AllAttached();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::AllDetached()
|
|
{
|
|
BView::AllDetached();
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::DoMiscellaneous(MiscCode code, MiscData *data)
|
|
{
|
|
if (code > B_SWAP_OP)
|
|
return false;
|
|
|
|
switch (code)
|
|
{
|
|
case B_NO_OP:
|
|
{
|
|
break;
|
|
}
|
|
case B_REPLACE_OP:
|
|
{
|
|
return ReplaceItem(data->replace.index, data->replace.item);
|
|
}
|
|
case B_MOVE_OP:
|
|
{
|
|
return MoveItem(data->move.from, data->move.to);
|
|
}
|
|
case B_SWAP_OP:
|
|
{
|
|
return SwapItems(data->swap.a, data->swap.b);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::_ReservedListView2() {}
|
|
void BListView::_ReservedListView3() {}
|
|
void BListView::_ReservedListView4() {}
|
|
//------------------------------------------------------------------------------
|
|
BListView &BListView::operator=(const BListView &)
|
|
{
|
|
return *this;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::InitObject(list_view_type type)
|
|
{
|
|
fListType = type;
|
|
fFirstSelected = -1;
|
|
fLastSelected = -1;
|
|
fAnchorIndex = -1;
|
|
fWidth = Bounds().Width();
|
|
fSelectMessage = NULL;
|
|
fScrollView = NULL;
|
|
fTrack = NULL;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::FixupScrollBar()
|
|
{
|
|
BRect bounds, frame;
|
|
BScrollBar *vertScroller = ScrollBar(B_VERTICAL);
|
|
|
|
if (!vertScroller)
|
|
return;
|
|
|
|
bounds = Bounds();
|
|
int32 count = CountItems();
|
|
|
|
float y = 0;
|
|
|
|
for (int32 i = 0; i < count; i++)
|
|
{
|
|
frame = ItemFrame(i);
|
|
y += frame.Height();
|
|
}
|
|
|
|
if (bounds.Height() > y)
|
|
{
|
|
vertScroller->SetRange(0.0f, 0.0f);
|
|
vertScroller->SetValue(0.0f);
|
|
}
|
|
else
|
|
{
|
|
vertScroller->SetRange(0.0f, y - bounds.Height());
|
|
vertScroller->SetProportion(bounds.Height () / y);
|
|
}
|
|
|
|
if (count != 0)
|
|
vertScroller->SetSteps((float)ceil(FirstItem()->Height()),
|
|
bounds.Height());
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::InvalidateFrom(int32 index)
|
|
{
|
|
if (index <= fList.CountItems())
|
|
Invalidate(Bounds() & ItemFrame(index));
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::FontChanged()
|
|
{
|
|
BFont font;
|
|
GetFont(&font);
|
|
|
|
for (int i = 0; i < CountItems (); i ++)
|
|
ItemAt(i)->Update(this, &font);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::_Select(int32 index, bool extend)
|
|
{
|
|
if (index < 0 || index >= CountItems())
|
|
return false;
|
|
|
|
if ((fFirstSelected != -1) && (!extend))
|
|
{
|
|
for (int32 item = fFirstSelected; item <= fLastSelected; ++item)
|
|
{
|
|
if ((ItemAt(item)->IsSelected()) && (item != index))
|
|
{
|
|
ItemAt(item)->Deselect();
|
|
InvalidateItem(item);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::_Select(int32 from, int32 to, bool extend)
|
|
{
|
|
if (to < from)
|
|
return false;
|
|
|
|
if ((fFirstSelected != -1) && (!extend))
|
|
{
|
|
for (int32 item = fFirstSelected; item <= fLastSelected; ++item)
|
|
{
|
|
if ((ItemAt(item)->IsSelected()) && (item < from || item > to))
|
|
{
|
|
ItemAt(item)->Deselect();
|
|
InvalidateItem(item);
|
|
}
|
|
}
|
|
|
|
fFirstSelected = -1;
|
|
}
|
|
|
|
if (fFirstSelected == -1)
|
|
{
|
|
fFirstSelected = from;
|
|
fLastSelected = to;
|
|
}
|
|
else if (from < fFirstSelected)
|
|
fFirstSelected = from;
|
|
else if (to > fLastSelected)
|
|
fLastSelected = to;
|
|
|
|
for (int32 item = from; item <= to; ++item)
|
|
{
|
|
if (!ItemAt(item)->IsSelected())
|
|
{
|
|
ItemAt(item)->Select();
|
|
InvalidateItem(item);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::_Deselect(int32 index)
|
|
{
|
|
if (index < 0 || index >= CountItems())
|
|
return false;
|
|
|
|
if (!Window()->Lock())
|
|
return false;
|
|
|
|
BListItem *item = ItemAt(index);
|
|
|
|
if (item->IsSelected())
|
|
{
|
|
BRect frame(ItemFrame(index));
|
|
BRect bounds(Bounds());
|
|
|
|
item->Deselect();
|
|
|
|
if (fFirstSelected == index && fLastSelected == index)
|
|
{
|
|
fFirstSelected = -1;
|
|
fLastSelected = -1;
|
|
}
|
|
else
|
|
{
|
|
if (fFirstSelected == index)
|
|
fFirstSelected = CalcFirstSelected(index);
|
|
|
|
if (fLastSelected == index)
|
|
fLastSelected = CalcLastSelected(index);
|
|
}
|
|
|
|
if (bounds.Intersects(frame))
|
|
DrawItem(ItemAt(index), frame, true);
|
|
}
|
|
|
|
Window()->Unlock();
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::Deselect(int32 from, int32 to)
|
|
{
|
|
if (from < 0 || from >= CountItems() || to < 0 || to >= CountItems())
|
|
return;
|
|
|
|
bool changed = false;
|
|
|
|
for (int32 i = from; i <= to; i++)
|
|
{
|
|
if (_Deselect(i))
|
|
changed = true;
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
SelectionChanged();
|
|
InvokeNotify(fSelectMessage, B_CONTROL_MODIFIED);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::_DeselectAll(int32 except_from, int32 except_to)
|
|
{
|
|
if (fFirstSelected == -1)
|
|
return true;
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::TryInitiateDrag(BPoint where)
|
|
{
|
|
return false;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::CalcFirstSelected(int32 after)
|
|
{
|
|
if (after >= CountItems())
|
|
return -1;
|
|
|
|
for (int32 i = after; i < CountItems(); i++)
|
|
{
|
|
if (ItemAt(i)->IsSelected())
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
int32 BListView::CalcLastSelected(int32 before)
|
|
{
|
|
if (before < 0)
|
|
return -1;
|
|
|
|
for (int32 i = before; i >= 0; i--)
|
|
{
|
|
if (ItemAt(i)->IsSelected())
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DrawItem(BListItem *item, BRect itemRect, bool complete)
|
|
{
|
|
item->DrawItem(this, itemRect, complete);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::DoSwapItems(int32 a, int32 b)
|
|
{
|
|
if (!fList.SwapItems(a, b))
|
|
return false;
|
|
|
|
Invalidate(ItemFrame(a));
|
|
Invalidate(ItemFrame(b));
|
|
|
|
if (fAnchorIndex == a)
|
|
fAnchorIndex = b;
|
|
else if (fAnchorIndex == b)
|
|
fAnchorIndex = a;
|
|
|
|
RescanSelection(a, b);
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::DoMoveItem(int32 from, int32 to)
|
|
{
|
|
BRect frameFrom = ItemFrame(from);
|
|
BRect frameTo = ItemFrame(to);
|
|
|
|
if (!fList.MoveItem(from, to))
|
|
return false;
|
|
|
|
RescanSelection(from, to);
|
|
|
|
BRect frame = frameFrom | frameTo;
|
|
|
|
if (Bounds().Intersects(frame))
|
|
Invalidate(Bounds() & frame);
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
bool BListView::DoReplaceItem(int32 index, BListItem *item)
|
|
{
|
|
BRect frame = ItemFrame(index);
|
|
|
|
if (!fList.ReplaceItem(index, item))
|
|
return false;
|
|
|
|
if (frame != ItemFrame(index))
|
|
InvalidateFrom(index);
|
|
else
|
|
Invalidate(frame);
|
|
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::RescanSelection(int32 from, int32 to)
|
|
{
|
|
if (from > to)
|
|
{
|
|
int32 tmp = from;
|
|
from = to;
|
|
to = tmp;
|
|
}
|
|
|
|
if (fAnchorIndex != -1)
|
|
{
|
|
if (fAnchorIndex == from)
|
|
fAnchorIndex = to;
|
|
else if (fAnchorIndex == to)
|
|
fAnchorIndex = from;
|
|
}
|
|
|
|
/* if (from < fFirstSelected && from < fLastSelected)
|
|
return;
|
|
|
|
if (to > fFirstSelected && to > fLastSelected)
|
|
return;*/
|
|
|
|
int32 i;
|
|
|
|
for (i = from; i <= to; i++)
|
|
{
|
|
if (ItemAt(i)->IsSelected())
|
|
{
|
|
fFirstSelected = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = from; i <= to; i++)
|
|
if (ItemAt(i)->IsSelected())
|
|
fLastSelected = i;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DoMouseUp(BPoint where)
|
|
{
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
void BListView::DoMouseMoved(BPoint where)
|
|
{
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* $Log $
|
|
*
|
|
* $Id $
|
|
*
|
|
*/
|