1 /***********************************************************************
2 	created:	22/2/2004
3 	author:		Paul D Turner
4 
5 	purpose:	Implements the WindowFactoryManager
6 *************************************************************************/
7 /***************************************************************************
8  *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
9  *
10  *   Permission is hereby granted, free of charge, to any person obtaining
11  *   a copy of this software and associated documentation files (the
12  *   "Software"), to deal in the Software without restriction, including
13  *   without limitation the rights to use, copy, modify, merge, publish,
14  *   distribute, sublicense, and/or sell copies of the Software, and to
15  *   permit persons to whom the Software is furnished to do so, subject to
16  *   the following conditions:
17  *
18  *   The above copyright notice and this permission notice shall be
19  *   included in all copies or substantial portions of the Software.
20  *
21  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24  *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25  *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26  *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  *   OTHER DEALINGS IN THE SOFTWARE.
28  ***************************************************************************/
29 #include "CEGUI/WindowFactoryManager.h"
30 #include "CEGUI/WindowFactory.h"
31 #include "CEGUI/Exceptions.h"
32 #include <algorithm>
33 
34 // Start of CEGUI namespace section
35 namespace CEGUI
36 {
37 /*************************************************************************
38 	Static Data Definitions
39 *************************************************************************/
40 // singleton instance pointer
41 template<> WindowFactoryManager* Singleton<WindowFactoryManager>::ms_Singleton	= 0;
42 // list of owned WindowFactory object pointers
43 WindowFactoryManager::OwnedWindowFactoryList WindowFactoryManager::d_ownedFactories;
44 
45 //----------------------------------------------------------------------------//
WindowFactoryManager(void)46 WindowFactoryManager::WindowFactoryManager(void)
47 {
48     Logger::getSingleton().logEvent(
49         "CEGUI::WindowFactoryManager singleton created");
50 
51     // complete addition of any pre-added WindowFactory objects
52     WindowFactoryManager::OwnedWindowFactoryList::iterator i =
53         d_ownedFactories.begin();
54 
55     if (d_ownedFactories.end() != i)
56     {
57         Logger::getSingleton().logEvent(
58         "---- Adding pre-registered WindowFactory objects ----");
59 
60         for (; d_ownedFactories.end() != i; ++i)
61             addFactory(*i);
62     }
63 }
64 
65 /*************************************************************************
66 	Adds a WindowFactory object to the registry
67 *************************************************************************/
addFactory(WindowFactory * factory)68 void WindowFactoryManager::addFactory(WindowFactory* factory)
69 {
70 	// throw exception if passed factory is null.
71 	if (!factory)
72 	{
73 		CEGUI_THROW(NullObjectException(
74             "The provided WindowFactory pointer was invalid."));
75 	}
76 
77 	// throw exception if type name for factory is already in use
78 	if (d_factoryRegistry.find(factory->getTypeName()) != d_factoryRegistry.end())
79 	{
80 		CEGUI_THROW(AlreadyExistsException(
81             "A WindowFactory for type '" + factory->getTypeName() +
82             "' is already registered."));
83 	}
84 
85 	// add the factory to the registry
86 	d_factoryRegistry[factory->getTypeName()] = factory;
87 
88     char addr_buff[32];
89     sprintf(addr_buff, "(%p)", static_cast<void*>(factory));
90 	Logger::getSingleton().logEvent("WindowFactory for '" +
91        factory->getTypeName() +"' windows added. " + addr_buff);
92 }
93 
94 
95 /*************************************************************************
96 	removes a WindowFactory from the registry (by name)
97 *************************************************************************/
removeFactory(const String & name)98 void WindowFactoryManager::removeFactory(const String& name)
99 {
100     WindowFactoryRegistry::iterator i = d_factoryRegistry.find(name);
101 
102     // exit if no factory exists for this type
103     if (i == d_factoryRegistry.end())
104         return;
105 
106     // see if we own this factory
107     OwnedWindowFactoryList::iterator j = std::find(d_ownedFactories.begin(),
108                                                    d_ownedFactories.end(),
109                                                    (*i).second);
110 
111     char addr_buff[32];
112     sprintf(addr_buff, "(%p)", static_cast<void*>((*i).second));
113 
114 	d_factoryRegistry.erase(name);
115 
116     Logger::getSingleton().logEvent("WindowFactory for '" + name +
117                                     "' windows removed. " + addr_buff);
118 
119     // delete factory object if we created it
120     if (j != d_ownedFactories.end())
121     {
122         Logger::getSingleton().logEvent("Deleted WindowFactory for '" +
123                                         (*j)->getTypeName() +
124                                         "' windows.");
125 
126         CEGUI_DELETE_AO (*j);
127         d_ownedFactories.erase(j);
128     }
129 }
130 
131 
132 /*************************************************************************
133 	removes a WindowFactory from the registry (by pointer)
134 *************************************************************************/
removeFactory(WindowFactory * factory)135 void WindowFactoryManager::removeFactory(WindowFactory* factory)
136 {
137 	if (factory)
138 	{
139 		removeFactory(factory->getTypeName());
140 	}
141 
142 }
143 
144 //----------------------------------------------------------------------------//
removeAllFactories(void)145 void WindowFactoryManager::removeAllFactories(void)
146 {
147     while (!d_factoryRegistry.empty())
148         removeFactory((*d_factoryRegistry.begin()).second);
149 }
150 
151 
152 /*************************************************************************
153 	returns a pointer to the requested WindowFactory object
154 *************************************************************************/
getFactory(const String & type) const155 WindowFactory* WindowFactoryManager::getFactory(const String& type) const
156 {
157     // first, dereference aliased types, as needed.
158     String targetType(getDereferencedAliasType(type));
159 
160 	// try for a 'real' type
161 	WindowFactoryRegistry::const_iterator pos = d_factoryRegistry.find(targetType);
162 
163 	// found an actual factory for this type
164 	if (pos != d_factoryRegistry.end())
165 	{
166 		return pos->second;
167 	}
168     // no concrete type, try for a falagard mapped type
169     else
170     {
171         FalagardMapRegistry::const_iterator falagard = d_falagardRegistry.find(targetType);
172 
173         // found falagard mapping for this type
174         if (falagard != d_falagardRegistry.end())
175         {
176             // recursively call getFactory on the target base type
177             return getFactory(falagard->second.d_baseType);
178         }
179         // type not found anywhere, give up with an exception.
180         else
181         {
182             CEGUI_THROW(UnknownObjectException(
183                 "A WindowFactory object, an alias, or mapping for '" + type +
184                 "' Window objects is not registered with the system.\n\n"
185                 "Have you forgotten to load a scheme using "
186                 "CEGUI::SchemeManager::createFromFile(..)?"));
187         }
188     }
189 }
190 
191 
192 /*************************************************************************
193     Returns true if a WindowFactory, an alias, or a falagard mapping for
194     a specified window type is present
195 *************************************************************************/
isFactoryPresent(const String & name) const196 bool WindowFactoryManager::isFactoryPresent(const String& name) const
197 {
198     // first, dereference aliased types, as needed.
199     String targetType(getDereferencedAliasType(name));
200 
201     // now try for a 'real' type
202     if (d_factoryRegistry.find(targetType) != d_factoryRegistry.end())
203     {
204         return true;
205     }
206     // not a concrete type, so return whether it's a Falagard mapped type.
207     else
208     {
209         return (d_falagardRegistry.find(targetType) != d_falagardRegistry.end());
210     }
211 }
212 
213 
214 /*************************************************************************
215 	Return a WindowFactoryManager::WindowFactoryIterator object to
216 	iterate over the available WindowFactory types.
217 *************************************************************************/
getIterator(void) const218 WindowFactoryManager::WindowFactoryIterator	WindowFactoryManager::getIterator(void) const
219 {
220 	return WindowFactoryIterator(d_factoryRegistry.begin(), d_factoryRegistry.end());
221 }
222 
223 
224 /*************************************************************************
225 	Return a WindowFactoryManager::TypeAliasIterator object to iterate
226 	over the defined aliases for window types.
227 *************************************************************************/
getAliasIterator(void) const228 WindowFactoryManager::TypeAliasIterator WindowFactoryManager::getAliasIterator(void) const
229 {
230 	return TypeAliasIterator(d_aliasRegistry.begin(), d_aliasRegistry.end());
231 }
232 
233 
234 /*************************************************************************
235 	Add a window type alias mapping
236 *************************************************************************/
addWindowTypeAlias(const String & aliasName,const String & targetType)237 void WindowFactoryManager::addWindowTypeAlias(const String& aliasName, const String& targetType)
238 {
239 	TypeAliasRegistry::iterator pos = d_aliasRegistry.find(aliasName);
240 
241 	if (pos == d_aliasRegistry.end())
242 	{
243 		d_aliasRegistry[aliasName].d_targetStack.push_back(targetType);
244 	}
245 	// alias already exists, add our new entry to the list already there
246 	else
247 	{
248 		pos->second.d_targetStack.push_back(targetType);
249 	}
250 
251 	Logger::getSingleton().logEvent("Window type alias named '" + aliasName + "' added for window type '" + targetType +"'.");
252 }
253 
254 
255 /*************************************************************************
256 	Remove a window type alias mapping
257 *************************************************************************/
removeWindowTypeAlias(const String & aliasName,const String & targetType)258 void WindowFactoryManager::removeWindowTypeAlias(const String& aliasName, const String& targetType)
259 {
260 	// find alias name
261 	TypeAliasRegistry::iterator pos = d_aliasRegistry.find(aliasName);
262 
263 	// if alias name exists
264 	if (pos != d_aliasRegistry.end())
265 	{
266 		// find the specified target for this alias
267 		AliasTargetStack::TargetTypeStack::iterator aliasPos = std::find(pos->second.d_targetStack.begin(), pos->second.d_targetStack.end(), targetType);
268 
269 		// if the target exists for this alias
270 		if (aliasPos != pos->second.d_targetStack.end())
271 		{
272 			// erase the target mapping
273 			pos->second.d_targetStack.erase(aliasPos);
274 
275 			Logger::getSingleton().logEvent("Window type alias named '" + aliasName + "' removed for window type '" + targetType +"'.");
276 
277 			// if the list of targets for this alias is now empty
278 			if (pos->second.d_targetStack.empty())
279 			{
280 				// erase the alias name also
281 				d_aliasRegistry.erase(aliasName);
282 
283 				Logger::getSingleton().logEvent("Window type alias named '" + aliasName + "' has no more targets and has been removed.", Informative);
284 			}
285 
286 		}
287 
288 	}
289 
290 }
291 
removeAllWindowTypeAliases()292 void WindowFactoryManager::removeAllWindowTypeAliases()
293 {
294 	d_aliasRegistry.clear();
295 }
296 
addFalagardWindowMapping(const String & newType,const String & targetType,const String & lookName,const String & renderer,const String & effectName)297 void WindowFactoryManager::addFalagardWindowMapping(const String& newType,
298                                                     const String& targetType,
299                                                     const String& lookName,
300                                                     const String& renderer,
301                                                     const String& effectName)
302 {
303     WindowFactoryManager::FalagardWindowMapping mapping;
304     mapping.d_windowType = newType;
305     mapping.d_baseType   = targetType;
306     mapping.d_lookName   = lookName;
307     mapping.d_rendererType = renderer;
308     mapping.d_effectName = effectName;
309 
310     // see if the type we're creating already exists
311     if (d_falagardRegistry.find(newType) != d_falagardRegistry.end())
312     {
313         // type already exists, log the fact that it's going to be replaced.
314         Logger::getSingleton().logEvent("Falagard mapping for type '" + newType + "' already exists - current mapping will be replaced.");
315     }
316 
317     char addr_buff[32];
318     sprintf(addr_buff, "(%p)", static_cast<void*>(&mapping));
319     Logger::getSingleton().logEvent("Creating falagard mapping for type '" +
320         newType + "' using base type '" + targetType + "', window renderer '" +
321         renderer + "' Look'N'Feel '" + lookName + "' and RenderEffect '" +
322         effectName + "'. " + addr_buff);
323 
324     d_falagardRegistry[newType] = mapping;
325 }
326 
removeFalagardWindowMapping(const String & type)327 void WindowFactoryManager::removeFalagardWindowMapping(const String& type)
328 {
329     FalagardMapRegistry::iterator iter = d_falagardRegistry.find(type);
330 
331     if (iter != d_falagardRegistry.end())
332     {
333         Logger::getSingleton().logEvent("Removing falagard mapping for type '" + type + "'.");
334         d_falagardRegistry.erase(iter);
335     }
336 }
337 
removeAllFalagardWindowMappings()338 void WindowFactoryManager::removeAllFalagardWindowMappings()
339 {
340 	d_falagardRegistry.clear();
341 }
342 
getFalagardMappingIterator() const343 WindowFactoryManager::FalagardMappingIterator WindowFactoryManager::getFalagardMappingIterator() const
344 {
345     return FalagardMappingIterator(d_falagardRegistry.begin(), d_falagardRegistry.end());
346 }
347 
isFalagardMappedType(const String & type) const348 bool WindowFactoryManager::isFalagardMappedType(const String& type) const
349 {
350     return d_falagardRegistry.find(getDereferencedAliasType(type)) != d_falagardRegistry.end();
351 }
352 
getMappedLookForType(const String & type) const353 const String& WindowFactoryManager::getMappedLookForType(const String& type) const
354 {
355     FalagardMapRegistry::const_iterator iter =
356         d_falagardRegistry.find(getDereferencedAliasType(type));
357 
358     if (iter != d_falagardRegistry.end())
359     {
360         return (*iter).second.d_lookName;
361     }
362     // type does not exist as a mapped type (or an alias for one)
363     else
364     {
365         CEGUI_THROW(InvalidRequestException(
366             "Window factory type '" + type +
367             "' is not a falagard mapped type (or an alias for one)."));
368     }
369 }
370 
getMappedRendererForType(const String & type) const371 const String& WindowFactoryManager::getMappedRendererForType(const String& type) const
372 {
373     FalagardMapRegistry::const_iterator iter =
374         d_falagardRegistry.find(getDereferencedAliasType(type));
375 
376     if (iter != d_falagardRegistry.end())
377     {
378         return (*iter).second.d_rendererType;
379     }
380     // type does not exist as a mapped type (or an alias for one)
381     else
382     {
383         CEGUI_THROW(InvalidRequestException(
384             "Window factory type '" + type +
385             "' is not a falagard mapped type (or an alias for one)."));
386     }
387 }
388 
getDereferencedAliasType(const String & type) const389 String WindowFactoryManager::getDereferencedAliasType(const String& type) const
390 {
391     TypeAliasRegistry::const_iterator alias = d_aliasRegistry.find(type);
392 
393     // if this is an aliased type, ensure to fully dereference by recursively
394     // calling ourselves on the active target for the given type.
395     if (alias != d_aliasRegistry.end())
396         return getDereferencedAliasType(alias->second.getActiveTarget());
397 
398     // we're not an alias, so return the input type unchanged
399     return type;
400 }
401 
getFalagardMappingForType(const String & type) const402 const WindowFactoryManager::FalagardWindowMapping& WindowFactoryManager::getFalagardMappingForType(const String& type) const
403 {
404     FalagardMapRegistry::const_iterator iter =
405         d_falagardRegistry.find(getDereferencedAliasType(type));
406 
407     if (iter != d_falagardRegistry.end())
408     {
409         return (*iter).second;
410     }
411     // type does not exist as a mapped type (or an alias for one)
412     else
413     {
414         CEGUI_THROW(InvalidRequestException(
415             "Window factory type '" + type +
416             "' is not a falagard mapped type (or an alias for one)."));
417     }
418 }
419 
420 
421 //////////////////////////////////////////////////////////////////////////
422 /*************************************************************************
423 	Methods for AliasTargetStack class
424 *************************************************************************/
425 //////////////////////////////////////////////////////////////////////////
getActiveTarget(void) const426 const String& WindowFactoryManager::AliasTargetStack::getActiveTarget(void) const
427 {
428 	return d_targetStack.back();
429 }
430 
431 
getStackedTargetCount(void) const432 uint WindowFactoryManager::AliasTargetStack::getStackedTargetCount(void) const
433 {
434 	return (uint)d_targetStack.size();
435 }
436 
437 
438 } // End of  CEGUI namespace section
439