2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../core/juce_StandardHeader.h"
30 #include "juce_ValueTree.h"
31 #include "../io/streams/juce_MemoryInputStream.h"
34 //==============================================================================
35 class ValueTree::SetPropertyAction
: public UndoableAction
38 SetPropertyAction (const SharedObjectPtr
& target_
, const Identifier
& name_
,
39 const var
& newValue_
, const var
& oldValue_
,
40 const bool isAddingNewProperty_
, const bool isDeletingProperty_
)
41 : target (target_
), name (name_
), newValue (newValue_
), oldValue (oldValue_
),
42 isAddingNewProperty (isAddingNewProperty_
), isDeletingProperty (isDeletingProperty_
)
48 jassert (! (isAddingNewProperty
&& target
->hasProperty (name
)));
50 if (isDeletingProperty
)
51 target
->removeProperty (name
, nullptr);
53 target
->setProperty (name
, newValue
, nullptr);
60 if (isAddingNewProperty
)
61 target
->removeProperty (name
, nullptr);
63 target
->setProperty (name
, oldValue
, nullptr);
70 return (int) sizeof (*this); //xxx should be more accurate
73 UndoableAction
* createCoalescedAction (UndoableAction
* nextAction
)
75 if (! (isAddingNewProperty
|| isDeletingProperty
))
77 SetPropertyAction
* next
= dynamic_cast <SetPropertyAction
*> (nextAction
);
79 if (next
!= nullptr && next
->target
== target
&& next
->name
== name
80 && ! (next
->isAddingNewProperty
|| next
->isDeletingProperty
))
82 return new SetPropertyAction (target
, name
, next
->newValue
, oldValue
, false, false);
90 const SharedObjectPtr target
;
91 const Identifier name
;
94 const bool isAddingNewProperty
: 1, isDeletingProperty
: 1;
96 JUCE_DECLARE_NON_COPYABLE (SetPropertyAction
);
99 //==============================================================================
100 class ValueTree::AddOrRemoveChildAction
: public UndoableAction
103 AddOrRemoveChildAction (const SharedObjectPtr
& target_
, const int childIndex_
,
104 const SharedObjectPtr
& newChild_
)
106 child (newChild_
!= nullptr ? newChild_
: target_
->children
[childIndex_
]),
107 childIndex (childIndex_
),
108 isDeleting (newChild_
== nullptr)
110 jassert (child
!= nullptr);
116 target
->removeChild (childIndex
, nullptr);
118 target
->addChild (child
, childIndex
, nullptr);
127 target
->addChild (child
, childIndex
, nullptr);
131 // If you hit this, it seems that your object's state is getting confused - probably
132 // because you've interleaved some undoable and non-undoable operations?
133 jassert (childIndex
< target
->children
.size());
134 target
->removeChild (childIndex
, nullptr);
142 return (int) sizeof (*this); //xxx should be more accurate
146 const SharedObjectPtr target
, child
;
147 const int childIndex
;
148 const bool isDeleting
;
150 JUCE_DECLARE_NON_COPYABLE (AddOrRemoveChildAction
);
153 //==============================================================================
154 class ValueTree::MoveChildAction
: public UndoableAction
157 MoveChildAction (const SharedObjectPtr
& parent_
,
158 const int startIndex_
, const int endIndex_
)
160 startIndex (startIndex_
),
167 parent
->moveChild (startIndex
, endIndex
, nullptr);
173 parent
->moveChild (endIndex
, startIndex
, nullptr);
179 return (int) sizeof (*this); //xxx should be more accurate
182 UndoableAction
* createCoalescedAction (UndoableAction
* nextAction
)
184 MoveChildAction
* next
= dynamic_cast <MoveChildAction
*> (nextAction
);
186 if (next
!= nullptr && next
->parent
== parent
&& next
->startIndex
== endIndex
)
187 return new MoveChildAction (parent
, startIndex
, next
->endIndex
);
193 const SharedObjectPtr parent
;
194 const int startIndex
, endIndex
;
196 JUCE_DECLARE_NON_COPYABLE (MoveChildAction
);
200 //==============================================================================
201 ValueTree::SharedObject::SharedObject (const Identifier
& type_
)
202 : type (type_
), parent (nullptr)
206 ValueTree::SharedObject::SharedObject (const SharedObject
& other
)
207 : type (other
.type
), properties (other
.properties
), parent (nullptr)
209 for (int i
= 0; i
< other
.children
.size(); ++i
)
211 SharedObject
* const child
= new SharedObject (*other
.children
.getUnchecked(i
));
212 child
->parent
= this;
213 children
.add (child
);
217 ValueTree::SharedObject::~SharedObject()
219 jassert (parent
== nullptr); // this should never happen unless something isn't obeying the ref-counting!
221 for (int i
= children
.size(); --i
>= 0;)
223 const SharedObjectPtr
c (children
.getUnchecked(i
));
226 c
->sendParentChangeMessage();
230 //==============================================================================
231 void ValueTree::SharedObject::sendPropertyChangeMessage (ValueTree
& tree
, const Identifier
& property
)
233 for (int i
= valueTreesWithListeners
.size(); --i
>= 0;)
235 ValueTree
* const v
= valueTreesWithListeners
[i
];
237 v
->listeners
.call (&ValueTree::Listener::valueTreePropertyChanged
, tree
, property
);
241 void ValueTree::SharedObject::sendPropertyChangeMessage (const Identifier
& property
)
243 ValueTree
tree (this);
245 for (ValueTree::SharedObject
* t
= this; t
!= nullptr; t
= t
->parent
)
246 t
->sendPropertyChangeMessage (tree
, property
);
249 void ValueTree::SharedObject::sendChildAddedMessage (ValueTree
& tree
, ValueTree
& child
)
251 for (int i
= valueTreesWithListeners
.size(); --i
>= 0;)
253 ValueTree
* const v
= valueTreesWithListeners
[i
];
255 v
->listeners
.call (&ValueTree::Listener::valueTreeChildAdded
, tree
, child
);
259 void ValueTree::SharedObject::sendChildAddedMessage (ValueTree child
)
261 ValueTree
tree (this);
263 for (ValueTree::SharedObject
* t
= this; t
!= nullptr; t
= t
->parent
)
264 t
->sendChildAddedMessage (tree
, child
);
267 void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree
& tree
, ValueTree
& child
)
269 for (int i
= valueTreesWithListeners
.size(); --i
>= 0;)
271 ValueTree
* const v
= valueTreesWithListeners
[i
];
273 v
->listeners
.call (&ValueTree::Listener::valueTreeChildRemoved
, tree
, child
);
277 void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree child
)
279 ValueTree
tree (this);
281 for (ValueTree::SharedObject
* t
= this; t
!= nullptr; t
= t
->parent
)
282 t
->sendChildRemovedMessage (tree
, child
);
285 void ValueTree::SharedObject::sendChildOrderChangedMessage (ValueTree
& tree
)
287 for (int i
= valueTreesWithListeners
.size(); --i
>= 0;)
289 ValueTree
* const v
= valueTreesWithListeners
[i
];
291 v
->listeners
.call (&ValueTree::Listener::valueTreeChildOrderChanged
, tree
);
295 void ValueTree::SharedObject::sendChildOrderChangedMessage()
297 ValueTree
tree (this);
299 for (ValueTree::SharedObject
* t
= this; t
!= nullptr; t
= t
->parent
)
300 t
->sendChildOrderChangedMessage (tree
);
303 void ValueTree::SharedObject::sendParentChangeMessage()
305 ValueTree
tree (this);
308 for (i
= children
.size(); --i
>= 0;)
310 SharedObject
* const t
= children
[i
];
312 t
->sendParentChangeMessage();
315 for (i
= valueTreesWithListeners
.size(); --i
>= 0;)
317 ValueTree
* const v
= valueTreesWithListeners
[i
];
319 v
->listeners
.call (&ValueTree::Listener::valueTreeParentChanged
, tree
);
323 //==============================================================================
324 const var
& ValueTree::SharedObject::getProperty (const Identifier
& name
) const
326 return properties
[name
];
329 var
ValueTree::SharedObject::getProperty (const Identifier
& name
, const var
& defaultReturnValue
) const
331 return properties
.getWithDefault (name
, defaultReturnValue
);
334 void ValueTree::SharedObject::setProperty (const Identifier
& name
, const var
& newValue
, UndoManager
* const undoManager
)
336 if (undoManager
== nullptr)
338 if (properties
.set (name
, newValue
))
339 sendPropertyChangeMessage (name
);
343 const var
* const existingValue
= properties
.getVarPointer (name
);
345 if (existingValue
!= nullptr)
347 if (*existingValue
!= newValue
)
348 undoManager
->perform (new SetPropertyAction (this, name
, newValue
, *existingValue
, false, false));
352 undoManager
->perform (new SetPropertyAction (this, name
, newValue
, var::null
, true, false));
357 bool ValueTree::SharedObject::hasProperty (const Identifier
& name
) const
359 return properties
.contains (name
);
362 void ValueTree::SharedObject::removeProperty (const Identifier
& name
, UndoManager
* const undoManager
)
364 if (undoManager
== nullptr)
366 if (properties
.remove (name
))
367 sendPropertyChangeMessage (name
);
371 if (properties
.contains (name
))
372 undoManager
->perform (new SetPropertyAction (this, name
, var::null
, properties
[name
], false, true));
376 void ValueTree::SharedObject::removeAllProperties (UndoManager
* const undoManager
)
378 if (undoManager
== nullptr)
380 while (properties
.size() > 0)
382 const Identifier
name (properties
.getName (properties
.size() - 1));
383 properties
.remove (name
);
384 sendPropertyChangeMessage (name
);
389 for (int i
= properties
.size(); --i
>= 0;)
390 undoManager
->perform (new SetPropertyAction (this, properties
.getName(i
), var::null
, properties
.getValueAt(i
), false, true));
394 ValueTree
ValueTree::SharedObject::getChildWithName (const Identifier
& typeToMatch
) const
396 for (int i
= 0; i
< children
.size(); ++i
)
397 if (children
.getUnchecked(i
)->type
== typeToMatch
)
398 return ValueTree (children
.getUnchecked(i
).getObject());
400 return ValueTree::invalid
;
403 ValueTree
ValueTree::SharedObject::getOrCreateChildWithName (const Identifier
& typeToMatch
, UndoManager
* undoManager
)
405 for (int i
= 0; i
< children
.size(); ++i
)
406 if (children
.getUnchecked(i
)->type
== typeToMatch
)
407 return ValueTree (children
.getUnchecked(i
).getObject());
409 SharedObject
* const newObject
= new SharedObject (typeToMatch
);
410 addChild (newObject
, -1, undoManager
);
411 return ValueTree (newObject
);
415 ValueTree
ValueTree::SharedObject::getChildWithProperty (const Identifier
& propertyName
, const var
& propertyValue
) const
417 for (int i
= 0; i
< children
.size(); ++i
)
418 if (children
.getUnchecked(i
)->getProperty (propertyName
) == propertyValue
)
419 return ValueTree (children
.getUnchecked(i
).getObject());
421 return ValueTree::invalid
;
424 bool ValueTree::SharedObject::isAChildOf (const SharedObject
* const possibleParent
) const
426 const SharedObject
* p
= parent
;
430 if (p
== possibleParent
)
439 int ValueTree::SharedObject::indexOf (const ValueTree
& child
) const
441 return children
.indexOf (child
.object
);
444 void ValueTree::SharedObject::addChild (SharedObject
* child
, int index
, UndoManager
* const undoManager
)
446 if (child
!= nullptr && child
->parent
!= this)
448 if (child
!= this && ! isAChildOf (child
))
450 // You should always make sure that a child is removed from its previous parent before
451 // adding it somewhere else - otherwise, it's ambiguous as to whether a different
452 // undomanager should be used when removing it from its current parent..
453 jassert (child
->parent
== nullptr);
455 if (child
->parent
!= nullptr)
457 jassert (child
->parent
->children
.indexOf (child
) >= 0);
458 child
->parent
->removeChild (child
->parent
->children
.indexOf (child
), undoManager
);
461 if (undoManager
== nullptr)
463 children
.insert (index
, child
);
464 child
->parent
= this;
465 sendChildAddedMessage (ValueTree (child
));
466 child
->sendParentChangeMessage();
471 index
= children
.size();
473 undoManager
->perform (new AddOrRemoveChildAction (this, index
, child
));
478 // You're attempting to create a recursive loop! A node
479 // can't be a child of one of its own children!
485 void ValueTree::SharedObject::removeChild (const int childIndex
, UndoManager
* const undoManager
)
487 const SharedObjectPtr
child (children
[childIndex
]);
489 if (child
!= nullptr)
491 if (undoManager
== nullptr)
493 children
.remove (childIndex
);
494 child
->parent
= nullptr;
495 sendChildRemovedMessage (ValueTree (child
));
496 child
->sendParentChangeMessage();
500 undoManager
->perform (new AddOrRemoveChildAction (this, childIndex
, nullptr));
505 void ValueTree::SharedObject::removeAllChildren (UndoManager
* const undoManager
)
507 while (children
.size() > 0)
508 removeChild (children
.size() - 1, undoManager
);
511 void ValueTree::SharedObject::moveChild (int currentIndex
, int newIndex
, UndoManager
* undoManager
)
513 // The source index must be a valid index!
514 jassert (isPositiveAndBelow (currentIndex
, children
.size()));
516 if (currentIndex
!= newIndex
517 && isPositiveAndBelow (currentIndex
, children
.size()))
519 if (undoManager
== nullptr)
521 children
.move (currentIndex
, newIndex
);
522 sendChildOrderChangedMessage();
526 if (! isPositiveAndBelow (newIndex
, children
.size()))
527 newIndex
= children
.size() - 1;
529 undoManager
->perform (new MoveChildAction (this, currentIndex
, newIndex
));
534 void ValueTree::SharedObject::reorderChildren (const ReferenceCountedArray
<SharedObject
>& newOrder
, UndoManager
* undoManager
)
536 jassert (newOrder
.size() == children
.size());
538 if (undoManager
== nullptr)
541 sendChildOrderChangedMessage();
545 for (int i
= 0; i
< children
.size(); ++i
)
547 const SharedObjectPtr
child (newOrder
.getUnchecked(i
));
549 if (children
.getUnchecked(i
) != child
)
551 const int oldIndex
= children
.indexOf (child
);
552 jassert (oldIndex
>= 0);
553 moveChild (oldIndex
, i
, undoManager
);
559 bool ValueTree::SharedObject::isEquivalentTo (const SharedObject
& other
) const
561 if (type
!= other
.type
562 || properties
.size() != other
.properties
.size()
563 || children
.size() != other
.children
.size()
564 || properties
!= other
.properties
)
567 for (int i
= 0; i
< children
.size(); ++i
)
568 if (! children
.getUnchecked(i
)->isEquivalentTo (*other
.children
.getUnchecked(i
)))
575 //==============================================================================
576 ValueTree::ValueTree() noexcept
580 const ValueTree
ValueTree::invalid
;
582 ValueTree::ValueTree (const Identifier
& type_
)
583 : object (new ValueTree::SharedObject (type_
))
585 jassert (type_
.toString().isNotEmpty()); // All objects should be given a sensible type name!
588 ValueTree::ValueTree (SharedObject
* const object_
)
593 ValueTree::ValueTree (const ValueTree
& other
)
594 : object (other
.object
)
598 ValueTree
& ValueTree::operator= (const ValueTree
& other
)
600 if (listeners
.size() > 0)
602 if (object
!= nullptr)
603 object
->valueTreesWithListeners
.removeValue (this);
605 if (other
.object
!= nullptr)
606 other
.object
->valueTreesWithListeners
.add (this);
609 object
= other
.object
;
614 ValueTree::~ValueTree()
616 if (listeners
.size() > 0 && object
!= nullptr)
617 object
->valueTreesWithListeners
.removeValue (this);
620 bool ValueTree::operator== (const ValueTree
& other
) const noexcept
622 return object
== other
.object
;
625 bool ValueTree::operator!= (const ValueTree
& other
) const noexcept
627 return object
!= other
.object
;
630 bool ValueTree::isEquivalentTo (const ValueTree
& other
) const
632 return object
== other
.object
633 || (object
!= nullptr && other
.object
!= nullptr && object
->isEquivalentTo (*other
.object
));
636 ValueTree
ValueTree::createCopy() const
638 return ValueTree (object
!= nullptr ? new SharedObject (*object
) : nullptr);
641 bool ValueTree::hasType (const Identifier
& typeName
) const
643 return object
!= nullptr && object
->type
== typeName
;
646 Identifier
ValueTree::getType() const
648 return object
!= nullptr ? object
->type
: Identifier();
651 ValueTree
ValueTree::getParent() const
653 return ValueTree (object
!= nullptr ? object
->parent
: (SharedObject
*) nullptr);
656 ValueTree
ValueTree::getSibling (const int delta
) const
658 if (object
== nullptr || object
->parent
== nullptr)
661 const int index
= object
->parent
->indexOf (*this) + delta
;
662 return ValueTree (object
->parent
->children
[index
].getObject());
665 const var
& ValueTree::operator[] (const Identifier
& name
) const
667 return object
== nullptr ? var::null
: object
->getProperty (name
);
670 const var
& ValueTree::getProperty (const Identifier
& name
) const
672 return object
== nullptr ? var::null
: object
->getProperty (name
);
675 var
ValueTree::getProperty (const Identifier
& name
, const var
& defaultReturnValue
) const
677 return object
== nullptr ? defaultReturnValue
: object
->getProperty (name
, defaultReturnValue
);
680 void ValueTree::setProperty (const Identifier
& name
, const var
& newValue
, UndoManager
* const undoManager
)
682 jassert (name
.toString().isNotEmpty());
684 if (object
!= nullptr && name
.toString().isNotEmpty())
685 object
->setProperty (name
, newValue
, undoManager
);
688 bool ValueTree::hasProperty (const Identifier
& name
) const
690 return object
!= nullptr && object
->hasProperty (name
);
693 void ValueTree::removeProperty (const Identifier
& name
, UndoManager
* const undoManager
)
695 if (object
!= nullptr)
696 object
->removeProperty (name
, undoManager
);
699 void ValueTree::removeAllProperties (UndoManager
* const undoManager
)
701 if (object
!= nullptr)
702 object
->removeAllProperties (undoManager
);
705 int ValueTree::getNumProperties() const
707 return object
== nullptr ? 0 : object
->properties
.size();
710 Identifier
ValueTree::getPropertyName (const int index
) const
712 return object
== nullptr ? Identifier()
713 : object
->properties
.getName (index
);
716 //==============================================================================
717 class ValueTreePropertyValueSource
: public Value::ValueSource
,
718 public ValueTree::Listener
721 ValueTreePropertyValueSource (const ValueTree
& tree_
,
722 const Identifier
& property_
,
723 UndoManager
* const undoManager_
)
725 property (property_
),
726 undoManager (undoManager_
)
728 tree
.addListener (this);
731 ~ValueTreePropertyValueSource()
733 tree
.removeListener (this);
738 return tree
[property
];
741 void setValue (const var
& newValue
)
743 tree
.setProperty (property
, newValue
, undoManager
);
746 void valueTreePropertyChanged (ValueTree
& treeWhosePropertyHasChanged
, const Identifier
& changedProperty
)
748 if (tree
== treeWhosePropertyHasChanged
&& property
== changedProperty
)
749 sendChangeMessage (false);
752 void valueTreeChildAdded (ValueTree
&, ValueTree
&) {}
753 void valueTreeChildRemoved (ValueTree
&, ValueTree
&) {}
754 void valueTreeChildOrderChanged (ValueTree
&) {}
755 void valueTreeParentChanged (ValueTree
&) {}
759 const Identifier property
;
760 UndoManager
* const undoManager
;
762 ValueTreePropertyValueSource
& operator= (const ValueTreePropertyValueSource
&);
765 Value
ValueTree::getPropertyAsValue (const Identifier
& name
, UndoManager
* const undoManager
) const
767 return Value (new ValueTreePropertyValueSource (*this, name
, undoManager
));
770 //==============================================================================
771 int ValueTree::getNumChildren() const
773 return object
== nullptr ? 0 : object
->children
.size();
776 ValueTree
ValueTree::getChild (int index
) const
778 return ValueTree (object
!= nullptr ? (SharedObject
*) object
->children
[index
] : (SharedObject
*) nullptr);
781 ValueTree
ValueTree::getChildWithName (const Identifier
& type
) const
783 return object
!= nullptr ? object
->getChildWithName (type
) : ValueTree::invalid
;
786 ValueTree
ValueTree::getOrCreateChildWithName (const Identifier
& type
, UndoManager
* undoManager
)
788 return object
!= nullptr ? object
->getOrCreateChildWithName (type
, undoManager
) : ValueTree::invalid
;
791 ValueTree
ValueTree::getChildWithProperty (const Identifier
& propertyName
, const var
& propertyValue
) const
793 return object
!= nullptr ? object
->getChildWithProperty (propertyName
, propertyValue
) : ValueTree::invalid
;
796 bool ValueTree::isAChildOf (const ValueTree
& possibleParent
) const
798 return object
!= nullptr && object
->isAChildOf (possibleParent
.object
);
801 int ValueTree::indexOf (const ValueTree
& child
) const
803 return object
!= nullptr ? object
->indexOf (child
) : -1;
806 void ValueTree::addChild (const ValueTree
& child
, int index
, UndoManager
* const undoManager
)
808 if (object
!= nullptr)
809 object
->addChild (child
.object
, index
, undoManager
);
812 void ValueTree::removeChild (const int childIndex
, UndoManager
* const undoManager
)
814 if (object
!= nullptr)
815 object
->removeChild (childIndex
, undoManager
);
818 void ValueTree::removeChild (const ValueTree
& child
, UndoManager
* const undoManager
)
820 if (object
!= nullptr)
821 object
->removeChild (object
->children
.indexOf (child
.object
), undoManager
);
824 void ValueTree::removeAllChildren (UndoManager
* const undoManager
)
826 if (object
!= nullptr)
827 object
->removeAllChildren (undoManager
);
830 void ValueTree::moveChild (int currentIndex
, int newIndex
, UndoManager
* undoManager
)
832 if (object
!= nullptr)
833 object
->moveChild (currentIndex
, newIndex
, undoManager
);
836 //==============================================================================
837 void ValueTree::addListener (Listener
* listener
)
839 if (listener
!= nullptr)
841 if (listeners
.size() == 0 && object
!= nullptr)
842 object
->valueTreesWithListeners
.add (this);
844 listeners
.add (listener
);
848 void ValueTree::removeListener (Listener
* listener
)
850 listeners
.remove (listener
);
852 if (listeners
.size() == 0 && object
!= nullptr)
853 object
->valueTreesWithListeners
.removeValue (this);
856 //==============================================================================
857 XmlElement
* ValueTree::SharedObject::createXml() const
859 XmlElement
* const xml
= new XmlElement (type
.toString());
860 properties
.copyToXmlAttributes (*xml
);
862 for (int i
= 0; i
< children
.size(); ++i
)
863 xml
->addChildElement (children
.getUnchecked(i
)->createXml());
868 XmlElement
* ValueTree::createXml() const
870 return object
!= nullptr ? object
->createXml() : nullptr;
873 ValueTree
ValueTree::fromXml (const XmlElement
& xml
)
875 ValueTree
v (xml
.getTagName());
876 v
.object
->properties
.setFromXmlAttributes (xml
);
878 forEachXmlChildElement (xml
, e
)
879 v
.addChild (fromXml (*e
), -1, nullptr);
884 //==============================================================================
885 void ValueTree::writeToStream (OutputStream
& output
)
887 output
.writeString (getType().toString());
889 const int numProps
= getNumProperties();
890 output
.writeCompressedInt (numProps
);
893 for (i
= 0; i
< numProps
; ++i
)
895 const Identifier
name (getPropertyName(i
));
896 output
.writeString (name
.toString());
897 getProperty(name
).writeToStream (output
);
900 const int numChildren
= getNumChildren();
901 output
.writeCompressedInt (numChildren
);
903 for (i
= 0; i
< numChildren
; ++i
)
904 getChild (i
).writeToStream (output
);
907 ValueTree
ValueTree::readFromStream (InputStream
& input
)
909 const String
type (input
.readString());
912 return ValueTree::invalid
;
916 const int numProps
= input
.readCompressedInt();
920 jassertfalse
; // trying to read corrupted data!
925 for (i
= 0; i
< numProps
; ++i
)
927 const String
name (input
.readString());
928 jassert (name
.isNotEmpty());
929 const var
value (var::readFromStream (input
));
930 v
.object
->properties
.set (name
, value
);
933 const int numChildren
= input
.readCompressedInt();
935 for (i
= 0; i
< numChildren
; ++i
)
937 ValueTree
child (readFromStream (input
));
939 v
.object
->children
.add (child
.object
);
940 child
.object
->parent
= v
.object
;
946 ValueTree
ValueTree::readFromData (const void* const data
, const size_t numBytes
)
948 MemoryInputStream
in (data
, numBytes
, false);
949 return readFromStream (in
);