cello
JUCE ValueTrees for Humans
Loading...
Searching...
No Matches
cello::Object Class Reference
Inheritance diagram for cello::Object:
cello::UpdateSource cello::IpcClientProperties cello::IpcServerProperties

Public Types

enum class  FileFormat { xml , binary , zipped }
 
enum class  CreationType { initialized , wrapped }
 

Public Member Functions

 Object (const juce::String &type, const Object *state)
 Construct a new cello::Object object, which will attempt to initialize from the 'state' parameter. If 'state' contains a ValueTree of the requested type, we'll use that as our store.
 
 Object (const juce::String &type, const Object &state)
 Construct a new Object, initializing from the state argument. Follows the same descent logic used in the above constructor.
 
 Object (const juce::String &type, juce::ValueTree tree)
 Construct a new Object from a raw juce ValueTree. Its behavior mimics that of the ctor that accepts a pointer to object, attempting to either:
 
 Object (const juce::String &type, juce::File file, FileFormat format=FileFormat::xml)
 Construct a new Object by attempting to load it from a file on disk. You can test whether this succeeded by checking the return value of getCreationType() – if its value is CreationType::initialized, the load from disk failed, and this instance was default-initialized.
 
 Object (const Object &rhs)
 Construct a new Object object as a copy of an existing one. We register as a listener, but this new copy does not have any callbacks registered. Both objects will point at the same shared value tree.
 
CreationType wrap (const Object &other)
 Wrap another Object's tree after this object is created.
 
Objectoperator= (const Object &rhs)
 set this object to use a different Object's value tree, which we will begin listening to. Our valueTreeRedirected callback should be executed.
 
 ~Object () override
 Destroy the Object object The important thing done here is to remove ourselves as a listener to the value tree we're attached to.
 
bool operator== (const juce::ValueTree &rhs) const noexcept
 test for true equivalence: does this object point to the same underlying tree as the tree on the right hand side? Note that because cello::Object has operator juce::ValueTree, you can pass a reference to Object as the rhs and it will work correctly.
 
bool operator!= (const juce::ValueTree &rhs) const noexcept
 
juce::Identifier getType () const
 Get the type of this object as a juce::Identifier.
 
juce::String getTypeName () const
 Get the type of this object as a string.
 
juce::String toXmlString (const juce::XmlElement::TextFormat &format={}) const
 Generate a string representation of this object's tree.
 
CreationType getCreationType () const
 Determine how this object was created, which will be one of:
 
bool wasWrapped () const
 utility method to test the creation type as a bool.
 
bool wasInitialized () const
 utility method to test the creation type as a bool.
 
 operator juce::ValueTree () const
 Get the ValueTree we're using as our data store.
 
juce::ValueTree clone (bool deep) const
 Make and return a copy of our underlying value tree.
 
void update (const juce::MemoryBlock &updateBlock)
 Apply delta/update generated by the juce::ValueTreeSynchroniser class; this is used in the sync and ipc implementations.
 
void excludeListener (juce::ValueTree::Listener *listener)
 A listener to exclude from property change updates.
 
juce::ValueTree::Listener * getExcludedListener () const
 Get a pointer to the listener to exclude from property change updates.
 
Database functionality
juce::ValueTree find (const cello::Query &query, bool deep=false)
 Perform a query against the children of this Object, returning a new ValueTree containing zero or more copies of child trees that match the query, possibly sorted into a different order than they exist in this tree.
 
juce::ValueTree findOne (const cello::Query &query, bool deep=false)
 Perform a query against the children of this object, returning a copy of the first child found that meets the predicates in the query object, or an empty tree if none is found.
 
bool upsert (const Object *object, const juce::Identifier &key, bool deep=false)
 Update or insert a child object (concept borrowed from MongoDB) Looks for a child with a 'key' value that matches the one found in the object we've been passed. If a match is found, we update the entry in place (update). If no match is found, we append a copy of object to our children.
 
void upsertAll (const Object *parent, const juce::Identifier &key, bool deep=false)
 Perform an upsert using each of the children of the parent being passed. Common workflow here:
 
