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_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
);
56 Component
* findComponentWithID (Component
* const c
, const String
& compId
)
58 jassert (compId
.isNotEmpty());
59 if (c
->getComponentID() == compId
)
62 for (int i
= c
->getNumChildComponents(); --i
>= 0;)
64 Component
* const child
= findComponentWithID (c
->getChildComponent (i
), compId
);
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
));
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());
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);
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
));
128 Component
* ComponentBuilder::getManagedComponent()
130 if (component
== nullptr)
132 component
= createComponent();
135 componentRef
= 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);
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
)
179 int ComponentBuilder::getNumHandlers() const noexcept
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_
)
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);
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
);
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);
269 Component
* c
= findComponentWithID (existingComponents
, getStateId (childState
));
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));