haiku/src/kits/interface/ListView.cpp
Marc Flerackers 007ed8c58b Compilation fixes and BOutlineListView
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3538 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-06-16 07:55:04 +00:00

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(&notify);
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 $
*
*/