Undo/redo functionality
void setUndoManager (juce::UndoManager *undo)
 Set the undo manager to use in this object (and others created from it).
 
juce::UndoManager * getUndoManager () const
 Get the current undo manager; only useful to this object's Value objects and when creating other Objects to wrap our subtrees.
 
bool canUndo () const
 Test whether this object/tree has anything that can be undone.
 
bool undo ()
 Attempt to undo the last transaction.
 
bool canRedo () const
 Test whether this object/tree has anything that can be redone.
 
bool redo ()
 Attempt to redo the last transaction.
 
void clearUndoHistory ()
 reset the undo manager
 
Pythonesque access

We use names (ending in -attr) borrowed from Python for this set of functions to make them stand out. When using these, the Object becomes more dynamically typed; the type-safety provided by working through * the cello::Value class is bypassed, and you can add/remove attributes/properties and change their types from the object at runtime as is useful for you.

template<typename T>
getattr (const juce::Identifier &attr, const T &defaultVal) const
 Get a property value from this object, or default if it doesn't have a property with that name.
 
bool hasattr (const juce::Identifier &attr) const
 test the object to see if it has an attribute with this id.
 
template<typename T>
Objectsetattr (const juce::Identifier &attr, const T &attrVal)
 Set a new value for the specified attribute/property. We return a reference to this object so that setattr calls may be chained.
 
void delattr (const juce::Identifier &attr)
 Remove the specified property from this object.
 
- Public Member Functions inherited from cello::UpdateSource
void forceUpdate (bool shouldForceUpdate)
 If passed true, any call that sets any Value property on this Object will result in a property change update callback being executed. Default (false) behavior only performs this callback when the underlying value is changed.
 
bool shouldForceUpdate () const
 

Protected Attributes

juce::ValueTree data
 The tree where our data lives.
 
juce::UndoManager * undoManager { nullptr }
 The undo manager to use for set() operations.
 
CreationType creationType { CreationType::wrapped }
 Remember how this Object was created.
 
juce::ValueTree::Listener * excludedListener { nullptr }
 a listener to not update when properties change.
 
bool doForceUpdates { false }
 

Child Operations

using Iterator = juce::ValueTree::Iterator
 
Iterator begin ()
 
Iterator end ()
 
juce::ValueTree operator[] (int index) const
 return a child tree of this object by its index. NOTE that it does not return an object; to work with this data in its cello::Object form, you'll need to use this tree to create a new one, probably testing its type to make sure you're creating the correct Object type from it.
 
int getNumChildren () const
 Check how many children this object has.
 
void append (Object *object)
 Add a new child object to the end of our child object list,.
 
void insert (Object *object, int index)
 add a new child object at a specific index in the list.
 
Objectremove (Object *object)
 Attempt to remove a child object from this.
 
juce::ValueTree remove (int index)
 remove a child by its index.
 
void move (int fromIndex, int toIndex)
 Change the position of one of this object's children.
 
template<typename Comparator>
void sort (Comparator &comp, bool stableSort)
 Sort this object's children using the provided comparison object.
 

Callbacks

using ChildUpdateFn = std::function<void (juce::ValueTree& child, int oldIndex, int newIndex)>
 
using SelfUpdateFn = std::function<void (void)>
 
ChildUpdateFn onChildAdded
 
ChildUpdateFn onChildRemoved
 
ChildUpdateFn onChildMoved
 
SelfUpdateFn onParentChanged
 
SelfUpdateFn onTreeRedirected
 
void onPropertyChange (juce::Identifier id, PropertyUpdateFn callback)
 Install (or clear) a function to be called when one of this Object's properties changes. A cello extension to this mechanism is that you can pass in the type id of this tree, and you'll receive a callback on that key when any of the other properties that don't have a handler have changed.
 
void onPropertyChange (PropertyUpdateFn callback)
 install or clear a generic callback that will be called when any property in the object changes. The identifier of the property that changed will be passed to the callback.
 
void onPropertyChange (const ValueBase &val, PropertyUpdateFn callback)
 register a property change callback by passing in a reference to a Value object instead of its id.
 

File operations

save/load objects to/from disk.

