Update BLayout::ItemAdded() and BLayout::ItemRemoved() to take an int32 index parameter, and ItemAdded() to return a bool indicating success or failure. Update BLayout::AddItem() to take the result of ItemAdded() into account. Also update BLayout::AllUnarchived() to take this into account. In either situation, if ItemAdded() returns false, the item does not get added to the layout. Removed various TODOs about code that could be removed once this change was made. In BSplitLayout, an item's LayoutData was lazy-initialized, but would always be created during ItemAdded(). Now we create the LayoutData explicitly, so that we can catch failed memory allocations. Closes #5524.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37817 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Alex Wilson
2010-07-30 02:28:17 +00:00
parent 0265102f8b
commit 6829d4174b
10 changed files with 97 additions and 82 deletions
+2 -2
View File
@@ -36,8 +36,8 @@ public:
static BArchivable* Instantiate(BMessage* from); static BArchivable* Instantiate(BMessage* from);
protected: protected:
virtual void ItemAdded(BLayoutItem* item); virtual bool ItemAdded(BLayoutItem* item, int32 atIndex);
virtual void ItemRemoved(BLayoutItem* item); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex);
private: private:
BSize fMin; BSize fMin;
+2 -2
View File
@@ -63,8 +63,8 @@ public:
BLayoutItem* item, int32 index); BLayoutItem* item, int32 index);
protected: protected:
virtual void ItemAdded(BLayoutItem* item); virtual bool ItemAdded(BLayoutItem* item, int32 atIndex);
virtual void ItemRemoved(BLayoutItem* item); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex);
virtual bool HasMultiColumnItems(); virtual bool HasMultiColumnItems();
virtual bool HasMultiRowItems(); virtual bool HasMultiRowItems();
+2 -2
View File
@@ -45,8 +45,8 @@ public:
BLayoutItem* item, int32 index); BLayoutItem* item, int32 index);
protected: protected:
virtual void ItemAdded(BLayoutItem* item); virtual bool ItemAdded(BLayoutItem* item, int32 atIndex);
virtual void ItemRemoved(BLayoutItem* item); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex);
virtual void PrepareItems(enum orientation orientation); virtual void PrepareItems(enum orientation orientation);
+2 -4
View File
@@ -60,10 +60,8 @@ public:
virtual status_t ItemUnarchived(const BMessage* from, virtual status_t ItemUnarchived(const BMessage* from,
BLayoutItem* item, int32 index); BLayoutItem* item, int32 index);
protected: protected:
// TODO: Since memory allocations can fail, we should return a bool and virtual bool ItemAdded(BLayoutItem* item, int32 atIndex);
// undo the addition, if false. virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex);
virtual void ItemAdded(BLayoutItem* item);
virtual void ItemRemoved(BLayoutItem* item);
private: private:
friend class BView; friend class BView;
+4 -3
View File
@@ -234,15 +234,16 @@ BCardLayout::Instantiate(BMessage* from)
} }
void bool
BCardLayout::ItemAdded(BLayoutItem* item) BCardLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{ {
item->SetVisible(false); item->SetVisible(false);
return true;
} }
void void
BCardLayout::ItemRemoved(BLayoutItem* item) BCardLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
{ {
if (fVisibleItem == item) { if (fVisibleItem == item) {
BLayoutItem* newVisibleItem = NULL; BLayoutItem* newVisibleItem = NULL;
+6 -15
View File
@@ -493,8 +493,6 @@ status_t
BGridLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const BGridLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
{ {
ItemLayoutData* data = _LayoutDataForItem(item); ItemLayoutData* data = _LayoutDataForItem(item);
if (!data) // TODO: remove this check once AddItem() returns a bool
return B_ERROR;
status_t err = into->AddInt32(kItemDimensionsField, data->dimensions.x); status_t err = into->AddInt32(kItemDimensionsField, data->dimensions.x);
if (err == B_OK) if (err == B_OK)
@@ -513,12 +511,8 @@ BGridLayout::ItemUnarchived(const BMessage* from,
BLayoutItem* item, int32 index) BLayoutItem* item, int32 index)
{ {
ItemLayoutData* data = _LayoutDataForItem(item); ItemLayoutData* data = _LayoutDataForItem(item);
if (!data) { // TODO: remove this check once AddItem() returns a bool
data = new ItemLayoutData();
item->SetLayoutData(data);
}
Dimensions& dimensions = data->dimensions; Dimensions& dimensions = data->dimensions;
index *= 4; index *= 4;
// each item stores 4 int32s into kItemDimensionsField // each item stores 4 int32s into kItemDimensionsField
status_t err = from->FindInt32(kItemDimensionsField, index, &dimensions.x); status_t err = from->FindInt32(kItemDimensionsField, index, &dimensions.x);
@@ -552,21 +546,18 @@ BGridLayout::ItemUnarchived(const BMessage* from,
} }
void bool
BGridLayout::ItemAdded(BLayoutItem* item) BGridLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{ {
item->SetLayoutData(new ItemLayoutData); item->SetLayoutData(new(nothrow) ItemLayoutData);
return item->LayoutData() != NULL;
} }
void void
BGridLayout::ItemRemoved(BLayoutItem* item) BGridLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
{ {
ItemLayoutData* data = _LayoutDataForItem(item); ItemLayoutData* data = _LayoutDataForItem(item);
// TODO: Once ItemAdded() returns a bool, we can remove this check.
if (!data)
return;
Dimensions itemDimensions = data->dimensions; Dimensions itemDimensions = data->dimensions;
item->SetLayoutData(NULL); item->SetLayoutData(NULL);
delete data; delete data;
+10 -12
View File
@@ -13,6 +13,9 @@
#include <new> #include <new>
using std::nothrow;
namespace { namespace {
const char* const kItemWeightField = "BGroupLayout:item:weight"; const char* const kItemWeightField = "BGroupLayout:item:weight";
const char* const kVerticalField = "BGroupLayout:vertical"; const char* const kVerticalField = "BGroupLayout:vertical";
@@ -204,7 +207,7 @@ BArchivable*
BGroupLayout::Instantiate(BMessage* from) BGroupLayout::Instantiate(BMessage* from)
{ {
if (validate_instantiation(from, "BGroupLayout")) if (validate_instantiation(from, "BGroupLayout"))
return new(std::nothrow) BGroupLayout(from); return new(nothrow) BGroupLayout(from);
return NULL; return NULL;
} }
@@ -213,13 +216,7 @@ status_t
BGroupLayout::ItemArchived(BMessage* into, BGroupLayout::ItemArchived(BMessage* into,
BLayoutItem* item, int32 index) const BLayoutItem* item, int32 index) const
{ {
BGroupLayout::ItemLayoutData* data = return into->AddFloat(kItemWeightField, _LayoutDataForItem(item)->weight);
(BGroupLayout::ItemLayoutData*)item->LayoutData();
if (!data) // TODO: remove this once ItemAdded() returns a bool
return B_BAD_VALUE;
return into->AddFloat(kItemWeightField, data->weight);
} }
@@ -237,15 +234,16 @@ BGroupLayout::ItemUnarchived(const BMessage* from,
} }
void bool
BGroupLayout::ItemAdded(BLayoutItem* item) BGroupLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{ {
item->SetLayoutData(new(std::nothrow) ItemLayoutData); item->SetLayoutData(new(nothrow) ItemLayoutData);
return item->LayoutData() != NULL;
} }
void void
BGroupLayout::ItemRemoved(BLayoutItem* item) BGroupLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
{ {
if (ItemLayoutData* data = _LayoutDataForItem(item)) { if (ItemLayoutData* data = _LayoutDataForItem(item)) {
item->SetLayoutData(NULL); item->SetLayoutData(NULL);
+41 -21
View File
@@ -18,6 +18,7 @@
using std::nothrow; using std::nothrow;
namespace { namespace {
const char* const kLayoutItemField = "BLayout:items"; const char* const kLayoutItemField = "BLayout:items";
} }
@@ -93,20 +94,29 @@ BLayout::AddItem(int32 index, BLayoutItem* item)
// if the item refers to a BView, we make sure it is added to the parent // if the item refers to a BView, we make sure it is added to the parent
// view // view
bool addedView = false;
BView* view = item->View(); BView* view = item->View();
if (view && view->fParent != fView && !fView->_AddChild(view, NULL)) if (view && view->fParent != fView
&& !(addedView = fView->_AddChild(view, NULL)))
return false; return false;
// validate the index // validate the index
if (index < 0 || index > fItems.CountItems()) if (index < 0 || index > fItems.CountItems())
index = fItems.CountItems(); index = fItems.CountItems();
fItems.AddItem(item, index); if (fItems.AddItem(item, index) && ItemAdded(item, index)) {
ItemAdded(item); item->SetLayout(this);
item->SetLayout(this); InvalidateLayout();
InvalidateLayout(); return true;
} else {
return true; // this check is necessary so that if an addition somewhere other
// than the end of the list fails, we don't remove the wrong item
if (fItems.ItemAt(index) == item)
fItems.RemoveItem(index);
if (addedView)
view->_RemoveSelf();
return false;
}
} }
@@ -154,7 +164,7 @@ BLayout::RemoveItem(int32 index)
view->_RemoveSelf(); view->_RemoveSelf();
item->SetLayout(NULL); item->SetLayout(NULL);
ItemRemoved(item); ItemRemoved(item, index);
InvalidateLayout(); InvalidateLayout();
return item; return item;
@@ -233,7 +243,6 @@ BLayout::AllUnarchived(const BMessage* from)
{ {
BUnarchiver unarchiver(from); BUnarchiver unarchiver(from);
status_t err = BArchivable::AllUnarchived(from); status_t err = BArchivable::AllUnarchived(from);
if (err != B_OK) if (err != B_OK)
return err; return err;
@@ -241,24 +250,34 @@ BLayout::AllUnarchived(const BMessage* from)
unarchiver.ArchiveMessage()->GetInfo(kLayoutItemField, NULL, &itemCount); unarchiver.ArchiveMessage()->GetInfo(kLayoutItemField, NULL, &itemCount);
for (int32 i = 0; i < itemCount && err == B_OK; i++) { for (int32 i = 0; i < itemCount && err == B_OK; i++) {
BLayoutItem* item; BLayoutItem* item;
err = unarchiver.FindObject(kLayoutItemField, i, item); err = unarchiver.FindObject(kLayoutItemField,
i, BUnarchiver::B_DONT_ASSUME_OWNERSHIP, item);
if (err != B_OK)
return err;
if (err == B_OK && item) { if (!fItems.AddItem(item, i) || !ItemAdded(item, i)) {
if (fItems.AddItem(item)) { fItems.RemoveItem(i);
ItemAdded(item); return B_ERROR;
item->SetLayout(this);
err = ItemUnarchived(from, item, i);
} else
err = B_NO_MEMORY;
} }
err = ItemUnarchived(from, item, i);
if (err != B_OK) {
fItems.RemoveItem(i);
ItemRemoved(item, i);
return err;
}
item->SetLayout(this);
unarchiver.AssumeOwnership(item);
} }
InvalidateLayout();
return err; return err;
} }
status_t status_t
BLayout::ItemArchived(BMessage* into, BLayoutItem* of, int32 index) const BLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
{ {
return B_OK; return B_OK;
} }
@@ -271,14 +290,15 @@ BLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, int32 index)
} }
void bool
BLayout::ItemAdded(BLayoutItem* item) BLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{ {
return true;
} }
void void
BLayout::ItemRemoved(BLayoutItem* item) BLayout::ItemRemoved(BLayoutItem* item, int32 fromIndex)
{ {
} }
+26 -19
View File
@@ -18,6 +18,9 @@
#include "SimpleLayouter.h" #include "SimpleLayouter.h"
using std::nothrow;
// archivng constants // archivng constants
namespace { namespace {
const char* const kItemCollapsibleField = "BSplitLayout:item:collapsible"; const char* const kItemCollapsibleField = "BSplitLayout:item:collapsible";
@@ -741,10 +744,7 @@ BSplitLayout::Instantiate(BMessage* from)
status_t status_t
BSplitLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const BSplitLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const
{ {
ItemLayoutInfo* info = (ItemLayoutInfo*)item->LayoutData(); ItemLayoutInfo* info = _ItemLayoutInfo(item);
if (!info) // TODO: remove this check when AddItem() returns a bool
return B_ERROR;
status_t err = into->AddFloat(kItemWeightField, info->weight); status_t err = into->AddFloat(kItemWeightField, info->weight);
if (err == B_OK) if (err == B_OK)
@@ -769,30 +769,43 @@ BSplitLayout::ItemUnarchived(const BMessage* from,
} }
void bool
BSplitLayout::ItemAdded(BLayoutItem* item) BSplitLayout::ItemAdded(BLayoutItem* item, int32 atIndex)
{ {
ItemLayoutInfo* itemInfo = new(nothrow) ItemLayoutInfo();
if (!itemInfo)
return false;
if (CountItems() > 1) { if (CountItems() > 1) {
SplitterItem* splitterItem = new SplitterItem(this); SplitterItem* splitter = new(nothrow) SplitterItem(this);
SetItemWeight(splitterItem, 0); ItemLayoutInfo* splitterInfo = new(nothrow) ItemLayoutInfo();
fSplitterItems.AddItem(splitterItem); if (!splitter || !splitterInfo || !fSplitterItems.AddItem(splitter)) {
delete itemInfo;
delete splitter;
delete splitterInfo;
return false;
}
splitter->SetLayoutData(splitterInfo);
SetItemWeight(splitter, 0);
} }
item->SetLayoutData(itemInfo);
SetItemWeight(item, 1); SetItemWeight(item, 1);
return true;
} }
void void
BSplitLayout::ItemRemoved(BLayoutItem* item) BSplitLayout::ItemRemoved(BLayoutItem* item, int32 atIndex)
{ {
if (fSplitterItems.CountItems() > 0) { if (fSplitterItems.CountItems() > 0) {
SplitterItem* splitterItem = (SplitterItem*)fSplitterItems.RemoveItem( SplitterItem* splitterItem = (SplitterItem*)fSplitterItems.RemoveItem(
fSplitterItems.CountItems() - 1); fSplitterItems.CountItems() - 1);
delete (ItemLayoutInfo*)splitterItem->LayoutData(); delete _ItemLayoutInfo(splitterItem);
delete splitterItem; delete splitterItem;
} }
delete (ItemLayoutInfo*)item->LayoutData(); delete _ItemLayoutInfo(item);
item->SetLayoutData(NULL); item->SetLayoutData(NULL);
} }
@@ -1184,13 +1197,7 @@ BSplitLayout::_SetSplitterValue(int32 index, int32 value)
BSplitLayout::ItemLayoutInfo* BSplitLayout::ItemLayoutInfo*
BSplitLayout::_ItemLayoutInfo(BLayoutItem* item) const BSplitLayout::_ItemLayoutInfo(BLayoutItem* item) const
{ {
ItemLayoutInfo* info = (ItemLayoutInfo*)item->LayoutData(); return (ItemLayoutInfo*)item->LayoutData();
if (!info) {
info = new ItemLayoutInfo();
item->SetLayoutData(info);
}
return info;
} }
+2 -2
View File
@@ -98,8 +98,8 @@ public:
BLayoutItem* item, int32 index); BLayoutItem* item, int32 index);
protected: protected:
virtual void ItemAdded(BLayoutItem* item); virtual bool ItemAdded(BLayoutItem* item, int32 atIndex);
virtual void ItemRemoved(BLayoutItem* item); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex);
private: private:
class ItemLayoutInfo; class ItemLayoutInfo;