diff --git a/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp b/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp index 12c4c958d2..06ef2b52ab 100644 --- a/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp +++ b/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp @@ -287,8 +287,8 @@ XmlElement* KnownPluginList::createXml() const { XmlElement* const e = new XmlElement ("KNOWNPLUGINS"); - for (int i = 0; i < types.size(); ++i) - e->addChildElement (types.getUnchecked(i)->createXml()); + for (int i = types.size(); --i >= 0;) + e->prependChildElement (types.getUnchecked(i)->createXml()); for (int i = 0; i < blacklist.size(); ++i) e->createNewChildElement ("BLACKLISTED")->setAttribute ("id", blacklist[i]); diff --git a/modules/juce_core/xml/juce_XmlElement.cpp b/modules/juce_core/xml/juce_XmlElement.cpp index 6032151978..0a0a72593c 100644 --- a/modules/juce_core/xml/juce_XmlElement.cpp +++ b/modules/juce_core/xml/juce_XmlElement.cpp @@ -585,18 +585,36 @@ XmlElement* XmlElement::getChildByAttribute (StringRef attributeName, StringRef void XmlElement::addChildElement (XmlElement* const newNode) noexcept { if (newNode != nullptr) + { + // The element being added must not be a child of another node! + jassert (newNode->nextListItem == nullptr); + firstChildElement.append (newNode); + } } void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept { if (newNode != nullptr) { - removeChildElement (newNode, false); + // The element being added must not be a child of another node! + jassert (newNode->nextListItem == nullptr); + firstChildElement.insertAtIndex (indexToInsertAt, newNode); } } +void XmlElement::prependChildElement (XmlElement* newNode) noexcept +{ + if (newNode != nullptr) + { + // The element being added must not be a child of another node! + jassert (newNode->nextListItem == nullptr); + + firstChildElement.insertNext (newNode); + } +} + XmlElement* XmlElement::createNewChildElement (const String& childTagName) { XmlElement* const newElement = new XmlElement (childTagName); diff --git a/modules/juce_core/xml/juce_XmlElement.h b/modules/juce_core/xml/juce_XmlElement.h index ff47977adf..3f9bfb9e22 100644 --- a/modules/juce_core/xml/juce_XmlElement.h +++ b/modules/juce_core/xml/juce_XmlElement.h @@ -504,6 +504,10 @@ public: make sure the object that you pass in will not be deleted by anything else, and make sure it's not already the child of another element. + Note that due to the XmlElement using a singly-linked-list, prependChildElement() + is an O(1) operation, but addChildElement() is an O(N) operation - so if + you're adding large number of elements, you may prefer to do so in reverse order! + @see getFirstChildElement, getNextElement, getNumChildElements, getChildElement, removeChildElement */ @@ -523,6 +527,21 @@ public: void insertChildElement (XmlElement* newChildNode, int indexToInsertAt) noexcept; + /** Inserts an element at the beginning of this element's list of children. + + Child elements are deleted automatically when their parent is deleted, so + make sure the object that you pass in will not be deleted by anything else, + and make sure it's not already the child of another element. + + Note that due to the XmlElement using a singly-linked-list, prependChildElement() + is an O(1) operation, but addChildElement() is an O(N) operation - so if + you're adding large number of elements, you may prefer to do so in reverse order! + + @param newChildNode the element to add + @see addChildElement, insertChildElement + */ + void prependChildElement (XmlElement* newChildElement) noexcept; + /** Creates a new element with the given name and returns it, after adding it as a child element. diff --git a/modules/juce_data_structures/values/juce_ValueTree.cpp b/modules/juce_data_structures/values/juce_ValueTree.cpp index 5a823f7273..2c4a94cef4 100644 --- a/modules/juce_data_structures/values/juce_ValueTree.cpp +++ b/modules/juce_data_structures/values/juce_ValueTree.cpp @@ -412,8 +412,9 @@ public: XmlElement* const xml = new XmlElement (type.toString()); properties.copyToXmlAttributes (*xml); - for (int i = 0; i < children.size(); ++i) - xml->addChildElement (children.getObjectPointerUnchecked(i)->createXml()); + // (NB: it's faster to add nodes to XML elements in reverse order) + for (int i = children.size(); --i >= 0;) + xml->prependChildElement (children.getObjectPointerUnchecked(i)->createXml()); return xml; } diff --git a/modules/juce_gui_basics/widgets/juce_TreeView.cpp b/modules/juce_gui_basics/widgets/juce_TreeView.cpp index c7672e0cb1..bf4248e4c0 100644 --- a/modules/juce_gui_basics/widgets/juce_TreeView.cpp +++ b/modules/juce_gui_basics/widgets/juce_TreeView.cpp @@ -1840,8 +1840,8 @@ XmlElement* TreeViewItem::getOpennessState (const bool canReturnNull) const e = new XmlElement ("OPEN"); - for (int i = 0; i < subItems.size(); ++i) - e->addChildElement (subItems.getUnchecked(i)->getOpennessState (true)); + for (int i = subItems.size(); --i >= 0;) + e->prependChildElement (subItems.getUnchecked(i)->getOpennessState (true)); } else {