implement generic object attach-to-model and purge
This commit is contained in:
parent
c43040985c
commit
b21db07aff
10 changed files with 218 additions and 30 deletions
|
|
@ -64,6 +64,7 @@
|
|||
#include "lib/lumitime.hpp"
|
||||
#include "proc/mobject/placement.hpp"
|
||||
#include "proc/mobject/placement-ref.hpp"
|
||||
#include "proc/mobject/session/session-service-mutate.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -134,6 +135,38 @@ namespace mobject {
|
|||
}
|
||||
|
||||
|
||||
/** attach a child element to the model
|
||||
* @param newPlacement to be copied into the model, placed
|
||||
* into the scope of the object denoted by this MORef
|
||||
* @return MORef designing the newly created and attached object instance
|
||||
*/
|
||||
template<class MOX>
|
||||
MORef<MOX>
|
||||
attach (Placement<MOX> const& newPlacement)
|
||||
{
|
||||
if (!isValid())
|
||||
throw lumiera::error::State("Attempt to attach a child to an inactive MObject ref"
|
||||
, LUMIERA_ERROR_BOTTOM_MOBJECTREF);
|
||||
MORef<MOX> newInstance;
|
||||
PlacementMO::ID thisScope = pRef_;
|
||||
return newInstance.activate (
|
||||
session::SessionServiceMutate::attach_toModel (newPlacement, thisScope));
|
||||
}
|
||||
|
||||
|
||||
/** detach this object instance from model,
|
||||
* including all child elements
|
||||
*/
|
||||
void
|
||||
purge ()
|
||||
{
|
||||
if (isValid())
|
||||
session::SessionServiceMutate::detach_and_clear (pRef_);
|
||||
|
||||
ENSURE (!isValid());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* === Lifecycle === */
|
||||
|
||||
|
|
|
|||
|
|
@ -121,18 +121,18 @@ namespace mobject {
|
|||
|
||||
static session::SessManager& current;
|
||||
|
||||
DefaultsAccess defaults; ///< manages default configured objects
|
||||
TimelineAccess timelines; ///< collection of timelines (top level)
|
||||
SequenceAccess sequences; ///< collection of sequences
|
||||
DefaultsAccess defaults; ///< manages default configured objects
|
||||
TimelineAccess timelines; ///< collection of timelines (top level)
|
||||
SequenceAccess sequences; ///< collection of sequences
|
||||
|
||||
virtual bool isValid () = 0;
|
||||
virtual void attach (PMO& placement) = 0;
|
||||
virtual bool detach (PMO& placement) = 0;
|
||||
virtual bool isValid () = 0;
|
||||
virtual MObjectRef attach (PMO& placement) = 0;
|
||||
virtual bool detach (PMO& placement) = 0;
|
||||
|
||||
virtual MObjectRef getRoot() = 0;
|
||||
virtual MObjectRef getRoot() = 0;
|
||||
|
||||
virtual session::PFix& getFixture () = 0;
|
||||
virtual void rebuildFixture () = 0;
|
||||
virtual session::PFix& getFixture () = 0;
|
||||
virtual void rebuildFixture () = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -296,6 +296,16 @@ namespace session {
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
removeAll (ID scopeID)
|
||||
{
|
||||
remove_all_from_scope (scopeID); // recursive
|
||||
remove_base_entry (scopeID); // discard storage
|
||||
|
||||
ENSURE (!util::contains(scopeTab_, scopeID));
|
||||
ENSURE (!contains (scopeID));
|
||||
}
|
||||
|
||||
|
||||
/* == access for self-test == */
|
||||
|
||||
|
|
@ -349,6 +359,21 @@ namespace session {
|
|||
NOTREACHED();
|
||||
}
|
||||
|
||||
void
|
||||
remove_all_from_scope (ID scopeID)
|
||||
{
|
||||
typedef ScopeTable::const_iterator Pos;
|
||||
pair<Pos,Pos> searchRange = scopeTab_.equal_range(scopeID);
|
||||
|
||||
Pos pos = searchRange.first;
|
||||
Pos end = searchRange.second;
|
||||
for ( ; pos!=end; ++pos)
|
||||
removeAll (pos->second); // depth-first recursion
|
||||
|
||||
scopeTab_.erase (pos,end); // assumed to be NOP for pos==end
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Helper for building a scope exploring iterator
|
||||
* for PlacementIndex: our "reverse index" (#scopeTab_)
|
||||
|
|
@ -499,6 +524,23 @@ namespace session {
|
|||
}
|
||||
|
||||
|
||||
/** recursively kill a complete scope,
|
||||
* including the given element and all children.
|
||||
* @note as an exception, when specifying model root,
|
||||
* any sub-elements are cleared but root is retained
|
||||
*/
|
||||
void
|
||||
PlacementIndex::clear (ID targetScope)
|
||||
{
|
||||
if (targetScope == getRoot().getID())
|
||||
pTab_->clear();
|
||||
else
|
||||
pTab_->removeAll (targetScope);
|
||||
|
||||
ENSURE (isValid());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlacementIndex::clear()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ namespace session {
|
|||
PlacementIndex(PlacementMO const&);
|
||||
~PlacementIndex() ;
|
||||
|
||||
void clear();
|
||||
void clear (ID targetScope);
|
||||
void clear ();
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -304,6 +305,7 @@ namespace session {
|
|||
* immediately followed by creating a typed-ID,
|
||||
* allowing to retain the original typed context
|
||||
* @todo this solution is half-baked ///////////////////////////////////TICKET #523
|
||||
* @todo is this API used in application code? or just used in tests?
|
||||
*/
|
||||
template<class PLA>
|
||||
typename BuildID<PLA>::Type
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ namespace session {
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
MObjectRef
|
||||
SessionImpl::attach (PMO& placement)
|
||||
{
|
||||
UNIMPLEMENTED ("add Placement to the current Session");
|
||||
|
|
|
|||
|
|
@ -84,8 +84,8 @@ namespace session {
|
|||
|
||||
/* ==== Session API ==== */
|
||||
virtual bool isValid ();
|
||||
virtual void attach (PMO& placement);
|
||||
virtual bool detach (PMO& placement);
|
||||
virtual MObjectRef attach (PMO& placement);
|
||||
virtual bool detach (PMO& placement);
|
||||
|
||||
virtual MObjectRef getRoot();
|
||||
|
||||
|
|
@ -131,6 +131,45 @@ namespace session {
|
|||
|
||||
|
||||
|
||||
template<class IMPL>
|
||||
struct ServiceAccessPoint<SessionServiceMutate, IMPL>
|
||||
: IMPL
|
||||
{
|
||||
PMO::ID const&
|
||||
insertCopy (PMO const& newPlacement, PMO::ID const& scope)
|
||||
{
|
||||
return index().insert (newPlacement,scope);
|
||||
}
|
||||
|
||||
bool
|
||||
purgeScopeRecursively (PMO::ID const& scope)
|
||||
{
|
||||
size_t siz = index().size();
|
||||
if (index().contains (scope))
|
||||
index().clear (scope);
|
||||
|
||||
ENSURE (!index().contains (scope) || (scope == index().getRoot().getID()));
|
||||
ENSURE (siz >= index().size());
|
||||
return siz != index().size();
|
||||
}
|
||||
|
||||
bool
|
||||
detachElement (PMO::ID const& placementID)
|
||||
{
|
||||
return index().remove (placementID);
|
||||
}
|
||||
|
||||
private:
|
||||
PlacementIndex&
|
||||
index()
|
||||
{
|
||||
return IMPL::getPlacementIndex();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<class IMPL>
|
||||
struct ServiceAccessPoint<SessionServiceExploreScope, IMPL>
|
||||
: IMPL
|
||||
|
|
@ -225,6 +264,7 @@ namespace session {
|
|||
* global Session PImpl
|
||||
*/
|
||||
typedef SessionServices< Types< SessionServiceFetch
|
||||
, SessionServiceMutate
|
||||
, SessionServiceExploreScope
|
||||
, SessionServiceMockIndex
|
||||
, SessionServiceDefaults
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
SESSION-SERVICE-FETCH.hpp - session implementation service API: fetch PlacementRef
|
||||
SESSION-SERVICE-MUTATE.hpp - session implementation service API: add/remove session contents
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -21,12 +21,14 @@
|
|||
*/
|
||||
|
||||
|
||||
/** @file session-service-fetch.hpp
|
||||
** Implementation level session API: resolve a Placement by hash-ID.
|
||||
** This specialised service is intended to be used by PlacementRef,
|
||||
** in order to (re)-access the Placement instance within the session,
|
||||
** given the hash-ID of this placement. An implementation of this
|
||||
** service is available through the SessionServices access mechanism.
|
||||
/** @file session-service-mutate.hpp
|
||||
** Implementation level session API: add or remove Session contents.
|
||||
** This specialised service is intended to be used by MObjectRef,
|
||||
** in order to attach a new Placement to the session or to detach
|
||||
** and purge an existing Placement. An implementation of this service
|
||||
** service is available through the SessionServices access mechanism,
|
||||
** and delegates the actual implementation to the PlacementIndex,
|
||||
** which is the core session datastructure.
|
||||
**
|
||||
** @see session-impl.hpp implementation of the service
|
||||
** @see session-services.cpp implementation of access
|
||||
|
|
@ -34,8 +36,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef MOBJECT_SESSION_SESSION_SERVICE_FETCH_H
|
||||
#define MOBJECT_SESSION_SESSION_SERVICE_FETCH_H
|
||||
#ifndef MOBJECT_SESSION_SESSION_SERVICE_MUTATE_H
|
||||
#define MOBJECT_SESSION_SESSION_SERVICE_MUTATE_H
|
||||
|
||||
//#include "proc/mobject/session.hpp"
|
||||
//#include "lib/meta/generator.hpp"
|
||||
|
|
@ -47,9 +49,6 @@
|
|||
namespace mobject {
|
||||
namespace session {
|
||||
|
||||
// using lumiera::typelist::InstantiateChained;
|
||||
// using lumiera::typelist::InheritFrom;
|
||||
// using lumiera::typelist::NullType;
|
||||
|
||||
/**
|
||||
* Implementation-level service for resolving an Placement-ID.
|
||||
|
|
@ -58,13 +57,15 @@ namespace session {
|
|||
* this index may be overlaid temporarily, by using the
|
||||
* SessionServiceMockIndex API.
|
||||
*/
|
||||
class SessionServiceFetch
|
||||
class SessionServiceMutate
|
||||
{
|
||||
public:
|
||||
static PlacementMO& resolveID (PlacementMO::ID const&) ;
|
||||
static bool isRegisteredID (PlacementMO::ID const&) ;
|
||||
typedef PlacementMO const& PMO;
|
||||
typedef PlacementMO::ID const& PID;
|
||||
|
||||
static bool isAccessible() ;
|
||||
static PID attach_toModel (PMO, PID) ;
|
||||
static bool detach_and_clear (PID) ;
|
||||
static bool detach (PID) ;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "proc/mobject/session/session-service-fetch.hpp"
|
||||
#include "proc/mobject/session/session-service-mutate.hpp"
|
||||
#include "proc/mobject/session/session-service-explore-scope.hpp"
|
||||
#include "proc/mobject/session/session-service-mock-index.hpp"
|
||||
#include "proc/mobject/session/session-service-defaults.hpp"
|
||||
|
|
@ -76,6 +77,46 @@ namespace session {
|
|||
}
|
||||
|
||||
|
||||
/** attach an object by placement onto the session.
|
||||
* Implemented by registering a copy of the Placement into the
|
||||
* PlacementIndex in the session. This copy establishes a new kind of
|
||||
* "object instance", represented by a new placement-ID, which is returned
|
||||
* and can be used to refer to this "instance" within the session from now on.
|
||||
* @param scope the (existing) parent scope where to attach the new element
|
||||
*/
|
||||
PlacementMO::ID const&
|
||||
SessionServiceMutate::attach_toModel(PMO newPlacement, PID scope)
|
||||
{
|
||||
return SessionImplAPI::current->insertCopy (newPlacement,scope);
|
||||
}
|
||||
|
||||
|
||||
/** detach the denoted element from the model <i>including all children.</i>
|
||||
* @return true if actually erased something
|
||||
* @note when specifying model root, all sub-elements will be cleared,
|
||||
* but model root itself will be retained.
|
||||
*/
|
||||
bool
|
||||
SessionServiceMutate::detach_and_clear (PID scope)
|
||||
{
|
||||
return SessionImplAPI::current->purgeScopeRecursively (scope);
|
||||
}
|
||||
|
||||
|
||||
/** detach the denoted leaf element from the model.
|
||||
* @return true if actually erased something
|
||||
* @throw error::Fatal when attempting to remove the model root
|
||||
* @throw error::State when the given element contains sub elements
|
||||
*/
|
||||
bool
|
||||
SessionServiceMutate::detach (PID leafElement)
|
||||
{
|
||||
return SessionImplAPI::current->detachElement (leafElement);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // deleter function to clean up test/mock PlacementIndex
|
||||
void
|
||||
remove_testIndex (PlacementIndex* testIdx)
|
||||
|
|
|
|||
|
|
@ -240,6 +240,31 @@ namespace test {
|
|||
|
||||
ASSERT (index.remove(e133)); // but can remove an scope, after emptying it
|
||||
ASSERT (!index.contains(e133));
|
||||
|
||||
// build a complete new subtree
|
||||
uint siz = index.size();
|
||||
ID e1321 = index.insert (testObj, e132);
|
||||
ID e13211 = index.insert (testObj, e1321);
|
||||
ID e13212 = index.insert (testObj, e1321);
|
||||
ID e13213 = index.insert (testObj, e1321);
|
||||
ID e13214 = index.insert (testObj, e1321);
|
||||
ID e132131 = index.insert (testObj, e13213);
|
||||
ID e132132 = index.insert (testObj, e13213);
|
||||
ID e132133 = index.insert (testObj, e13213);
|
||||
ID e132134 = index.insert (testObj, e13213);
|
||||
ID e132141 = index.insert (testObj, e13214);
|
||||
ID e132142 = index.insert (testObj, e13214);
|
||||
ID e132143 = index.insert (testObj, e13214);
|
||||
ID e132144 = index.insert (testObj, e13214);
|
||||
|
||||
// ...and kill it recursively in one sway
|
||||
index.clear (e1321);
|
||||
ASSERT (!index.contains (e1321));
|
||||
ASSERT (!index.contains (e13211));
|
||||
ASSERT (!index.contains (e13213));
|
||||
ASSERT (!index.contains (e132131));
|
||||
ASSERT (!index.contains (e132144));
|
||||
ASSERT (siz == index.size());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ namespace test {
|
|||
using lumiera::Query;
|
||||
|
||||
typedef MORef<session::Clip> RClip;
|
||||
typedef PlacementMO::ID PID;
|
||||
|
||||
|
||||
|
||||
|
|
@ -303,7 +304,10 @@ namespace test {
|
|||
|
||||
CHECK (focus.getObject() == sess->getRoot());
|
||||
|
||||
PID currRoot = sess->getRoot.getPlacement().getID();
|
||||
sess->getRoot().purge(); // purging the root scope effectively resets the session to defaults
|
||||
CHECK (currRoot == sess->getRoot.getPlacement.getID);
|
||||
// but the root element itself is retained
|
||||
CHECK (sess->isValid());
|
||||
CHECK (1 == sess->timelines.size());
|
||||
CHECK (1 == sess->sequences.size());
|
||||
|
|
|
|||
Loading…
Reference in a new issue