juce::Result save (juce::File file, FileFormat format=FileFormat::xml) const
 Save the object tree to disk.
 
static juce::ValueTree load (juce::File file, FileFormat format=FileFormat::xml)
 Reload data from disk. Used in the ctor that accepts file name and format.
 

Constructor & Destructor Documentation

◆ Object() [1/5]

cello::Object::Object ( const juce::String & type,
const Object * state )

Construct a new cello::Object object, which will attempt to initialize from the 'state' parameter. If 'state' contains a ValueTree of the requested type, we'll use that as our store.

Otherwise, we look for a child of our type: if found, we use that as our data. if not found, we create and (default) intialize a new tree of our type and add it as a child to the tree pointed to by state. If state is nullptr, we create and default-initialize a new tree object.

We register as a listener to whatever value tree we just found or created.

Parameters
type
statepointer to a cello::Object; pass nullptr to default initialize.

◆ Object() [2/5]

cello::Object::Object ( const juce::String & type,
const Object & state )

Construct a new Object, initializing from the state argument. Follows the same descent logic used in the above constructor.

Parameters
type
state

◆ Object() [3/5]

cello::Object::Object ( const juce::String & type,
juce::ValueTree tree )

Construct a new Object from a raw juce ValueTree. Its behavior mimics that of the ctor that accepts a pointer to object, attempting to either:

  • use the tree directly (if its type matches ours)
  • look inside it for a tree of the correct type
  • if that's not found (or the initial tree wasn't valid) , create a tree/Object of the correct type and add it to the tree that was passed in.
Parameters
type
tree

◆ Object() [4/5]

cello::Object::Object ( const juce::String & type,
juce::File file,
Object::FileFormat format = FileFormat::xml )

Construct a new Object by attempting to load it from a file on disk. You can test whether this succeeded by checking the return value of getCreationType() – if its value is CreationType::initialized, the load from disk failed, and this instance was default-initialized.

Parameters
type
file
format

◆ Object() [5/5]

cello::Object::Object ( const Object & rhs)

Construct a new Object object as a copy of an existing one. We register as a listener, but this new copy does not have any callbacks registered. Both objects will point at the same shared value tree.

Parameters
rhsObject to initialize ourselves from.

Member Function Documentation

◆ append()

void cello::Object::append ( Object * object)

Add a new child object to the end of our child object list,.

Parameters
object

◆ canRedo()

bool cello::Object::canRedo ( ) const

Test whether this object/tree has anything that can be redone.

Returns
false if there's no undo manager or nothing to redo

◆ canUndo()

bool cello::Object::canUndo ( ) const

Test whether this object/tree has anything that can be undone.

Returns
false if there's no undo manager or nothing to undo

◆ clone()

juce::ValueTree cello::Object::clone ( bool deep) const

Make and return a copy of our underlying value tree.

Parameters
deepInclude children?
Returns
a copy of this thing.

◆ delattr()

void cello::Object::delattr ( const juce::Identifier & attr)

Remove the specified property from this object.

Parameters
attr

◆ excludeListener()

void cello::Object::excludeListener ( juce::ValueTree::Listener * listener)
inline

A listener to exclude from property change updates.

Parameters
listener

◆ find()

juce::ValueTree cello::Object::find ( const cello::Query & query,
bool deep = false )

Perform a query against the children of this Object, returning a new ValueTree containing zero or more copies of child trees that match the query, possibly sorted into a different order than they exist in this tree.

Parameters
queryQuery object that defines the search/sort criteria
deepif true, also copy sub-items from object.
Returns
juce::ValueTree

◆ findOne()

juce::ValueTree cello::Object::findOne ( const cello::Query & query,
bool deep = false )

Perform a query against the children of this object, returning a copy of the first child found that meets the predicates in the query object, or an empty tree if none is found.

Parameters
queryQuery object that defines the search/sort criteria
deepif true, also copy sub-items from object.
Returns
juce::ValueTree copy of a matching child tree or {}

◆ getattr()

template<typename T>
T cello::Object::getattr ( const juce::Identifier & attr,
const T & defaultVal ) const
inline

