From 35bf0b5c1c5f89dac389efde9bcf19e880fa04e4 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Wed, 1 Feb 2012 11:19:07 +1300 Subject: [PATCH] Add initial support for archiving a BALMLayout. What's supported: * basic archive/instantiate * friend layouts coming soon: * saving of custom restraints * archiving of BadLayoutPolicy --- headers/libs/alm/ALMLayout.h | 13 ++ headers/libs/alm/Tab.h | 8 +- src/libs/alm/ALMLayout.cpp | 289 +++++++++++++++++++++++++++++++++- src/libs/alm/SharedSolver.cpp | 21 ++- src/libs/alm/SharedSolver.h | 12 +- src/libs/alm/Tab.cpp | 44 ++++++ 6 files changed, 375 insertions(+), 12 deletions(-) diff --git a/headers/libs/alm/ALMLayout.h b/headers/libs/alm/ALMLayout.h index fd6b28cfc3..aa44620172 100644 --- a/headers/libs/alm/ALMLayout.h +++ b/headers/libs/alm/ALMLayout.h @@ -39,6 +39,7 @@ public: BALMLayout(float hSpacing = 0.0f, float vSpacing = 0.0f, BALMLayout* friendLayout = NULL); + BALMLayout(BMessage* archive); virtual ~BALMLayout(); BReference AddXTab(); @@ -118,12 +119,23 @@ public: virtual BSize BasePreferredSize(); virtual BAlignment BaseAlignment(); + virtual status_t Archive(BMessage* into, bool deep = true) const; + static BArchivable* Instantiate(BMessage* archive); + virtual status_t Perform(perform_code d, void* arg); protected: virtual bool ItemAdded(BLayoutItem* item, int32 atIndex); virtual void ItemRemoved(BLayoutItem* item, int32 fromIndex); + virtual status_t ItemArchived(BMessage* into, BLayoutItem* item, + int32 index) const; + virtual status_t ItemUnarchived(const BMessage* from, + BLayoutItem* item, int32 index); + + virtual status_t AllUnarchived(const BMessage* archive); + virtual status_t AllArchived(BMessage* archive) const; + virtual void LayoutInvalidated(bool children); virtual void DoLayout(); @@ -184,6 +196,7 @@ private: bool _AddedTab(YTab* tab); BLayoutItem* _LayoutItemToAdd(BView* view); + void _SetSolver(BPrivate::SharedSolver* solver); BPrivate::SharedSolver* fSolver; diff --git a/headers/libs/alm/Tab.h b/headers/libs/alm/Tab.h index 2437d89ef5..89df113a2e 100644 --- a/headers/libs/alm/Tab.h +++ b/headers/libs/alm/Tab.h @@ -6,6 +6,7 @@ #define X_TAB_H +#include #include #include "Variable.h" @@ -17,9 +18,10 @@ namespace BALM { class BALMLayout; -class TabBase { +class TabBase : public BArchivable { private: TabBase(); + TabBase(BMessage* archive); virtual ~TabBase(); friend class BALMLayout; @@ -43,11 +45,13 @@ class XTab : public Variable, public TabBase, public BReferenceable { public: virtual ~XTab(); + static BArchivable* Instantiate(BMessage* archive); protected: friend class BALMLayout; XTab(BALMLayout* layout); private: + XTab(BMessage* archive); uint32 _reserved[2]; }; @@ -56,10 +60,12 @@ class YTab : public Variable, public TabBase, public BReferenceable { public: virtual ~YTab(); + static BArchivable* Instantiate(BMessage* archive); protected: friend class BALMLayout; YTab(BALMLayout* layout); private: + YTab(BMessage* archive); uint32 _reserved[2]; }; diff --git a/src/libs/alm/ALMLayout.cpp b/src/libs/alm/ALMLayout.cpp index d4e5754500..94215dc577 100644 --- a/src/libs/alm/ALMLayout.cpp +++ b/src/libs/alm/ALMLayout.cpp @@ -26,9 +26,21 @@ using namespace LinearProgramming; const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); +namespace { + +const char* kFriendField = "BALMLayout:friends"; +const char* kXTabsField = "BALMLayout:xtabs"; +const char* kYTabsField = "BALMLayout:ytabs"; +const char* kTabsField = "BALMLayout:item:tabs"; +const char* kMyTabsField = "BALMLayout:tabs"; +const char* kInsetsField = "BALMLayout:insets"; +const char* kSpacingField = "BALMLayout:spacing"; + int CompareXTabFunc(const XTab* tab1, const XTab* tab2); int CompareYTabFunc(const YTab* tab1, const YTab* tab2); +}; + namespace BALM { @@ -144,10 +156,7 @@ BALMLayout::BALMLayout(float hSpacing, float vSpacing, BALMLayout* friendLayout) fYTabsSorted(false), fBadLayoutPolicy(new DefaultPolicy()) { - fSolver = friendLayout ? friendLayout->fSolver : new SharedSolver(); - fSolver->AcquireReference(); - fSolver->RegisterLayout(this); - fRowColumnManager = new RowColumnManager(Solver()); + _SetSolver(friendLayout ? friendLayout->fSolver : new SharedSolver()); fLeft = AddXTab(); fRight = AddXTab(); @@ -167,13 +176,68 @@ BALMLayout::BALMLayout(float hSpacing, float vSpacing, BALMLayout* friendLayout) } +BALMLayout::BALMLayout(BMessage* archive) + : + BAbstractLayout(BUnarchiver::PrepareArchive(archive)), + fSolver(NULL), + fLeft(NULL), + fRight(NULL), + fTop(NULL), + fBottom(NULL), + fMinSize(kUnsetSize), + fMaxSize(kUnsetSize), + fPreferredSize(kUnsetSize), + fXTabsSorted(false), + fYTabsSorted(false), + fBadLayoutPolicy(new DefaultPolicy()) +{ + BUnarchiver unarchiver(archive); + + BRect insets; + status_t err = archive->FindRect(kInsetsField, &insets); + if (err != B_OK) { + unarchiver.Finish(err); + return; + } + + fLeftInset = insets.left; + fRightInset = insets.right; + fTopInset = insets.top; + fBottomInset = insets.bottom; + + + BSize spacing; + err = archive->FindSize(kSpacingField, &spacing); + if (err != B_OK) { + unarchiver.Finish(err); + return; + } + + fHSpacing = spacing.width; + fVSpacing = spacing.height; + + int32 tabCount = 0; + archive->GetInfo(kXTabsField, NULL, &tabCount); + for (int32 i = 0; i < tabCount && err == B_OK; i++) + err = unarchiver.EnsureUnarchived(kXTabsField, i); + + archive->GetInfo(kYTabsField, NULL, &tabCount); + for (int32 i = 0; i < tabCount && err == B_OK; i++) + err = unarchiver.EnsureUnarchived(kYTabsField, i); + + unarchiver.Finish(err); +} + + BALMLayout::~BALMLayout() { delete fRowColumnManager; delete fBadLayoutPolicy; - fSolver->LayoutLeaving(this); - fSolver->ReleaseReference(); + if (fSolver) { + fSolver->LayoutLeaving(this); + fSolver->ReleaseReference(); + } } @@ -317,6 +381,9 @@ BALMLayout::IndexOf(YTab* tab, bool ordered) } +namespace { + + int CompareXTabFunc(const XTab* tab1, const XTab* tab2) { @@ -339,6 +406,7 @@ CompareYTabFunc(const YTab* tab1, const YTab* tab2) } +}; // end anonymous namespace /** @@ -921,6 +989,202 @@ BALMLayout::BaseAlignment() } +status_t +BALMLayout::Archive(BMessage* into, bool deep) const +{ + BArchiver archiver(into); + status_t err = BAbstractLayout::Archive(into, deep); + if (err != B_OK) + return archiver.Finish(err); + + BRect insets(fLeftInset, fTopInset, fRightInset, fBottomInset); + err = into->AddRect(kInsetsField, insets); + if (err != B_OK) + return archiver.Finish(err); + + BSize spacing(fHSpacing, fVSpacing); + err = into->AddSize(kSpacingField, spacing); + if (err != B_OK) + return archiver.Finish(err); + + if (deep) { + for (int32 i = CountXTabs() - 1; i >= 0 && err == B_OK; i--) + err = archiver.AddArchivable(kXTabsField, XTabAt(i)); + + for (int32 i = CountYTabs() - 1; i >= 0 && err == B_OK; i--) + err = archiver.AddArchivable(kYTabsField, YTabAt(i)); + } + + if (err == B_OK) + err = archiver.AddArchivable(kMyTabsField, fLeft); + if (err == B_OK) + err = archiver.AddArchivable(kMyTabsField, fTop); + if (err == B_OK) + err = archiver.AddArchivable(kMyTabsField, fRight); + if (err == B_OK) + err = archiver.AddArchivable(kMyTabsField, fBottom); + + return archiver.Finish(err); +} + + +BArchivable* +BALMLayout::Instantiate(BMessage* from) +{ + if (validate_instantiation(from, "BALM::BALMLayout")) + return new BALMLayout(from); + return NULL; +} + + +status_t +BALMLayout::ItemArchived(BMessage* into, BLayoutItem* item, int32 index) const +{ + BArchiver archiver(into); + status_t err = BAbstractLayout::ItemArchived(into, item, index); + if (err != B_OK) + return err; + + Area* area = AreaFor(item); + err = archiver.AddArchivable(kTabsField, area->Left()); + if (err == B_OK) + archiver.AddArchivable(kTabsField, area->Top()); + if (err == B_OK) + archiver.AddArchivable(kTabsField, area->Right()); + if (err == B_OK) + archiver.AddArchivable(kTabsField, area->Bottom()); + + return err; +} + + +status_t +BALMLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item, + int32 index) +{ + BUnarchiver unarchiver(from); + status_t err = BAbstractLayout::ItemUnarchived(from, item, index); + if (err != B_OK) + return err; + + Area* area = AreaFor(item); + + XTab* left; + XTab* right; + YTab* bottom; + YTab* top; + err = unarchiver.FindObject(kTabsField, index * 4, left); + if (err == B_OK) + err = unarchiver.FindObject(kTabsField, index * 4 + 1, top); + if (err == B_OK) + err = unarchiver.FindObject(kTabsField, index * 4 + 2, right); + if (err == B_OK) + err = unarchiver.FindObject(kTabsField, index * 4 + 3, bottom); + + if (err == B_OK) { + area->_Init(Solver(), left, top, right, bottom, fRowColumnManager); + fRowColumnManager->AddArea(area); + } + return err; +} + + +status_t +BALMLayout::AllUnarchived(const BMessage* archive) +{ + BUnarchiver unarchiver(archive); + + status_t err = B_OK; + if (fSolver == NULL) { + _SetSolver(new SharedSolver()); + + int32 friendCount = 0; + archive->GetInfo(kFriendField, NULL, &friendCount); + for (int32 i = 0; i < friendCount; i++) { + BALMLayout* layout; + err = unarchiver.FindObject(kFriendField, i, + BUnarchiver::B_DONT_ASSUME_OWNERSHIP, layout); + if (err != B_OK) + return err; + + layout->_SetSolver(fSolver); + } + } + + LinearSpec* spec = Solver(); + int32 tabCount = 0; + archive->GetInfo(kXTabsField, NULL, &tabCount); + for (int32 i = 0; i < tabCount && err == B_OK; i++) { + XTab* tab; + err = unarchiver.FindObject(kXTabsField, i, + BUnarchiver::B_DONT_ASSUME_OWNERSHIP, tab); + spec->AddVariable(tab); + TabAddTransaction adder(this); + if (adder.AttempAdd(tab)) + adder.Commit(); + else + err = B_NO_MEMORY; + } + + archive->GetInfo(kYTabsField, NULL, &tabCount); + for (int32 i = 0; i < tabCount; i++) { + YTab* tab; + unarchiver.FindObject(kYTabsField, i, + BUnarchiver::B_DONT_ASSUME_OWNERSHIP, tab); + spec->AddVariable(tab); + TabAddTransaction adder(this); + if (adder.AttempAdd(tab)) + adder.Commit(); + else + err = B_NO_MEMORY; + } + + + if (err == B_OK) { + XTab* leftTab = NULL; + err = unarchiver.FindObject(kMyTabsField, 0, leftTab); + fLeft = leftTab; + } + + if (err == B_OK) { + YTab* topTab = NULL; + err = unarchiver.FindObject(kMyTabsField, 1, topTab); + fTop = topTab; + } + + if (err == B_OK) { + XTab* rightTab = NULL; + err = unarchiver.FindObject(kMyTabsField, 2, rightTab); + fRight = rightTab; + } + + if (err == B_OK) { + YTab* bottomTab = NULL; + err = unarchiver.FindObject(kMyTabsField, 3, bottomTab); + fBottom = bottomTab; + } + + if (err == B_OK) { + fLeft->SetRange(0, 0); + fTop->SetRange(0, 0); + + err = BAbstractLayout::AllUnarchived(archive); + } + return err; +} + + +status_t +BALMLayout::AllArchived(BMessage* archive) const +{ + status_t err = BAbstractLayout::AllArchived(archive); + + if (err == B_OK) + err = fSolver->AddFriendReferences(this, archive, kFriendField); + return err; +} + + /** * Invalidates the layout. * Resets minimum/maximum/preferred size. @@ -934,7 +1198,8 @@ BALMLayout::LayoutInvalidated(bool children) fXTabsSorted = false; fYTabsSorted = false; - fSolver->Invalidate(children); + if (fSolver) + fSolver->Invalidate(children); } @@ -1108,6 +1373,16 @@ BALMLayout::_LayoutItemToAdd(BView* view) } +void +BALMLayout::_SetSolver(SharedSolver* solver) +{ + fSolver = solver; + fSolver->AcquireReference(); + fSolver->RegisterLayout(this); + fRowColumnManager = new RowColumnManager(Solver()); +} + + status_t BALMLayout::Perform(perform_code d, void* arg) { diff --git a/src/libs/alm/SharedSolver.cpp b/src/libs/alm/SharedSolver.cpp index a0ec46b4d6..df46da6ac4 100644 --- a/src/libs/alm/SharedSolver.cpp +++ b/src/libs/alm/SharedSolver.cpp @@ -124,9 +124,9 @@ SharedSolver::RegisterLayout(BALMLayout* layout) void -SharedSolver::LayoutLeaving(BALMLayout* layout) +SharedSolver::LayoutLeaving(const BALMLayout* layout) { - fLayouts.RemoveItem(layout); + fLayouts.RemoveItem(const_cast(layout)); Invalidate(false); } @@ -177,6 +177,23 @@ SharedSolver::ValidateLayout(BLayoutContext* context) } +status_t +SharedSolver::AddFriendReferences(const BALMLayout* layout, BMessage* archive, + const char* field) +{ + status_t err = B_OK; + BArchiver archiver(archive); + for (int32 i = fLayouts.CountItems() - 1; i >= 0 && err == B_OK; i--) { + BALMLayout* current = fLayouts.ItemAt(i); + if (current == layout) + continue; + if (archiver.IsArchived(current)) + err = archiver.AddArchivable(field, current); + } + return err; +} + + void SharedSolver::SetMaxSize(BALMLayout* layout, const BSize& max) { diff --git a/src/libs/alm/SharedSolver.h b/src/libs/alm/SharedSolver.h index b9110ee0ff..ce9319b6d9 100644 --- a/src/libs/alm/SharedSolver.h +++ b/src/libs/alm/SharedSolver.h @@ -13,11 +13,16 @@ #include "LinearSpec.h" +class BMessage; + namespace BALM { class BALMLayout; }; +using BALM::BALMLayout; + + namespace BPrivate { @@ -32,13 +37,16 @@ public: LinearSpec* Solver() const; ResultType Result(); - void RegisterLayout(BALM::BALMLayout* layout); - void LayoutLeaving(BALM::BALMLayout* layout); + void RegisterLayout(BALMLayout* layout); + void LayoutLeaving(const BALMLayout* layout); ResultType ValidateMinSize(); ResultType ValidateMaxSize(); ResultType ValidatePreferredSize(); ResultType ValidateLayout(BLayoutContext* context); + + status_t AddFriendReferences(const BALMLayout* layout, + BMessage* archive, const char* field); private: struct MinSizeValidator; struct MaxSizeValidator; diff --git a/src/libs/alm/Tab.cpp b/src/libs/alm/Tab.cpp index 286744cc7e..13646c4119 100644 --- a/src/libs/alm/Tab.cpp +++ b/src/libs/alm/Tab.cpp @@ -58,6 +58,14 @@ TabBase::TabBase() } +TabBase::TabBase(BMessage* archive) + : + BArchivable(BUnarchiver::PrepareArchive(archive)) +{ + BUnarchiver(archive).Finish(B_OK); +} + + TabBase::~TabBase() { } @@ -103,6 +111,15 @@ XTab::XTab(BALMLayout* layout) } +XTab::XTab(BMessage* archive) + : + Variable(NULL), + TabBase(BUnarchiver::PrepareArchive(archive)) +{ + BUnarchiver(archive).Finish(B_OK); +} + + XTab::~XTab() { TabBase::BALMLayoutList* layouts = fLayouts; @@ -114,6 +131,15 @@ XTab::~XTab() } +BArchivable* +XTab::Instantiate(BMessage* archive) +{ + if (validate_instantiation(archive, "BALM::XTab")) + return new XTab(archive); + return NULL; +} + + YTab::YTab(BALMLayout* layout) : Variable(layout->Solver()) @@ -122,6 +148,15 @@ YTab::YTab(BALMLayout* layout) } +YTab::YTab(BMessage* archive) + : + Variable(NULL), + TabBase(BUnarchiver::PrepareArchive(archive)) +{ + BUnarchiver(archive).Finish(B_OK); +} + + YTab::~YTab() { TabBase::BALMLayoutList* layouts = fLayouts; @@ -131,3 +166,12 @@ YTab::~YTab() } delete fLayouts; } + + +BArchivable* +YTab::Instantiate(BMessage* archive) +{ + if (validate_instantiation(archive, "BALM::YTab")) + return new YTab(archive); + return NULL; +}