Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / layout / juce_ComponentBuilder.cpp
blobde1bb3069698ebe088e2bab867dddc7882a44386
1 /*
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"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_ComponentBuilder.h"
33 //=============================================================================
34 namespace ComponentBuilderHelpers
36 String getStateId (const ValueTree& state)
38 return state [ComponentBuilder::idProperty].toString();
41 Component* findComponentWithID (OwnedArray<Component>& components, const String& compId)
43 jassert (compId.isNotEmpty());
45 for (int i = components.size(); --i >= 0;)
47 Component* const c = components.getUnchecked (i);
49 if (c->getComponentID() == compId)
50 return components.removeAndReturn (i);
53 return nullptr;
56 Component* findComponentWithID (Component* const c, const String& compId)
58 jassert (compId.isNotEmpty());
59 if (c->getComponentID() == compId)
60 return c;
62 for (int i = c->getNumChildComponents(); --i >= 0;)
64 Component* const child = findComponentWithID (c->getChildComponent (i), compId);
66 if (child != nullptr)
67 return child;
70 return nullptr;
73 Component* createNewComponent (ComponentBuilder::TypeHandler& type,
74 const ValueTree& state, Component* parent)
76 Component* const c = type.addNewComponentFromState (state, parent);
77 jassert (c != nullptr && c->getParentComponent() == parent);
78 c->setComponentID (getStateId (state));
79 return c;
82 void updateComponent (ComponentBuilder& builder, const ValueTree& state)
84 Component* topLevelComp = builder.getManagedComponent();
86 if (topLevelComp != nullptr)
88 ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state);
89 const String uid (getStateId (state));
91 if (type == nullptr || uid.isEmpty())
93 // ..handle the case where a child of the actual state node has changed.
94 if (state.getParent().isValid())
95 updateComponent (builder, state.getParent());
97 else
99 Component* const changedComp = findComponentWithID (topLevelComp, uid);
101 if (changedComp != nullptr)
102 type->updateComponentFromState (changedComp, state);
108 //=============================================================================
109 const Identifier ComponentBuilder::idProperty ("id");
111 ComponentBuilder::ComponentBuilder (const ValueTree& state_)
112 : state (state_), imageProvider (nullptr)
114 state.addListener (this);
117 ComponentBuilder::~ComponentBuilder()
119 state.removeListener (this);
121 #if JUCE_DEBUG
122 // Don't delete the managed component!! The builder owns that component, and will delete
123 // it automatically when it gets deleted.
124 jassert (componentRef.get() == static_cast <Component*> (component));
125 #endif
128 Component* ComponentBuilder::getManagedComponent()
130 if (component == nullptr)
132 component = createComponent();
134 #if JUCE_DEBUG
135 componentRef = component;
136 #endif
139 return component;
142 Component* ComponentBuilder::createComponent()
144 jassert (types.size() > 0); // You need to register all the necessary types before you can load a component!
146 TypeHandler* const type = getHandlerForState (state);
147 jassert (type != nullptr); // trying to create a component from an unknown type of ValueTree
149 return type != nullptr ? ComponentBuilderHelpers::createNewComponent (*type, state, nullptr) : nullptr;
152 void ComponentBuilder::registerTypeHandler (ComponentBuilder::TypeHandler* const type)
154 jassert (type != nullptr);
156 // Don't try to move your types around! Once a type has been added to a builder, the
157 // builder owns it, and you should leave it alone!
158 jassert (type->builder == nullptr);
160 types.add (type);
161 type->builder = this;
164 ComponentBuilder::TypeHandler* ComponentBuilder::getHandlerForState (const ValueTree& s) const
166 const Identifier targetType (s.getType());
168 for (int i = 0; i < types.size(); ++i)
170 TypeHandler* const t = types.getUnchecked(i);
172 if (t->getType() == targetType)
173 return t;
176 return nullptr;
179 int ComponentBuilder::getNumHandlers() const noexcept
181 return types.size();
184 ComponentBuilder::TypeHandler* ComponentBuilder::getHandler (const int index) const noexcept
186 return types [index];
189 void ComponentBuilder::setImageProvider (ImageProvider* newImageProvider) noexcept
191 imageProvider = newImageProvider;
194 ComponentBuilder::ImageProvider* ComponentBuilder::getImageProvider() const noexcept
196 return imageProvider;
199 void ComponentBuilder::valueTreePropertyChanged (ValueTree& tree, const Identifier&)
201 ComponentBuilderHelpers::updateComponent (*this, tree);
204 void ComponentBuilder::valueTreeChildAdded (ValueTree& tree, ValueTree&)
206 ComponentBuilderHelpers::updateComponent (*this, tree);
209 void ComponentBuilder::valueTreeChildRemoved (ValueTree& tree, ValueTree&)
211 ComponentBuilderHelpers::updateComponent (*this, tree);
214 void ComponentBuilder::valueTreeChildOrderChanged (ValueTree& tree)
216 ComponentBuilderHelpers::updateComponent (*this, tree);
219 void ComponentBuilder::valueTreeParentChanged (ValueTree& tree)
221 ComponentBuilderHelpers::updateComponent (*this, tree);
224 //==============================================================================
225 ComponentBuilder::TypeHandler::TypeHandler (const Identifier& valueTreeType_)
226 : builder (nullptr),
227 valueTreeType (valueTreeType_)
231 ComponentBuilder::TypeHandler::~TypeHandler()
235 ComponentBuilder* ComponentBuilder::TypeHandler::getBuilder() const noexcept
237 // A type handler needs to be registered with a ComponentBuilder before using it!
238 jassert (builder != nullptr);
239 return builder;
242 void ComponentBuilder::updateChildComponents (Component& parent, const ValueTree& children)
244 using namespace ComponentBuilderHelpers;
246 const int numExistingChildComps = parent.getNumChildComponents();
248 Array <Component*> componentsInOrder;
249 componentsInOrder.ensureStorageAllocated (numExistingChildComps);
252 OwnedArray<Component> existingComponents;
253 existingComponents.ensureStorageAllocated (numExistingChildComps);
255 int i;
256 for (i = 0; i < numExistingChildComps; ++i)
257 existingComponents.add (parent.getChildComponent (i));
259 const int newNumChildren = children.getNumChildren();
260 for (i = 0; i < newNumChildren; ++i)
262 const ValueTree childState (children.getChild (i));
264 ComponentBuilder::TypeHandler* const type = getHandlerForState (childState);
265 jassert (type != nullptr);
267 if (type != nullptr)
269 Component* c = findComponentWithID (existingComponents, getStateId (childState));
271 if (c == nullptr)
272 c = createNewComponent (*type, childState, &parent);
274 componentsInOrder.add (c);
278 // (remaining unused items in existingComponents get deleted here as it goes out of scope)
281 // Make sure the z-order is correct..
282 if (componentsInOrder.size() > 0)
284 componentsInOrder.getLast()->toFront (false);
286 for (int i = componentsInOrder.size() - 1; --i >= 0;)
287 componentsInOrder.getUnchecked(i)->toBehind (componentsInOrder.getUnchecked (i + 1));
292 END_JUCE_NAMESPACE