diff --git a/headers/libs/alm/ALMLayout.h b/headers/libs/alm/ALMLayout.h index 104eb68d16..71577811de 100644 --- a/headers/libs/alm/ALMLayout.h +++ b/headers/libs/alm/ALMLayout.h @@ -151,6 +151,17 @@ private: BALMLayout(const BALMLayout&); void operator =(const BALMLayout&); + struct XTabRemover; + struct XTabRemoverFunc; + + struct YTabRemover; + struct YTabRemoverFunc; + + friend struct XTabRemover; + friend struct XTabRemoverFunc; + + friend struct YTabRemover; + friend struct YTabRemoverFunc; friend class XTab; friend class YTab; @@ -159,6 +170,9 @@ private: float InsetForTab(XTab* tab) const; float InsetForTab(YTab* tab) const; + void _RemoveSelfFromTab(XTab* tab); + void _RemoveSelfFromTab(YTab* tab); + BLayoutItem* _LayoutItemToAdd(BView* view); void _UpdateAreaConstraints(); diff --git a/headers/libs/alm/Tab.h b/headers/libs/alm/Tab.h index ab21ec7a1f..e8015e7cc4 100644 --- a/headers/libs/alm/Tab.h +++ b/headers/libs/alm/Tab.h @@ -29,7 +29,14 @@ protected: XTab(BALMLayout* layout); private: - BALMLayout* fALMLayout; + struct BALMLayoutList; + + bool IsInLayout(BALMLayout* layout); + bool AddedToLayout(BALMLayout* layout); + void LayoutLeaving(BALMLayout* layout); + bool IsSuitableFor(BALMLayout* layout); + + BALMLayoutList* fLayouts; uint32 _reserved[2]; }; @@ -44,7 +51,12 @@ protected: YTab(BALMLayout* layout); private: - BALMLayout* fALMLayout; + bool IsInLayout(BALMLayout* layout); + bool AddedToLayout(BALMLayout* layout); + void LayoutLeaving(BALMLayout* layout); + bool IsSuitableFor(BALMLayout* layout); + + XTab::BALMLayoutList* fLayouts; uint32 _reserved[2]; }; diff --git a/src/libs/alm/ALMLayout.cpp b/src/libs/alm/ALMLayout.cpp index 9abebd549f..25811ef86d 100644 --- a/src/libs/alm/ALMLayout.cpp +++ b/src/libs/alm/ALMLayout.cpp @@ -11,18 +11,70 @@ #include +#include #include #include "RowColumnManager.h" #include "ViewLayoutItem.h" +using BPrivate::AutoDeleter; using namespace LinearProgramming; const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); +struct BALMLayout::XTabRemoverFunc { + void operator()(XTab* tab) + { + if (tab) + layout->_RemoveSelfFromTab(tab); + } + + BALMLayout* layout; +}; + + +struct BALMLayout::XTabRemover + : public AutoDeleter { + + typedef AutoDeleter Base; + + XTabRemover(BALMLayout* layout, XTab* tab = NULL) + : + Base(tab) + { + fDelete.layout = layout; + } +}; + + +struct BALMLayout::YTabRemoverFunc { + void operator()(YTab* tab) + { + if (tab) + layout->_RemoveSelfFromTab(tab); + } + + BALMLayout* layout; +}; + + +struct BALMLayout::YTabRemover + : public AutoDeleter { + + typedef AutoDeleter Base; + + YTabRemover(BALMLayout* layout, YTab* tab = NULL) + : + Base(tab) + { + fDelete.layout = layout; + } +}; + + BALM::BALMLayout::BadLayoutPolicy::~BadLayoutPolicy() { } @@ -105,6 +157,10 @@ BALMLayout::AddXTab() return NULL; fXTabList.AddItem(tab); + if (!tab->AddedToLayout(this)) { + fXTabList.RemoveItem(tab); + return NULL; + } return tab; } @@ -140,6 +196,10 @@ BALMLayout::AddYTab() return NULL; fYTabList.AddItem(tab); + if (!tab->AddedToLayout(this)) { + fYTabList.RemoveItem(tab); + return NULL; + } return tab; } @@ -480,6 +540,11 @@ Area* BALMLayout::AddItem(BLayoutItem* item, XTab* left, YTab* top, XTab* _right, YTab* _bottom) { + if (!left->IsSuitableFor(this) || !top->IsSuitableFor(this) + || (_right && !_right->IsSuitableFor(this)) + || (_bottom && !_bottom->IsSuitableFor(this))) + debugger("Tab added to unfriendly layout!"); + BReference right = _right; if (right.Get() == NULL) right = AddXTab(); @@ -487,16 +552,51 @@ BALMLayout::AddItem(BLayoutItem* item, XTab* left, YTab* top, XTab* _right, if (bottom.Get() == NULL) bottom = AddYTab(); - // Area is added int ItemAdded + // TODO: make sure all tabs get into the lists + XTabRemover leftRemover(this); + if (!left->IsInLayout(this)) { + if (!left->AddedToLayout(this)) + return NULL; + leftRemover.SetTo(left); + } + + YTabRemover topRemover(this); + if (!top->IsInLayout(this)) { + if (!top->AddedToLayout(this)) + return NULL; + topRemover.SetTo(top); + } + + XTabRemover rightRemover(this); + if (_right != NULL && !right->IsInLayout(this)) { + if (!right->AddedToLayout(this)) + return NULL; + rightRemover.SetTo(right); + } + + YTabRemover bottomRemover(this); + if (_bottom != NULL && !bottom->IsInLayout(this)) { + if (!bottom->AddedToLayout(this)) + return NULL; + bottomRemover.SetTo(bottom); + } + + // Area is added in ItemAdded if (!BAbstractLayout::AddItem(-1, item)) return NULL; Area* area = AreaFor(item); - if (!area) + if (!area) { + RemoveItem(item); return NULL; + } area->_Init(fSolver, left, top, right, bottom, fRowColumnManager); - fRowColumnManager->AddArea(area); + + leftRemover.Detach(); + rightRemover.Detach(); + topRemover.Detach(); + bottomRemover.Detach(); return area; } @@ -907,6 +1007,20 @@ BALMLayout::InsetForTab(YTab* tab) const } +void +BALMLayout::_RemoveSelfFromTab(XTab* tab) +{ + tab->LayoutLeaving(this); +} + + +void +BALMLayout::_RemoveSelfFromTab(YTab* tab) +{ + tab->LayoutLeaving(this); +} + + BLayoutItem* BALMLayout::_LayoutItemToAdd(BView* view) { diff --git a/src/libs/alm/Tab.cpp b/src/libs/alm/Tab.cpp index b0969eaab1..39605d0879 100644 --- a/src/libs/alm/Tab.cpp +++ b/src/libs/alm/Tab.cpp @@ -10,29 +10,144 @@ #include +using std::nothrow; + + +struct XTab::BALMLayoutList { + BALMLayoutList(BALMLayout* _layout, BALMLayoutList* _next = NULL) + : + next(_next), + layout(_layout) + { + } + + ~BALMLayoutList() + { + delete next; + } + + bool HasLayout(BALMLayout* search) + { + if (layout == search) + return true; + return next ? next->HasLayout(search) : false; + } + + BALMLayoutList* Remove(BALMLayout* remove) + { + if (layout == remove) { + BALMLayoutList* _next = next; + delete this; + return _next; + } + if (next) + next = next->Remove(remove); + return this; + } + + BALMLayoutList* next; + BALMLayout* layout; +}; + + XTab::XTab(BALMLayout* layout) : Variable(layout->Solver()), - fALMLayout(layout) + fLayouts(new BALMLayoutList(layout)) { } XTab::~XTab() { - fALMLayout->fXTabList.RemoveItem(this); + BALMLayoutList* layouts = fLayouts; + while (layouts) { + layouts->layout->fXTabList.RemoveItem(this); + layouts = layouts->next; + } + delete fLayouts; +} + + +bool +XTab::IsInLayout(BALMLayout* layout) +{ + return fLayouts->HasLayout(layout); +} + + +bool +XTab::AddedToLayout(BALMLayout* layout) +{ + BALMLayoutList* newHead = new (nothrow) BALMLayoutList(layout, fLayouts); + if (newHead == NULL) + return false; + fLayouts = newHead; + return true; +} + + +void +XTab::LayoutLeaving(BALMLayout* layout) +{ + fLayouts = fLayouts->Remove(layout); +} + + +bool +XTab::IsSuitableFor(BALMLayout* layout) +{ + return (fLayouts->layout->Solver() == layout->Solver()); } YTab::YTab(BALMLayout* layout) : Variable(layout->Solver()), - fALMLayout(layout) + fLayouts(new XTab::BALMLayoutList(layout)) { } YTab::~YTab() { - fALMLayout->fYTabList.RemoveItem(this); + XTab::BALMLayoutList* layouts = fLayouts; + while (layouts) { + layouts->layout->fYTabList.RemoveItem(this); + layouts = layouts->next; + } + delete fLayouts; +} + + +bool +YTab::IsInLayout(BALMLayout* layout) +{ + return fLayouts->HasLayout(layout); +} + + +bool +YTab::AddedToLayout(BALMLayout* layout) +{ + XTab::BALMLayoutList* newHead + = new (nothrow) XTab::BALMLayoutList(layout, fLayouts); + if (newHead == NULL) + return false; + fLayouts = newHead; + return true; +} + + +void +YTab::LayoutLeaving(BALMLayout* layout) +{ + fLayouts = fLayouts->Remove(layout); +} + + +bool +YTab::IsSuitableFor(BALMLayout* layout) +{ + return (fLayouts->layout->Solver() == layout->Solver()); }