From 0a5e130725e2e8997bc0d9db9717f0a7874da8f3 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Thu, 2 Feb 2012 14:47:41 +1300 Subject: [PATCH] Make SharedSolver BArchivable to save extra user constraints. --- headers/libs/alm/Area.h | 5 + headers/libs/alm/Column.h | 14 ++- headers/libs/alm/Row.h | 14 ++- src/libs/alm/ALMLayout.cpp | 30 ++--- src/libs/alm/RowColumnManager.h | 8 +- src/libs/alm/SharedSolver.cpp | 217 ++++++++++++++++++++++++++++++-- src/libs/alm/SharedSolver.h | 26 +++- 7 files changed, 273 insertions(+), 41 deletions(-) diff --git a/headers/libs/alm/Area.h b/headers/libs/alm/Area.h index ef40616ded..6f471c6431 100644 --- a/headers/libs/alm/Area.h +++ b/headers/libs/alm/Area.h @@ -21,6 +21,10 @@ namespace LinearProgramming { class Constraint; }; +namespace BPrivate { + class SharedSolver; +}; + namespace BALM { @@ -113,6 +117,7 @@ private: private: friend class BALMLayout; friend class RowColumnManager; + friend class BPrivate::SharedSolver; BLayoutItem* fLayoutItem; int32 fID; diff --git a/headers/libs/alm/Column.h b/headers/libs/alm/Column.h index 50cc05b74e..c9ef423268 100644 --- a/headers/libs/alm/Column.h +++ b/headers/libs/alm/Column.h @@ -16,6 +16,11 @@ namespace LinearProgramming { }; +namespace BPrivate { + class SharedSolver; +}; + + namespace BALM { @@ -37,6 +42,10 @@ public: XTab* Right() const; private: + friend class BALMLayout; + friend class BALM::RowColumnManager; + friend class BPrivate::SharedSolver; + Column(LinearProgramming::LinearSpec* ls, XTab* left, XTab* right); @@ -48,11 +57,6 @@ private: // managed by RowColumnManager BObjectList fAreas; - -public: - friend class BALMLayout; - friend class BALM::RowColumnManager; - }; } // namespace BALM diff --git a/headers/libs/alm/Row.h b/headers/libs/alm/Row.h index b5af7c7cad..af49ea453d 100644 --- a/headers/libs/alm/Row.h +++ b/headers/libs/alm/Row.h @@ -16,6 +16,11 @@ namespace LinearProgramming { }; +namespace BPrivate { + class SharedSolver; +}; + + namespace BALM { @@ -37,6 +42,10 @@ public: YTab* Bottom() const; private: + friend class BALMLayout; + friend class BALM::RowColumnManager; + friend class BPrivate::SharedSolver; + Row(LinearProgramming::LinearSpec* ls, YTab* top, YTab* bottom); @@ -48,11 +57,6 @@ private: // managed by RowColumnManager BObjectList fAreas; - -public: - friend class BALMLayout; - friend class BALM::RowColumnManager; - }; } // namespace BALM diff --git a/src/libs/alm/ALMLayout.cpp b/src/libs/alm/ALMLayout.cpp index 841c1836db..c9a684078e 100644 --- a/src/libs/alm/ALMLayout.cpp +++ b/src/libs/alm/ALMLayout.cpp @@ -28,7 +28,7 @@ const BSize kUnsetSize(B_SIZE_UNSET, B_SIZE_UNSET); namespace { -const char* kFriendField = "BALMLayout:friends"; +const char* kSolverField = "BALMLayout:solver"; const char* kBadLayoutPolicyField = "BALMLayout:policy"; const char* kXTabsField = "BALMLayout:xtabs"; const char* kYTabsField = "BALMLayout:ytabs"; @@ -269,6 +269,9 @@ BALMLayout::BALMLayout(BMessage* archive) if (err == B_OK && archive->GetInfo(kBadLayoutPolicyField, NULL) == B_OK) err = unarchiver.EnsureUnarchived(kBadLayoutPolicyField); + if (err == B_OK) + err = unarchiver.EnsureUnarchived(kSolverField); + unarchiver.Finish(err); } @@ -1061,6 +1064,9 @@ BALMLayout::Archive(BMessage* into, bool deep) const err = archiver.AddArchivable(kBadLayoutPolicyField, fBadLayoutPolicy); } + if (err == B_OK) + err = archiver.AddArchivable(kSolverField, fSolver); + if (err == B_OK) err = archiver.AddArchivable(kMyTabsField, fLeft); if (err == B_OK) @@ -1140,26 +1146,14 @@ 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); - } - } + SharedSolver* solver; + status_t err = unarchiver.FindObject(kSolverField, solver); if (err != B_OK) return err; + _SetSolver(solver); + if (archive->GetInfo(kBadLayoutPolicyField, NULL) == B_OK) { BadLayoutPolicy* policy; err = unarchiver.FindObject(kBadLayoutPolicyField, policy); @@ -1235,8 +1229,6 @@ BALMLayout::AllArchived(BMessage* archive) const { status_t err = BAbstractLayout::AllArchived(archive); - if (err == B_OK) - err = fSolver->AddFriendReferences(this, archive, kFriendField); return err; } diff --git a/src/libs/alm/RowColumnManager.h b/src/libs/alm/RowColumnManager.h index 55a844397a..39bc57dbfb 100644 --- a/src/libs/alm/RowColumnManager.h +++ b/src/libs/alm/RowColumnManager.h @@ -14,6 +14,11 @@ #include "Tab.h" +namespace BPrivate { + class SharedSolver; +}; + + namespace BALM { @@ -41,6 +46,7 @@ public: void UpdateConstraints(); void TabsChanged(Area* area); private: + friend class BPrivate::SharedSolver; Row* _FindRowFor(Area* area); Column* _FindColumnFor(Area* area); @@ -52,7 +58,7 @@ private: void _UpdateConstraints(Row* row); void _UpdateConstraints(Column* column); - BObjectList fRows; + BObjectList fRows; BObjectList fColumns; LinearSpec* fLinearSpec; diff --git a/src/libs/alm/SharedSolver.cpp b/src/libs/alm/SharedSolver.cpp index df46da6ac4..57529c5165 100644 --- a/src/libs/alm/SharedSolver.cpp +++ b/src/libs/alm/SharedSolver.cpp @@ -6,13 +6,26 @@ #include "SharedSolver.h" +#include + #include +#include #include +#include "RowColumnManager.h" + using LinearProgramming::LinearSpec; +namespace { + +type_code kConstraintsTypeCode = 'cnst'; +const char* kConstraintsField = "SharedSolver:constraints"; + +}; + + struct SharedSolver::MinSizeValidator { inline void CallSolverMethod(LinearSpec* spec, VariableList* vars) { @@ -80,6 +93,19 @@ SharedSolver::SharedSolver() } +SharedSolver::SharedSolver(BMessage* archive) + : + BArchivable(archive), + fConstraintsValid(false), + fMinValid(false), + fMaxValid(false), + fPreferredValid(false), + fLayoutValid(false), + fLayoutContext(NULL) +{ +} + + SharedSolver::~SharedSolver() { if (fLayouts.CountItems() > 0) @@ -178,18 +204,184 @@ SharedSolver::ValidateLayout(BLayoutContext* context) status_t -SharedSolver::AddFriendReferences(const BALMLayout* layout, BMessage* archive, - const char* field) +SharedSolver::Archive(BMessage* archive, bool deep) const { - status_t err = B_OK; + return BArchivable::Archive(archive, deep); +} + + +status_t +SharedSolver::AllArchived(BMessage* archive) const +{ + /* + for each archived layout: + add it to our archive + add constraints created by areas and column manager to a set + for each constraint in the linear spec: + if it is not in the set above: + archive it + */ BArchiver archiver(archive); - for (int32 i = fLayouts.CountItems() - 1; i >= 0 && err == B_OK; i--) { - BALMLayout* current = fLayouts.ItemAt(i); - if (current == layout) + std::set autoConstraints; + for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) { + BALMLayout* layout = fLayouts.ItemAt(i); + if (!archiver.IsArchived(layout)) continue; - if (archiver.IsArchived(current)) - err = archiver.AddArchivable(field, current); + + for (int32 j = layout->CountItems() - 1; j >= 0; j--) + _AddConstraintsToSet(layout->AreaAt(j), autoConstraints); + + for (int32 j = layout->fRowColumnManager->fRows.CountItems() - 1; + j >= 0; j--) { + Row* row = layout->fRowColumnManager->fRows.ItemAt(i); + autoConstraints.insert(row->fPrefSizeConstraint); + } + + for (int32 j = layout->fRowColumnManager->fColumns.CountItems() - 1; + j >= 0; j--) { + Column* column = layout->fRowColumnManager->fColumns.ItemAt(i); + autoConstraints.insert(column->fPrefSizeConstraint); + } } + + status_t err = B_OK; + const ConstraintList& constraints = fLinearSpec.Constraints(); + for (int32 i = constraints.CountItems() - 1; i >= 0 && err == B_OK; i--) { + Constraint* constraint = constraints.ItemAt(i); + if (autoConstraints.find(constraint) != autoConstraints.end()) + err = _AddConstraintToArchive(constraint, archive); + } + return err; +} + + +status_t +SharedSolver::AllUnarchived(const BMessage* archive) +{ + int32 count = 0; + archive->GetInfo(kConstraintsField, NULL, &count); + + status_t err = B_OK; + BUnarchiver unarchiver(archive); + for (int32 i = 0; i < count && err == B_OK; i++) { + const void* constraintData; + ssize_t numBytes; + err = archive->FindData(kConstraintsField, kConstraintsTypeCode, + i, &constraintData, &numBytes); + if (err != B_OK) + return err; + + err = _InstantiateConstraint(constraintData, numBytes, unarchiver); + } + return err; +} + + +void +SharedSolver::_AddConstraintsToSet(Area* area, + std::set& constraints) +{ + if (area->fMinContentWidth) + constraints.insert(area->fMinContentWidth); + if (area->fMaxContentWidth) + constraints.insert(area->fMaxContentWidth); + if (area->fMinContentHeight) + constraints.insert(area->fMinContentHeight); + if (area->fMaxContentHeight) + constraints.insert(area->fMaxContentHeight); + if (area->fContentAspectRatioC) + constraints.insert(area->fContentAspectRatioC); +} + + +status_t +SharedSolver::_AddConstraintToArchive(Constraint* constraint, BMessage* archive) +{ + // TODO: check Read/Write calls + BArchiver archiver(archive); + BMallocIO buffer; + SummandList* leftSide = constraint->LeftSide(); + int32 summandCount = leftSide->CountItems(); + buffer.Write(&summandCount, sizeof(summandCount)); + + for (int32 i = 0; i < summandCount; i++) { + Summand* summand = leftSide->ItemAt(i); + Variable* var = summand->Var(); + BArchivable* varArchivable = dynamic_cast(var); + if (!varArchivable || !archiver.IsArchived(varArchivable)) + return B_NAME_NOT_FOUND; + + int32 token; + archiver.GetTokenForArchivable(varArchivable, token); + buffer.Write(&token, sizeof(token)); + + double coefficient = summand->Coeff(); + buffer.Write(&coefficient, sizeof(coefficient)); + } + + int32 op = constraint->Op(); + buffer.Write(&op, sizeof(op)); + + double rightSide = constraint->RightSide(); + buffer.Write(&rightSide, sizeof(rightSide)); + double penaltyNeg = constraint->PenaltyNeg(); + buffer.Write(&penaltyNeg, sizeof(penaltyNeg)); + double penaltyPos = constraint->PenaltyPos(); + buffer.Write(&penaltyPos, sizeof(penaltyPos)); + + return archive->AddData(kConstraintsField, kConstraintsTypeCode, + buffer.Buffer(), buffer.BufferLength(), false); +} + + +status_t +SharedSolver::_InstantiateConstraint(const void* rawData, ssize_t numBytes, + BUnarchiver& unarchiver) +{ + // TODO: check Read/Write calls + BMemoryIO buffer(rawData, numBytes); + int32 summandCount; + buffer.Read((void*)&summandCount, sizeof(summandCount)); + + SummandList* summandList = new SummandList(20, true); + ObjectDeleter deleter(summandList); + status_t err = B_OK; + for (int32 i = 0; i < summandCount; i++) { + int32 token; + buffer.Read((void*)&token, sizeof(token)); + + BArchivable* varArchivable; + err = unarchiver.GetObject(token, varArchivable); + if (err != B_OK) + break; + Variable* var = dynamic_cast(varArchivable); + if (!var) + return B_BAD_TYPE; + + fLinearSpec.AddVariable(var); + + double coefficient; + buffer.Read(&coefficient, sizeof(coefficient)); + + summandList->AddItem(new Summand(coefficient, var)); + } + + int32 op; + buffer.Read(&op, sizeof(op)); + + double rightSide; + buffer.Read(&rightSide, sizeof(rightSide)); + double penaltyNeg; + buffer.Read(&penaltyNeg, sizeof(penaltyNeg)); + double penaltyPos; + buffer.Read(&penaltyPos, sizeof(penaltyPos)); + + if (err == B_OK) { + fLinearSpec.AddConstraint(summandList, (OperatorType)op, rightSide, + penaltyNeg, penaltyPos); + deleter.Detach(); + } + return err; } @@ -275,3 +467,12 @@ SharedSolver::_Validate(bool& isValid, ResultType& result) isValid = true; fLayoutValid = false; } + + +BArchivable* +SharedSolver::Instantiate(BMessage* archive) +{ + if (validate_instantiation(archive, "BPrivate::SharedSolver")) + return new SharedSolver(archive); + return NULL; +} diff --git a/src/libs/alm/SharedSolver.h b/src/libs/alm/SharedSolver.h index ce9319b6d9..0e9c84d649 100644 --- a/src/libs/alm/SharedSolver.h +++ b/src/libs/alm/SharedSolver.h @@ -6,6 +6,9 @@ #define _SHARED_SOLVER_H +#include + +#include #include #include #include @@ -17,18 +20,20 @@ class BMessage; namespace BALM { class BALMLayout; + class Area; }; - using BALM::BALMLayout; - +using BALM::Area; namespace BPrivate { -class SharedSolver : BLayoutContextListener, public BReferenceable { +class SharedSolver : BLayoutContextListener, public BReferenceable, + public BArchivable { public: + SharedSolver(BMessage* archive); SharedSolver(); ~SharedSolver(); @@ -47,6 +52,13 @@ public: status_t AddFriendReferences(const BALMLayout* layout, BMessage* archive, const char* field); + + status_t Archive(BMessage* archive, bool deep) const; + status_t AllArchived(BMessage* archive) const; + status_t AllUnarchived(const BMessage* archive); + + static BArchivable* Instantiate(BMessage* archive); + private: struct MinSizeValidator; struct MaxSizeValidator; @@ -56,6 +68,14 @@ private: friend struct MaxSizeValidator; friend struct PreferredSizeValidator; + + static void _AddConstraintsToSet(Area* area, + std::set& constraints); + static status_t _AddConstraintToArchive(Constraint* constraint, + BMessage* archive); + status_t _InstantiateConstraint(const void* rawData, + ssize_t numBytes, BUnarchiver& unarchiver); + void SetMaxSize(BALM::BALMLayout* layout, const BSize& max); void SetMinSize(BALM::BALMLayout* layout,