Get a property value from this object, or default if it doesn't have a property with that name.

Template Parameters
T
Parameters
attr
defaultVal
Returns
T

◆ getCreationType()

CreationType cello::Object::getCreationType ( ) const
inline

Determine how this object was created, which will be one of:

  • CreationType::initialized – All values were default-initialized
  • CreationType::wrapped – this object refers to a value tree that already existed

It might be an error in your application to expect one or the other and not find it at runtime.

Returns
CreationType

◆ getExcludedListener()

juce::ValueTree::Listener * cello::Object::getExcludedListener ( ) const
inline

Get a pointer to the listener to exclude from property change updates.

Returns
juce::ValueTree::Listener*

◆ getNumChildren()

int cello::Object::getNumChildren ( ) const

Check how many children this object has.

Returns
int

◆ getType()

juce::Identifier cello::Object::getType ( ) const
inline

Get the type of this object as a juce::Identifier.

Returns
juce::Identifier

◆ getTypeName()

juce::String cello::Object::getTypeName ( ) const
inline

Get the type of this object as a string.

Returns
juce::String

◆ getUndoManager()

juce::UndoManager * cello::Object::getUndoManager ( ) const

Get the current undo manager; only useful to this object's Value objects and when creating other Objects to wrap our subtrees.

Returns
juce::UndoManager*

◆ hasattr()

bool cello::Object::hasattr ( const juce::Identifier & attr) const

test the object to see if it has an attribute with this id.

Parameters
attr
Returns
true
false

◆ insert()

void cello::Object::insert ( Object * object,
int index )

add a new child object at a specific index in the list.

Parameters
object
index

◆ load()

juce::ValueTree cello::Object::load ( juce::File file,
FileFormat format = FileFormat::xml )
static

Reload data from disk. Used in the ctor that accepts file name and format.

Parameters
file
formatone of (xml, binary, zipped)
Returns
ValueTree, invalid if the attempt to load failed.

◆ move()

void cello::Object::move ( int fromIndex,
int toIndex )

Change the position of one of this object's children.

Parameters
fromIndex
toIndex

◆ onPropertyChange() [1/3]

void cello::Object::onPropertyChange ( const ValueBase & val,
PropertyUpdateFn callback )

register a property change callback by passing in a reference to a Value object instead of its id.

Parameters
val
callback

◆ onPropertyChange() [2/3]

void cello::Object::onPropertyChange ( juce::Identifier id,
PropertyUpdateFn callback )

Install (or clear) a function to be called when one of this Object's properties changes. A cello extension to this mechanism is that you can pass in the type id of this tree, and you'll receive a callback on that key when any of the other properties that don't have a handler have changed.

Parameters
idthe ID of the property that has changed.
callbackfunction to call on update.

◆ onPropertyChange() [3/3]

void cello::Object::onPropertyChange ( PropertyUpdateFn callback)
inline

install or clear a generic callback that will be called when any property in the object changes. The identifier of the property that changed will be passed to the callback.

Parameters
callback

◆ operator juce::ValueTree()

cello::Object::operator juce::ValueTree ( ) const
inline

Get the ValueTree we're using as our data store.

Returns
juce::ValueTree

◆ operator=()

Object & cello::Object::operator= ( const Object & rhs)

set this object to use a different Object's value tree, which we will begin listening to. Our valueTreeRedirected callback should be executed.

Parameters
rhs
Returns
Object&

◆ operator==()

bool cello::Object::operator== ( const juce::ValueTree & rhs) const
inlinenoexcept

test for true equivalence: does this object point to the same underlying tree as the tree on the right hand side? Note that because cello::Object has operator juce::ValueTree, you can pass a reference to Object as the rhs and it will work correctly.

Parameters
rhs
Returns
true if the same tree is on both sides.

◆ operator[]()

juce::ValueTree cello::Object::operator[] ( int index) const

return a child tree of this object by its index. NOTE that it does not return an object; to work with this data in its cello::Object form, you'll need to use this tree to create a new one, probably testing its type to make sure you're creating the correct Object type from it.

Parameters
index
Returns
juce::ValueTree; will be invalid if the index is out of range.

◆ redo()

bool cello::Object::redo ( )

Attempt to redo the last transaction.

Returns
false if there's no undo manager, nothing to redo, or the attempt to redo fails.

◆ remove() [1/2]

juce::ValueTree cello::Object::remove ( int index)

remove a child by its index.

Parameters
index
Returns
Invalid tree if the index was out of bounds.

◆ remove() [2/2]

Object * cello::Object::remove ( Object * object)

Attempt to remove a child object from this.

Parameters
objectObject containing sub-tree to remove
Returns
nullptr on failure (the specified object wasn't a child)

◆ save()

juce::Result cello::Object::save ( juce::File file,
FileFormat format = FileFormat::xml ) const

Save the object tree to disk.

Parameters
file
formatone of (xml, binary, zipped)
Returns
Result of the save operation.

◆ setattr()

template<typename T>
Object & cello::Object::setattr ( const juce::Identifier & attr,
const T & attrVal )
inline

Set a new value for the specified attribute/property. We return a reference to this object so that setattr calls may be chained.

Template Parameters
T
Parameters
attr
attrVal

◆ setUndoManager()

void cello::Object::setUndoManager ( juce::UndoManager * undo)

Set the undo manager to use in this object (and others created from it).

Parameters
undo

◆ sort()

template<typename Comparator>
void cello::Object::sort ( Comparator & comp,
bool stableSort )

Sort this object's children using the provided comparison object.

The comp object must contain a method that uses the signature: int compareElements (const ValueTree& first, const ValueTree& second) and returns

  • a value of < 0 if the first comes before the second
  • a value of 0 if the two objects are equivalent
  • a value of > 0 if the second comes before the first
Parameters
comp
stableSorttrue to keep equivalent items in the same order after sorting.

◆ toXmlString()

juce::String cello::Object::toXmlString ( const juce::XmlElement::TextFormat & format = {}) const
inline

Generate a string representation of this object's tree.

Parameters
formatspecifies details of the output.
Returns
juce::String

◆ undo()

bool cello::Object::undo ( )

Attempt to undo the last transaction.

Returns
false if there's no undo manager, nothing to undo, or the attempt to undo fails.

◆ update()

void cello::Object::update ( const juce::MemoryBlock & updateBlock)

Apply delta/update generated by the juce::ValueTreeSynchroniser class; this is used in the sync and ipc implementations.

Parameters
updateBlockBinary data to apply to this object.

◆ upsert()

bool cello::Object::upsert ( const Object * object,
const juce::Identifier & key,
bool deep = false )

Update or insert a child object (concept borrowed from MongoDB) Looks for a child with a 'key' value that matches the one found in the object we've been passed. If a match is found, we update the entry in place (update). If no match is found, we append a copy of object to our children.

Parameters
objectObject with data to update or add
keyproperty name to use to match the two entries
deepif true, also copy sub-items from object.
Returns
false if the object being added doesn't have the key property.

◆ upsertAll()

void cello::Object::upsertAll ( const Object * parent,
const juce::Identifier & key,
bool deep = false )

Perform an upsert using each of the children of the parent being passed. Common workflow here:

  1. perform a query to get a list of copies of some children.
  2. modify those copies
  3. Update them in place in their original parent container.
Parameters
parentobject with children to use as update sources
keykey to match children together
deepcopy subtrees as well?

◆ wasInitialized()

bool cello::Object::wasInitialized ( ) const
inline

utility method to test the creation type as a bool.

Returns
true if this object was created by default initialization.

◆ wasWrapped()

bool cello::Object::wasWrapped ( ) const
inline

utility method to test the creation type as a bool.

Returns
true if this object was created by wrapping an existing tree.

◆ wrap()

Object::CreationType cello::Object::wrap ( const Object & other)

Wrap another Object's tree after this object is created.

Parameters
other
Returns
CreationType, whether we were able to wrap that object or created a newly initialized child of it.

Member Data Documentation

◆ doForceUpdates

bool cello::Object::doForceUpdates { false }
protected

should we send property change notifications even if a property doesn't change?


The documentation for this class was generated from the following files: