1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // wxFormBuilder - A Visual Dialog Editor for wxWidgets.
4 // Copyright (C) 2005 José Antonio Hurtado
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 //
20 // Written by
21 //   José Antonio Hurtado - joseantonio.hurtado@gmail.com
22 //   Juan Antonio Ortega  - jortegalalmolda@gmail.com
23 //
24 ///////////////////////////////////////////////////////////////////////////////
25 
26 #include "objectbase.h"
27 #include "database.h"
28 #include "rad/bitmaps.h"
29 #include "utils/stringutils.h"
30 #include "utils/typeconv.h"
31 #include "utils/debug.h"
32 #include "utils/wxfbexception.h"
33 #include "rad/appdata.h"
34 #include <wx/filename.h>
35 #include <wx/image.h>
36 #include <wx/dir.h>
37 #include <ticpp.h>
38 #include <wx/config.h>
39 #include <wx/tokenzr.h>
40 #include <wx/stdpaths.h>
41 #include <wx/app.h>
42 
43 //#define DEBUG_PRINT(x) cout << x
44 
45 #define OBJINFO_TAG "objectinfo"
46 #define CODEGEN_TAG "codegen"
47 #define TEMPLATE_TAG "template"
48 #define NAME_TAG "name"
49 #define DESCRIPTION_TAG "help"
50 #define CUSTOM_EDITOR_TAG "editor"
51 #define PROPERTY_TAG "property"
52 #define CHILD_TAG "child"
53 #define EVENT_TAG "event"
54 #define EVENT_CLASS_TAG "class"
55 #define CATEGORY_TAG "category"
56 #define OBJECT_TAG "object"
57 #define CLASS_TAG "class"
58 #define PACKAGE_TAG "package"
59 #define PKGDESC_TAG "desc"
60 #define PRGLANG_TAG "language"
61 #define ICON_TAG "icon"
62 #define SMALL_ICON_TAG "smallIcon"
63 #define EXPANDED_TAG "expanded"
64 #define WXVERSION_TAG "wxversion"
65 
66 
67 #ifdef __WXMAC__
68 #include <dlfcn.h>
69 #endif
70 
ObjectPackage(wxString name,wxString desc,wxBitmap icon)71 ObjectPackage::ObjectPackage(wxString name, wxString desc, wxBitmap icon)
72 {
73 	m_name = name;
74 	m_desc = desc;
75 	m_icon = icon;
76 }
77 
GetObjectInfo(unsigned int idx)78 PObjectInfo ObjectPackage::GetObjectInfo(unsigned int idx)
79 {
80 	assert (idx < m_objs.size());
81 	return m_objs[idx];
82 }
83 
AppendPackage(PObjectPackage package)84 void ObjectPackage::AppendPackage( PObjectPackage package )
85 {
86 	m_objs.insert( m_objs.end(), package->m_objs.begin(), package->m_objs.end() );
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
90 
ObjectDatabase()91 ObjectDatabase::ObjectDatabase()
92 {
93 	//InitObjectTypes();
94 	//  InitWidgetTypes();
95 	InitPropertyTypes();
96 }
97 
~ObjectDatabase()98 ObjectDatabase::~ObjectDatabase()
99 {
100     for ( ComponentLibraryMap::iterator lib = m_componentLibs.begin(); lib != m_componentLibs.end(); ++lib )
101     {
102         (*(lib->first))( lib->second );
103     }
104 
105     for ( LibraryVector::iterator lib = m_libs.begin(); lib != m_libs.end(); ++lib )
106     {
107         #ifdef __WXFB_DEBUG__
108 			// Only unload in release - can't get a good stack trace if the library is unloaded
109 			#ifdef __WXMAC__
110 				dlclose( *lib );
111 			#else
112 				(*lib)->Detach();
113 			#endif
114         #endif
115 
116 		#ifndef __WXMAC__
117 			delete *lib;
118 		#endif
119     }
120 }
121 
GetObjectInfo(wxString class_name)122 PObjectInfo ObjectDatabase::GetObjectInfo(wxString class_name)
123 {
124 	PObjectInfo info;
125 	ObjectInfoMap::iterator it = m_objs.find( class_name );
126 
127 	if ( it != m_objs.end() )
128 	{
129 		info = it->second;
130 	}
131 
132 	return info;
133 }
134 
GetPackage(unsigned int idx)135 PObjectPackage ObjectDatabase::GetPackage(unsigned int idx)
136 {
137 	assert (idx < m_pkgs.size());
138 
139 	return m_pkgs[idx];
140 }
141 
142 
143 /**
144 * @todo La herencia de propiedades ha de ser de forma recursiva.
145 */
146 
NewObject(PObjectInfo obj_info)147 PObjectBase ObjectDatabase::NewObject(PObjectInfo obj_info)
148 {
149 	PObjectBase object;
150 
151 	// Llagados aquí el objeto se crea seguro...
152 	object = PObjectBase(new ObjectBase(obj_info->GetClassName()));
153 	object->SetObjectTypeName(obj_info->GetObjectTypeName()); // *FIXME*
154 
155 	object->SetObjectInfo(obj_info);
156 
157 	PPropertyInfo prop_info;
158 	PEventInfo    event_info;
159 	PObjectInfo   class_info = obj_info;
160 
161 	unsigned int base = 0;
162 
163 	while (class_info)
164 	{
165 		unsigned int i;
166 		for (i = 0; i < class_info->GetPropertyCount(); i++)
167 		{
168 			prop_info = class_info->GetPropertyInfo(i);
169 
170 			PProperty property(new Property(prop_info, object));
171 
172 			// Set the default value, either from the property info, or an override from this class
173 			wxString defaultValue = prop_info->GetDefaultValue();
174 			if ( base > 0 )
175 			{
176 				wxString defaultValueTemp = obj_info->GetBaseClassDefaultPropertyValue( base - 1, prop_info->GetName() );
177 				if ( !defaultValueTemp.empty() )
178 				{
179 					defaultValue = defaultValueTemp;
180 				}
181 			}
182 			property->SetValue( defaultValue );
183 
184 			// Las propiedades están implementadas con una estructura "map",
185 			// ello implica que no habrá propiedades duplicadas.
186 			// En otro caso habrá que asegurarse de que dicha propiedad
187 			// no existe.
188 			// Otra cosa importante, es que el orden en que se insertan
189 			// las propiedades, de abajo-arriba, esto permite que se pueda redefir
190 			// alguna propiedad.
191 			object->AddProperty (property);
192 		}
193 
194 		for (i=0; i < class_info->GetEventCount(); i++)
195 		{
196 		  event_info = class_info->GetEventInfo(i);
197 		  PEvent event(new Event(event_info,object));
198 		  // notice that for event there isn't a default value on its creation
199 		  // because there is not handler at the moment
200 		  object->AddEvent(event);
201 		}
202 
203 		class_info = ( base < obj_info->GetBaseClassCount() ?
204 			obj_info->GetBaseClass(base++) : PObjectInfo());
205 	}
206 
207 	// si el objeto tiene la propiedad name (reservada para el nombre del
208 	// objeto) le añadimos el contador para no repetir nombres.
209 
210 	obj_info->IncrementInstanceCount();
211 
212 	unsigned int ins = obj_info->GetInstanceCount();
213 	PProperty pname = object->GetProperty( wxT(NAME_TAG) );
214 	if (pname)
215 		pname->SetValue(pname->GetValue() + StringUtils::IntToStr(ins));
216 
217 	return object;
218 }
219 
220 
CountChildrenWithSameType(PObjectBase parent,PObjectType type)221 int ObjectDatabase::CountChildrenWithSameType(PObjectBase parent,PObjectType type)
222 {
223 	unsigned int count = 0;
224 	unsigned int numChildren = parent->GetChildCount();
225 	for (unsigned int i=0; i < numChildren ; i++)
226 	{
227 		if (type == parent->GetChild(i)->GetObjectInfo()->GetObjectType())
228 			count++;
229 	}
230 
231 	return count;
232 }
233 
234 /**
235 * Crea una instancia de classname por debajo de parent.
236 * La función realiza la comprobación de tipos para crear el objeto:
237 * - Comprueba si el tipo es un tipo-hijo válido de "parent", en cuyo caso
238 *   se comprobará también que el número de hijos del mismo tipo no sobrepase
239 el máximo definido. El objeto no se crea si supera el máximo permitido.
240 * - Si el tipo-hijo no se encuentra entre los definidos para el tipo de
241 *   "parent" se intentará crearlo como hijo de alguno de los tipos hijos con el
242 *   flag item a "1". Para ello va recorriendo todos los tipos con flag item,
243 *   si no puede crear el objeto, bien por que el tipo no es válido o porque
244 *   sobrepasa el máximo permitido si intenta con el siguiente hasta que no queden
245 *   más.
246 *
247 * Nota: quizá sea conveniente que el método cree el objeto sin enlazarlo
248 *       en el árbol, para facilitar el undo-redo.
249 */
CreateObject(std::string classname,PObjectBase parent)250 PObjectBase ObjectDatabase::CreateObject( std::string classname, PObjectBase parent)
251 {
252 	PObjectBase object;
253 	PObjectInfo objInfo = GetObjectInfo( _WXSTR(classname) );
254 
255 	if (!objInfo)
256 	{
257 		THROW_WXFBEX( 	wxT("Unknown Object Type: ") << _WXSTR(classname) << wxT("\n")
258 						wxT("The most likely causes are that this copy of wxFormBuilder is out of date, or that there is a plugin missing.\n")
259 						wxT("Please check at http://www.wxFormBuilder.org") << wxT("\n") )
260 	}
261 
262 	PObjectType objType = objInfo->GetObjectType();
263 
264 	if (parent)
265 	{
266 		// Comprobamos si el tipo es válido
267 		PObjectType parentType = parent->GetObjectInfo()->GetObjectType();
268 
269 		//AUI
270 		bool aui = false;
271 		if( parentType->GetName() == wxT("form") )
272 		{
273 			aui = parent->GetPropertyAsInteger(wxT("aui_managed"));
274 		}
275 
276 		int max = parentType->FindChildType(objType, aui);
277 
278 		// FIXME! Esto es un parche para evitar crear los tipos menubar,statusbar y
279 		// toolbar en un form que no sea wxFrame.
280 		// Hay que modificar el conjunto de tipos para permitir tener varios tipos
281 		// de forms (como childType de project), pero hay mucho código no válido
282 		// para forms que no sean de tipo "form". Dicho de otra manera, hay
283 		// código que dependen del nombre del tipo, cosa que hay que evitar.
284 		if (parentType->GetName() == wxT("form") && parent->GetClassName() != wxT("Frame") &&
285 			(objType->GetName() == wxT("statusbar") ||
286 			objType->GetName() == wxT("menubar") ||
287 			objType->GetName() == wxT("ribbonbar") ||
288 			objType->GetName() == wxT("toolbar") ))
289 			return PObjectBase(); // tipo no válido
290 
291 		// No menu dropdown for wxToolBar until wx 2.9 :(
292 		if ( parentType->GetName() == wxT("tool") )
293 		{
294 			PObjectBase gParent = parent->GetParent();
295 			if (
296 				( gParent->GetClassName() == wxT("wxToolBar") ) &&
297 				( objType->GetName() == wxT("menu") )
298 			)
299 				return PObjectBase(); // not a valid type
300 		}
301 
302 		if (max != 0) // tipo válido
303 		{
304 			bool create = true;
305 
306 			// comprobamos el número de instancias
307 			if (max > 0 && CountChildrenWithSameType(parent, objType) >= max)
308 				create = false;
309 
310 			if (create)
311 				object = NewObject(objInfo);
312 		}
313 		else // max == 0
314 		{
315 			// el tipo no es válido, vamos a comprobar si podemos insertarlo
316 			// como hijo de un "item"
317 			bool created = false;
318 			for (unsigned int i=0; !created && i < parentType->GetChildTypeCount(); i++)
319 			{
320 				PObjectType childType = parentType->GetChildType(i);
321 				int max = childType->FindChildType(objType, aui);
322 
323 				if (childType->IsItem() && max != 0)
324 				{
325 					max = parentType->FindChildType(childType, aui);
326 
327 					// si el tipo es un item y además el tipo del objeto a crear
328 					// puede ser hijo del tipo del item vamos a intentar crear la
329 					// instancia del item para crear el objeto como hijo de este
330 					if (max < 0 || CountChildrenWithSameType(parent, childType) < max)
331 					{
332 						// No hay problemas para crear el item debajo de parent
333 						PObjectBase item = NewObject(GetObjectInfo(childType->GetName()));
334 
335 						//PObjectBase obj = CreateObject(classname,item);
336 						PObjectBase obj = NewObject(objInfo);
337 
338 						// la siguiente condición debe cumplirse siempre
339 						// ya que un item debe siempre contener a otro objeto
340 						if (obj)
341 						{
342 							// enlazamos item y obj
343 							item->AddChild(obj);
344 							obj->SetParent(item);
345 
346 							// sizeritem es un tipo de objeto reservado, para que el uso sea
347 							// más práctico se asignan unos valores por defecto en función
348 							// del tipo de objeto creado
349 							if ( item->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
350 								SetDefaultLayoutProperties(item);
351 
352 							object = item;
353 							created = true;
354 						}
355 						else
356 							wxLogError(wxT("Review your definitions file (objtypes.xml)"));
357 					}
358 				}
359 			}
360 		}
361 		///////////////////////////////////////////////////////////////////////
362 		// Nota: provisionalmente vamos a enlazar el objeto al padre pero
363 		//       esto debería hacerse fuera para poder implementar el Undo-Redo
364 		///////////////////////////////////////////////////////////////////////
365 		//if (object)
366 		//{
367 		//  parent->AddChild(object);
368 		//  object->SetParent(parent);
369 		//}
370 	}
371 	else // parent == NULL;
372 	{
373 		object = NewObject(objInfo);
374 	}
375 
376 	return object;
377 }
378 
CopyObject(PObjectBase obj)379 PObjectBase ObjectDatabase::CopyObject(PObjectBase obj)
380 {
381 	assert(obj);
382 
383 	PObjectInfo objInfo = obj->GetObjectInfo();
384 
385 	PObjectBase copyObj = NewObject(objInfo); // creamos la copia
386 	assert(copyObj);
387 
388 	// copiamos las propiedades
389 	unsigned int i;
390 	unsigned int count = obj->GetPropertyCount();
391 	for (i = 0; i < count; i++)
392 	{
393 		PProperty objProp = obj->GetProperty(i);
394 		assert(objProp);
395 
396 		PProperty copyProp = copyObj->GetProperty(objProp->GetName());
397 		assert(copyProp);
398 
399 		wxString propValue = objProp->GetValue();
400 		copyProp->SetValue(propValue);
401 	}
402 
403 	// ...and the event handlers
404 	count = obj->GetEventCount();
405 	for (i = 0; i < count; i++)
406 	{
407 	  PEvent event = obj->GetEvent(i);
408 	  PEvent copyEvent = copyObj->GetEvent(event->GetName());
409 	  copyEvent->SetValue(event->GetValue());
410 	}
411 
412 	// creamos recursivamente los hijos
413 	count = obj->GetChildCount();
414 	for (i = 0; i<count; i++)
415 	{
416 		PObjectBase childCopy = CopyObject(obj->GetChild(i));
417 		copyObj->AddChild(childCopy);
418 		childCopy->SetParent(copyObj);
419 	}
420 
421 	return copyObj;
422 }
423 
SetDefaultLayoutProperties(PObjectBase sizeritem)424 void ObjectDatabase::SetDefaultLayoutProperties(PObjectBase sizeritem)
425 {
426 	if ( !sizeritem->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
427 	{
428 		LogDebug( wxT("SetDefaultLayoutProperties expects a subclass of sizeritembase") );
429 		return;
430 	}
431 
432 	PObjectBase child = sizeritem->GetChild(0);
433 	PObjectInfo childInfo = child->GetObjectInfo();
434 	wxString obj_type = child->GetObjectTypeName();
435 
436 	PProperty proportion = sizeritem->GetProperty( wxT("proportion") );
437 
438 	if ( childInfo->IsSubclassOf( wxT("sizer") ) || childInfo->IsSubclassOf( wxT("gbsizer") ) || obj_type == wxT("splitter") || childInfo->GetClassName() == wxT("spacer") )
439 	{
440 		if ( proportion )
441 		{
442 			proportion->SetValue( wxT("1") );
443 		}
444 		sizeritem->GetProperty( wxT("flag") )->SetValue( wxT("wxEXPAND") );
445 	}
446 	else if ( childInfo->GetClassName() == wxT("wxStaticLine") )
447 	{
448 		sizeritem->GetProperty( wxT("flag") )->SetValue( wxT("wxEXPAND | wxALL") );
449 	}
450 	else if ( childInfo->GetClassName() == wxT("wxToolBar") )
451 	{
452 		sizeritem->GetProperty( wxT("flag") )->SetValue( wxT("wxEXPAND") );
453 	}
454 	else if ( obj_type == wxT("widget") || obj_type == wxT("statusbar") )
455 	{
456 		if ( proportion )
457 		{
458 			proportion->SetValue( wxT("0") );
459 		}
460 		sizeritem->GetProperty( wxT("flag") )->SetValue( wxT("wxALL") );
461 	}
462 	else if (	obj_type == wxT("notebook")			||
463 				obj_type == wxT("flatnotebook")		||
464 				obj_type == wxT("listbook")			||
465 				obj_type == wxT("choicebook")		||
466 				obj_type == wxT("auinotebook")		||
467 				obj_type == wxT("treelistctrl")		||
468 				obj_type == wxT("expanded_widget")	||
469 				obj_type == wxT("container")
470 				)
471 	{
472 		if ( proportion )
473 		{
474 			proportion->SetValue( wxT("1") );
475 		}
476 		sizeritem->GetProperty( wxT("flag") )->SetValue( wxT("wxEXPAND | wxALL") );
477 	}
478 }
479 
ResetObjectCounters()480 void ObjectDatabase::ResetObjectCounters()
481 {
482 	ObjectInfoMap::iterator it;
483 	for (it = m_objs.begin() ; it != m_objs.end() ; it++)
484 	{
485 		it->second->ResetInstanceCount();
486 	}
487 }
488 
489 ///////////////////////////////////////////////////////////////////////
490 
CreateObject(ticpp::Element * xml_obj,PObjectBase parent)491 PObjectBase ObjectDatabase::CreateObject( ticpp::Element* xml_obj, PObjectBase parent )
492 {
493 	try
494 	{
495 		std::string class_name;
496 		xml_obj->GetAttribute( CLASS_TAG, &class_name, false );
497 
498 		PObjectBase newobject = CreateObject( class_name, parent );
499 
500 		// It is possible the CreateObject returns an "item" containing the object, e.g. SizerItem or SplitterItem
501 		// If that is the case, reassign "object" to the actual object
502 		PObjectBase object = newobject;
503 		if ( object && object->GetChildCount() > 0 )
504 		{
505 			object = object->GetChild( 0 );
506 		}
507 
508 		if ( object )
509 		{
510 			// Get the state of expansion in the object tree
511 			bool expanded;
512 			xml_obj->GetAttributeOrDefault( EXPANDED_TAG, &expanded, true );
513 			object->SetExpanded( expanded );
514 
515 			// Load the properties
516 			ticpp::Element* xml_prop = xml_obj->FirstChildElement( PROPERTY_TAG, false );
517 			while ( xml_prop )
518 			{
519 				std::string prop_name;
520 				xml_prop->GetAttribute( NAME_TAG, &prop_name, false );
521 				PProperty prop = object->GetProperty( _WXSTR(prop_name) );
522 
523 				if ( prop ) // does the property exist
524 				{
525 					// load the value
526 					prop->SetValue( _WXSTR( xml_prop->GetText( false ) ) );
527 				}
528 				else
529 				{
530 					std::string value = xml_prop->GetText( false );
531 					if ( !value.empty() )
532 					{
533 						wxLogError( wxT("The property named \"%s\" of class \"%s\" is not supported by this version of wxFormBuilder.\n")
534 									wxT("If your project file was just converted from an older version, then the conversion was not complete.\n")
535 									wxT("Otherwise, this project is from a newer version of wxFormBuilder.\n\n")
536 									wxT("The property's value is: %s\n")
537 									wxT("If you save this project, YOU WILL LOSE DATA"), _WXSTR(prop_name).c_str(), _WXSTR(class_name).c_str(), _WXSTR(value).c_str() );
538 					}
539 				}
540 
541 				xml_prop = xml_prop->NextSiblingElement( PROPERTY_TAG, false );
542 			}
543 
544 			// load the event handlers
545 			ticpp::Element* xml_event = xml_obj->FirstChildElement( EVENT_TAG, false );
546 			while ( xml_event )
547 			{
548 				std::string event_name;
549 				xml_event->GetAttribute( NAME_TAG, &event_name, false );
550 				PEvent event = object->GetEvent( _WXSTR(event_name) );
551 				if ( event )
552 				{
553 					event->SetValue( _WXSTR( xml_event->GetText( false ) ) );
554 				}
555 
556 				xml_event = xml_event->NextSiblingElement( EVENT_TAG, false );
557 			}
558 
559 
560 			if ( parent )
561 			{
562 				// set up parent/child relationship
563 				parent->AddChild( newobject );
564 				newobject->SetParent( parent );
565 			}
566 
567 			// create the children
568 			ticpp::Element* child = xml_obj->FirstChildElement( OBJECT_TAG, false );
569 			while ( child )
570 			{
571 				CreateObject( child, object );
572 				child = child->NextSiblingElement( OBJECT_TAG, false );
573 			}
574 		}
575 
576 		return newobject;
577 	}
578 	catch( ticpp::Exception& )
579 	{
580 		return PObjectBase();
581 	}
582 }
583 
584 //////////////////////////////
585 
IncludeInPalette(wxString type)586 bool IncludeInPalette(wxString type)
587 {
588 	return true;
589 }
590 
LoadPlugins(PwxFBManager manager)591 void ObjectDatabase::LoadPlugins( PwxFBManager manager )
592 {
593 	// Load some default templates
594 	LoadCodeGen( m_xmlPath + wxT("properties.cppcode") );
595 	LoadCodeGen( m_xmlPath + wxT("properties.pythoncode") );
596 	LoadCodeGen( m_xmlPath + wxT("properties.luacode") );
597 	LoadCodeGen( m_xmlPath + wxT("properties.phpcode") );
598 	LoadPackage( m_xmlPath + wxT("default.xml"), m_iconPath );
599 	LoadCodeGen( m_xmlPath + wxT("default.cppcode") );
600 	LoadCodeGen( m_xmlPath + wxT("default.pythoncode") );
601 	LoadCodeGen( m_xmlPath + wxT("default.luacode") );
602 	LoadCodeGen( m_xmlPath + wxT("default.phpcode") );
603 
604 	// Map to temporarily hold plugins.
605 	// Used to both set page order and to prevent two plugins with the same name.
606 	typedef std::map< wxString, PObjectPackage > PackageMap;
607 	PackageMap packages;
608 
609 	// Open plugins directory for iteration
610 	if ( !wxDir::Exists( m_pluginPath ) )
611 	{
612 		return;
613 	}
614 
615 	wxDir pluginsDir( m_pluginPath );
616 	if ( !pluginsDir.IsOpened() )
617 	{
618 		return;
619 	}
620 
621 	// Iterate through plugin directories and load the package from the xml subdirectory
622 	wxString pluginDirName;
623 	bool moreDirectories = pluginsDir.GetFirst( &pluginDirName, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN );
624     while ( moreDirectories )
625     {
626     	// Iterate through .xml files in the xml directory
627     	wxString nextPluginPath = m_pluginPath + pluginDirName;
628     	wxString nextPluginXmlPath = nextPluginPath + wxFILE_SEP_PATH + wxT("xml");
629     	wxString nextPluginIconPath = nextPluginPath + wxFILE_SEP_PATH + wxT("icons");
630     	if ( wxDir::Exists( nextPluginPath ) )
631     	{
632     		if ( wxDir::Exists( nextPluginXmlPath ) )
633     		{
634 				wxDir pluginXmlDir( nextPluginXmlPath );
635 				if ( pluginXmlDir.IsOpened() )
636 				{
637 					std::map< wxString, PObjectPackage > packagesToSetup;
638 					wxString packageXmlFile;
639 					bool moreXmlFiles = pluginXmlDir.GetFirst( &packageXmlFile, wxT("*.xml"), wxDIR_FILES | wxDIR_HIDDEN );
640 					while ( moreXmlFiles )
641 					{
642 						try
643 						{
644 							wxFileName nextXmlFile( nextPluginXmlPath + wxFILE_SEP_PATH + packageXmlFile );
645 							if ( !nextXmlFile.IsAbsolute() )
646 							{
647 								nextXmlFile.MakeAbsolute();
648 							}
649 
650 							PObjectPackage package = LoadPackage( nextXmlFile.GetFullPath(), nextPluginIconPath );
651 							if ( package )
652 							{
653 								// Load all packages, then setup all packages
654 								// this allows multiple packages sharing one library
655 								packagesToSetup[ nextXmlFile.GetFullPath() ] = package;
656 							}
657 						}
658 						catch ( wxFBException& ex )
659 						{
660 							wxLogError( ex.what() );
661 						}
662 						moreXmlFiles = pluginXmlDir.GetNext( &packageXmlFile );
663 					}
664 
665 					std::map< wxString, PObjectPackage >::iterator packageIt;
666 					for ( packageIt = packagesToSetup.begin(); packageIt != packagesToSetup.end(); ++packageIt )
667 					{
668 						// Setup the inheritance for base classes
669 						wxFileName fullNextPluginPath( nextPluginPath );
670 						if ( !fullNextPluginPath.IsAbsolute() )
671 						{
672 							fullNextPluginPath.MakeAbsolute();
673 						}
674 						wxFileName xmlFileName( packageIt->first );
675 						try
676 						{
677 							SetupPackage( xmlFileName.GetFullPath(), fullNextPluginPath.GetFullPath(), manager );
678 
679 							// Load the C++ code tempates
680 							xmlFileName.SetExt( wxT("cppcode") );
681 							LoadCodeGen( xmlFileName.GetFullPath() );
682 
683 							// Load the Python code tempates
684 							xmlFileName.SetExt( wxT("pythoncode") );
685 							LoadCodeGen( xmlFileName.GetFullPath() );
686 
687 							// Load the PHP code tempates
688 							xmlFileName.SetExt( wxT("phpcode") );
689 							LoadCodeGen( xmlFileName.GetFullPath() );
690 
691 							// Load the Lua code tempates
692 							xmlFileName.SetExt( wxT("luacode") );
693 							LoadCodeGen( xmlFileName.GetFullPath() );
694 
695 							std::pair< PackageMap::iterator, bool > addedPackage = packages.insert( PackageMap::value_type( packageIt->second->GetPackageName(), packageIt->second ) );
696 							if ( !addedPackage.second )
697 							{
698 								addedPackage.first->second->AppendPackage( packageIt->second );
699 #if wxVERSION_NUMBER < 2900
700 								LogDebug( _("Merged plugins named \"%s\""), packageIt->second->GetPackageName().c_str() );
701 #else
702                                 LogDebug( "Merged plugins named \"" + packageIt->second->GetPackageName() + "\"" );
703 #endif
704 							}
705 
706 						}
707 						catch ( wxFBException& ex )
708 						{
709 							wxLogError( ex.what() );
710 						}
711 					}
712 				}
713     		}
714     	}
715 
716         moreDirectories = pluginsDir.GetNext( &pluginDirName );
717     }
718 
719     // Get previous plugin order
720 	wxConfigBase* config = wxConfigBase::Get();
721 	wxString pages = config->Read( wxT("/palette/pageOrder"), wxT("Common,Additional,Data,Containers,Menu/Toolbar,Layout,Forms,Ribbon") );
722 
723 	// Add packages to the vector in the correct order
724 	wxStringTokenizer packageList( pages, wxT(",") );
725 	while ( packageList.HasMoreTokens() )
726 	{
727 		wxString packageName = packageList.GetNextToken();
728 		PackageMap::iterator packageIt = packages.find( packageName );
729 		if ( packages.end() == packageIt )
730 		{
731 			// Plugin missing - move on
732 			continue;
733 		}
734 		m_pkgs.push_back( packageIt->second );
735 		packages.erase( packageIt );
736 	}
737 
738     // If any packages remain in the map, they are new plugins and must still be added
739     for ( PackageMap::iterator packageIt = packages.begin(); packageIt != packages.end(); ++packageIt )
740     {
741     	m_pkgs.push_back( packageIt->second );
742     }
743 }
744 
SetupPackage(const wxString & file,const wxString & path,PwxFBManager manager)745 void ObjectDatabase::SetupPackage( const wxString& file, const wxString& path, PwxFBManager manager )
746 {
747 	#ifdef __WXMSW__
748 		wxString libPath = path;
749 	#else
750 		wxStandardPathsBase& stdpaths = wxStandardPaths::Get();
751 		wxString libPath = stdpaths.GetPluginsDir();
752 		libPath.Replace( wxTheApp->GetAppName().c_str(), wxT("wxformbuilder") );
753 	#endif
754 
755     // Renamed libraries for convenience in debug using a "-xx" wx version as suffix.
756     // This will also prevent loading debug libraries in release and vice versa,
757     // that used to cause crashes when trying to debug.
758     wxString wxver = wxT("");
759 
760 #ifdef DEBUG
761     #if wxVERSION_NUMBER < 2900
762         wxver = wxT("d");
763     #endif
764 	#ifdef APPEND_WXVERSION
765 		wxver = wxver + wxString::Format( wxT("-%i%i"), wxMAJOR_VERSION, wxMINOR_VERSION );
766 	#endif
767 #endif
768 
769 	try
770 	{
771 		ticpp::Document doc;
772 		XMLUtils::LoadXMLFile( doc, true, file );
773 
774 		ticpp::Element* root = doc.FirstChildElement( PACKAGE_TAG );
775 
776 		// get the library to import
777 		std::string lib;
778 		root->GetAttributeOrDefault( "lib", &lib, "" );
779 		if ( !lib.empty() )
780 		{
781 			// Allows plugin dependency dlls to be next to plugin dll in windows
782 			wxString workingDir = ::wxGetCwd();
783 			wxFileName::SetCwd( libPath );
784 			try
785 			{
786 				wxString fullLibPath = libPath + wxFILE_SEP_PATH + _WXSTR(lib) + wxver;
787 				if ( m_importedLibraries.insert( fullLibPath ).second )
788 				{
789 					ImportComponentLibrary( fullLibPath, manager );
790 				}
791 			}
792 			catch ( ... )
793 			{
794 				// Put Cwd back
795 				wxFileName::SetCwd( workingDir );
796 				throw;
797 			}
798 
799 			// Put Cwd back
800 			wxFileName::SetCwd( workingDir );
801 		}
802 
803 		ticpp::Element* elem_obj = root->FirstChildElement( OBJINFO_TAG, false );
804 		while ( elem_obj )
805 		{
806 			std::string wxver;
807 			elem_obj->GetAttributeOrDefault( WXVERSION_TAG, &wxver, "" );
808 			if( wxver != "" )
809 			{
810 				long wxversion = 0;
811 				// skip widgets supported by higher wxWidgets version than used for the build
812 				if( (! _WXSTR(wxver).ToLong( &wxversion ) ) || (wxversion > wxVERSION_NUMBER) )
813 				{
814 					elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
815 					continue;
816 				}
817 			}
818 
819 			std::string class_name;
820 			elem_obj->GetAttribute( CLASS_TAG, &class_name );
821 
822 			PObjectInfo class_info = GetObjectInfo( _WXSTR(class_name) );
823 
824 			ticpp::Element* elem_base = elem_obj->FirstChildElement( "inherits", false );
825 			while ( elem_base )
826 			{
827 				std::string base_name;
828 				elem_base->GetAttribute( CLASS_TAG, &base_name );
829 
830 				// Add a reference to its base class
831 				PObjectInfo base_info  = GetObjectInfo( _WXSTR(base_name) );
832 				if ( class_info && base_info )
833 				{
834 					size_t baseIndex = class_info->AddBaseClass( base_info );
835 
836 					std::string prop_name, value;
837 					ticpp::Element* inheritedProperty = elem_base->FirstChildElement( "property", false );
838 					while( inheritedProperty )
839 					{
840 						inheritedProperty->GetAttribute( NAME_TAG, &prop_name );
841 						value = inheritedProperty->GetText();
842 						class_info->AddBaseClassDefaultPropertyValue( baseIndex, _WXSTR(prop_name), _WXSTR(value) );
843 						inheritedProperty = inheritedProperty->NextSiblingElement( "property", false );
844 					}
845 				}
846 				elem_base = elem_base->NextSiblingElement( "inherits", false );
847 			}
848 
849 			// Add the "C++" base class, predefined for the components and widgets
850 			wxString typeName = class_info->GetObjectTypeName();
851 			if ( HasCppProperties( typeName ) )
852 			{
853 				PObjectInfo cpp_interface = GetObjectInfo( wxT("C++") );
854 				if ( cpp_interface )
855 				{
856 					size_t baseIndex = class_info->AddBaseClass( cpp_interface );
857 					if (    typeName == wxT("sizer")    ||
858                             typeName == wxT("gbsizer")  ||
859                             typeName == wxT("menuitem")  )
860 					{
861 						class_info->AddBaseClassDefaultPropertyValue( baseIndex, _("permission"), _("none") );
862 					}
863 				}
864 			}
865 
866 			elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
867 		}
868 	}
869 	catch ( ticpp::Exception& ex )
870 	{
871 		THROW_WXFBEX( _WXSTR(ex.m_details) );
872 	}
873 }
874 
HasCppProperties(wxString type)875 bool ObjectDatabase::HasCppProperties(wxString type)
876 {
877 	return (type == wxT("notebook")			||
878 			type == wxT("flatnotebook")		||
879 			type == wxT("listbook")			||
880 			type == wxT("choicebook")		||
881 			type == wxT("auinotebook")		||
882 			type == wxT("widget")			||
883 			type == wxT("expanded_widget")	||
884 			type == wxT("propgrid")	||
885 			type == wxT("propgridman")	||
886 			type == wxT("statusbar")		   ||
887 			type == wxT("component")		   ||
888 			type == wxT("container")		   ||
889 			type == wxT("menubar")			   ||
890 			type == wxT("menu")				   ||
891 			type == wxT("menuitem")			   ||
892 			type == wxT("submenu")			   ||
893 			type == wxT("toolbar")			   ||
894 			type == wxT("ribbonbar")			||
895 			type == wxT("ribbonpage")			||
896 			type == wxT("ribbonpanel")			||
897 			type == wxT("ribbonbuttonbar")		||
898 			type == wxT("ribbonbutton")			||
899 			type == wxT("ribbondropdownbutton" )	||
900 			type == wxT("ribbonhybridbutton" ) 	||
901 			type == wxT("ribbontogglebutton" ) 	||
902 			type == wxT("ribbontoolbar")	   		||
903 			type == wxT("ribbontool")		   	||
904 			type == wxT("ribbondropdowntool" )  	||
905 			type == wxT("ribbonhybridtool" )  		||
906 			type == wxT("ribbontoggletool" )  		||
907 			type == wxT("ribbongallery")	   		||
908 			type == wxT("ribbongalleryitem")   		||
909 			type == wxT("dataviewctrl")		   	||
910 			type == wxT("dataviewtreectrl")	  	||
911 			type == wxT("dataviewlistctrl")	   	||
912 			type == wxT("dataviewlistcolumn")	   	||
913 			type == wxT("tool")				||
914 			type == wxT("splitter")			||
915 			type == wxT("treelistctrl")		||
916 			type == wxT("sizer")			||
917 			type == wxT("nonvisual")		||
918 			type == wxT("gbsizer")          ||
919 			type == wxT("propgriditem")          ||
920 			type == wxT("propgridpage")          ||
921 			type == wxT("gbsizer")          ||
922             type == wxT("wizardpagesimple")
923 			);
924 }
925 
LoadCodeGen(const wxString & file)926 void ObjectDatabase::LoadCodeGen( const wxString& file )
927 {
928 	try
929 	{
930 		ticpp::Document doc;
931 		XMLUtils::LoadXMLFile( doc, true, file );
932 
933 		// read the codegen element
934 		ticpp::Element* elem_codegen = doc.FirstChildElement("codegen");
935 		std::string language;
936 		elem_codegen->GetAttribute( "language", &language );
937 		wxString lang = _WXSTR(language);
938 
939 		// read the templates
940 		ticpp::Element* elem_templates = elem_codegen->FirstChildElement( "templates", false );
941 		while ( elem_templates  )
942 		{
943 
944 			std::string prop_name;
945 			elem_templates->GetAttribute( "property", &prop_name, false );
946 			bool hasProp = !prop_name.empty();
947 
948 			std::string class_name;
949 			elem_templates->GetAttribute( "class", &class_name, !hasProp );
950 
951 			PCodeInfo code_info( new CodeInfo() );
952 
953 			ticpp::Element* elem_template = elem_templates->FirstChildElement( "template", false );
954 			while ( elem_template )
955 			{
956 				std::string template_name;
957 				elem_template->GetAttribute( "name", &template_name );
958 
959 				std::string template_code = elem_template->GetText( false );
960 
961 				code_info->AddTemplate( _WXSTR(template_name), _WXSTR(template_code) );
962 
963 				elem_template = elem_template->NextSiblingElement( "template", false );
964 			}
965 
966 			if ( hasProp )
967 			{
968 				// store code info for properties
969 				if ( !m_propertyTypeTemplates[ ParsePropertyType( _WXSTR(prop_name) ) ].insert( LangTemplateMap::value_type( lang, code_info ) ).second )
970 				{
971 					wxLogError( _("Found second template definition for property \"%s\" for language \"%s\""), _WXSTR(prop_name).c_str(), lang.c_str() );
972 				}
973 			}
974 			else
975 			{
976 				// store code info for objects
977 				PObjectInfo obj_info = GetObjectInfo( _WXSTR(class_name) );
978 				if ( obj_info )
979 				{
980 					obj_info->AddCodeInfo( lang, code_info );
981 				}
982 			}
983 
984 			elem_templates = elem_templates->NextSiblingElement( "templates", false );
985 		}
986 	}
987 	catch( ticpp::Exception& ex )
988 	{
989 		wxLogError( _WXSTR(ex.m_details) );
990 	}
991 	catch( wxFBException& ex )
992 	{
993 		wxLogError( ex.what() );
994 	}
995 }
996 
LoadPackage(const wxString & file,const wxString & iconPath)997 PObjectPackage ObjectDatabase::LoadPackage( const wxString& file, const wxString& iconPath )
998 {
999 	PObjectPackage package;
1000 
1001 	try
1002 	{
1003 		ticpp::Document doc;
1004 		XMLUtils::LoadXMLFile( doc, true, file );
1005 
1006 		ticpp::Element* root = doc.FirstChildElement( PACKAGE_TAG );
1007 
1008 		// Name Attribute
1009 		std::string pkg_name;
1010 		root->GetAttribute( NAME_TAG, &pkg_name );
1011 
1012 		// Description Attribute
1013 		std::string pkg_desc;
1014 		root->GetAttributeOrDefault( PKGDESC_TAG, &pkg_desc, "" );
1015 
1016 		// Icon Path Attribute
1017 		std::string pkgIconName;
1018 		root->GetAttributeOrDefault( ICON_TAG, &pkgIconName, "" );
1019 		wxString pkgIconPath = iconPath + wxFILE_SEP_PATH +  _WXSTR(pkgIconName);
1020 
1021 		wxBitmap pkg_icon;
1022 		if ( !pkgIconName.empty() && wxFileName::FileExists( pkgIconPath ) )
1023 		{
1024 			wxImage image( pkgIconPath, wxBITMAP_TYPE_ANY );
1025 			pkg_icon = wxBitmap( image.Scale( 16, 16 ) );
1026 		}
1027 		else
1028 		{
1029 			pkg_icon = AppBitmaps::GetBitmap( wxT("unknown"), 16 );
1030 		}
1031 
1032 		package = PObjectPackage ( new ObjectPackage( _WXSTR(pkg_name), _WXSTR(pkg_desc), pkg_icon ) );
1033 
1034 
1035 		ticpp::Element* elem_obj = root->FirstChildElement( OBJINFO_TAG, false );
1036 
1037 		while (elem_obj)
1038 		{
1039 			std::string class_name;
1040 			elem_obj->GetAttribute( CLASS_TAG, &class_name );
1041 
1042 			std::string type;
1043 			elem_obj->GetAttribute( "type", &type );
1044 
1045 			std::string icon;
1046 			elem_obj->GetAttributeOrDefault( "icon", &icon, "" );
1047 			wxString iconFullPath = iconPath + wxFILE_SEP_PATH + _WXSTR(icon);
1048 
1049 			std::string smallIcon;
1050 			elem_obj->GetAttributeOrDefault( "smallIcon", &smallIcon, "" );
1051 			wxString smallIconFullPath = iconPath + wxFILE_SEP_PATH + _WXSTR(smallIcon);
1052 
1053 			std::string wxver;
1054 			elem_obj->GetAttributeOrDefault( WXVERSION_TAG, &wxver, "" );
1055 			if( wxver != "" )
1056 			{
1057 				long wxversion = 0;
1058 				// skip widgets supported by higher wxWidgets version than used for the build
1059 				if( (! _WXSTR(wxver).ToLong( &wxversion ) ) || (wxversion > wxVERSION_NUMBER) )
1060 				{
1061 					elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
1062 					continue;
1063 				}
1064 			}
1065 
1066 			bool startGroup;
1067 			elem_obj->GetAttributeOrDefault( "startgroup", &startGroup, false );
1068 
1069 			PObjectInfo obj_info( new ObjectInfo( _WXSTR(class_name), GetObjectType( _WXSTR(type) ), package, startGroup ) );
1070 
1071 			if ( !icon.empty() && wxFileName::FileExists( iconFullPath ) )
1072 			{
1073 				wxImage img( iconFullPath, wxBITMAP_TYPE_ANY );
1074 				obj_info->SetIconFile( wxBitmap( img.Scale( ICON_SIZE, ICON_SIZE ) ) );
1075 			}
1076 			else
1077 			{
1078 				obj_info->SetIconFile( AppBitmaps::GetBitmap( wxT("unknown"), ICON_SIZE ) );
1079 			}
1080 
1081 			if ( !smallIcon.empty() && wxFileName::FileExists( smallIconFullPath ) )
1082 			{
1083 				wxImage img( smallIconFullPath, wxBITMAP_TYPE_ANY );
1084 				obj_info->SetSmallIconFile( wxBitmap( img.Scale( SMALL_ICON_SIZE, SMALL_ICON_SIZE ) ) );
1085 			}
1086 			else
1087 			{
1088 				wxImage img = obj_info->GetIconFile().ConvertToImage();
1089 				obj_info->SetSmallIconFile( wxBitmap( img.Scale( SMALL_ICON_SIZE, SMALL_ICON_SIZE ) ) );
1090 			}
1091 
1092 			// Parse the Properties
1093 			std::set< PropertyType > types;
1094 			ParseProperties( elem_obj, obj_info, obj_info->GetCategory(), &types );
1095 			ParseEvents    ( elem_obj, obj_info, obj_info->GetCategory() );
1096 
1097 			// Add the ObjectInfo to the map
1098 			m_objs.insert(ObjectInfoMap::value_type( _WXSTR(class_name), obj_info ) );
1099 
1100 			// Add the object to the palette
1101 			if ( ShowInPalette( obj_info->GetObjectTypeName() ) )
1102 			{
1103 				package->Add( obj_info );
1104 			}
1105 
1106 			elem_obj = elem_obj->NextSiblingElement( OBJINFO_TAG, false );
1107 		}
1108 	}
1109 	catch ( ticpp::Exception& ex )
1110 	{
1111 		THROW_WXFBEX( _WXSTR(ex.m_details) );
1112 	}
1113 
1114 	return package;
1115 }
1116 
ParseProperties(ticpp::Element * elem_obj,PObjectInfo obj_info,PPropertyCategory category,std::set<PropertyType> * types)1117 void ObjectDatabase::ParseProperties( ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category, std::set< PropertyType >* types )
1118 {
1119 	ticpp::Element* elem_category = elem_obj->FirstChildElement( CATEGORY_TAG, false );
1120 	while ( elem_category )
1121 	{
1122 		// Category name attribute
1123 		std::string cname;
1124 		elem_category->GetAttribute( NAME_TAG, &cname );
1125 		PPropertyCategory new_cat( new PropertyCategory( _WXSTR( cname ) ) );
1126 
1127 		// Add category
1128 		category->AddCategory( new_cat );
1129 
1130 		// Recurse
1131 		ParseProperties( elem_category, obj_info, new_cat, types );
1132 
1133 		elem_category = elem_category->NextSiblingElement( CATEGORY_TAG, false );
1134 	}
1135 
1136 	ticpp::Element* elem_prop = elem_obj->FirstChildElement( PROPERTY_TAG, false );
1137 	while ( elem_prop )
1138 	{
1139 		// Property Name Attribute
1140 		std::string pname;
1141 		elem_prop->GetAttribute( NAME_TAG, &pname );
1142 		category->AddProperty( _WXSTR(pname) );
1143 
1144 		std::string description;
1145 		elem_prop->GetAttributeOrDefault( DESCRIPTION_TAG, &description, "" );
1146 
1147 		std::string customEditor;
1148 		elem_prop->GetAttributeOrDefault( CUSTOM_EDITOR_TAG, &customEditor, "" );
1149 
1150 		std::string prop_type;
1151 		elem_prop->GetAttribute( "type", &prop_type );
1152 		PropertyType ptype;
1153 		try
1154 		{
1155 			ptype = ParsePropertyType( _WXSTR( prop_type ) );
1156 		}
1157 		catch( wxFBException& ex )
1158 		{
1159 			wxLogError( wxT("Error: %s\nWhile parsing property \"%s\" of class \"%s\""), ex.what(), _WXSTR(pname).c_str(), obj_info->GetClassName().c_str() );
1160 			elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
1161 			continue;
1162 		}
1163 
1164 		// Get default value
1165 		std::string def_value;
1166 		try
1167 		{
1168 			ticpp::Node* lastChild = elem_prop->LastChild();
1169 			ticpp::Text* text = lastChild->ToText();
1170 			def_value = text->Value();
1171 		}
1172 		catch( ticpp::Exception& ){}
1173 
1174 		// if the property is a "bitlist" then parse all of the options
1175 		POptionList opt_list;
1176 		std::list< PropertyChild > children;
1177 		if ( ptype == PT_BITLIST || ptype == PT_OPTION )
1178 		{
1179 			opt_list = POptionList( new OptionList() );
1180 			ticpp::Element* elem_opt = elem_prop->FirstChildElement( "option", false );
1181 			while( elem_opt )
1182 			{
1183 				std::string macro_name;
1184 				elem_opt->GetAttribute( NAME_TAG, &macro_name );
1185 
1186 				std::string macro_description;
1187 				elem_opt->GetAttributeOrDefault( DESCRIPTION_TAG, &macro_description, "" );
1188 
1189 				opt_list->AddOption( _WXSTR(macro_name), _WXSTR(macro_description) );
1190 
1191 				m_macroSet.insert( _WXSTR(macro_name) );
1192 
1193 				elem_opt = elem_opt->NextSiblingElement( "option", false );
1194 			}
1195 		}
1196 		else if ( ptype == PT_PARENT )
1197 		{
1198 			// If the property is a parent, then get the children
1199 			def_value.clear();
1200 			ticpp::Element* elem_child = elem_prop->FirstChildElement( "child", false );
1201 			while ( elem_child )
1202 			{
1203 				PropertyChild child;
1204 
1205 				std::string child_name;
1206 				elem_child->GetAttribute( NAME_TAG, &child_name );
1207 				child.m_name = _WXSTR( child_name );
1208 
1209 				std::string child_description;
1210 				elem_child->GetAttributeOrDefault( DESCRIPTION_TAG, &child_description, "" );
1211 				child.m_description = _WXSTR( child_description );
1212 
1213 				// Get default value
1214 				try
1215 				{
1216 					ticpp::Node* lastChild = elem_child->LastChild();
1217 					ticpp::Text* text = lastChild->ToText();
1218 					child.m_defaultValue = _WXSTR( text->Value() );
1219 
1220 					// build parent default value
1221 					if ( children.size() > 0 )
1222 					{
1223 						def_value += "; ";
1224 					}
1225 					def_value += text->Value();
1226 				}
1227 				catch( ticpp::Exception& ){}
1228 
1229 				children.push_back( child );
1230 
1231 				elem_child = elem_child->NextSiblingElement( "child", false );
1232 			}
1233 		}
1234 
1235 		// create an instance of PropertyInfo
1236 		PPropertyInfo prop_info( new PropertyInfo( _WXSTR(pname), ptype, _WXSTR(def_value), _WXSTR(description), _WXSTR(customEditor), opt_list, children ) );
1237 
1238 		// add the PropertyInfo to the property
1239 		obj_info->AddPropertyInfo( prop_info );
1240 
1241 		// merge property code templates, once per property type
1242 		if ( types->insert( ptype ).second )
1243 		{
1244 			LangTemplateMap& propLangTemplates = m_propertyTypeTemplates[ ptype ];
1245 			LangTemplateMap::iterator lang;
1246 			for ( lang = propLangTemplates.begin(); lang != propLangTemplates.end(); ++lang )
1247 			{
1248 				if ( lang->second )
1249 				{
1250 					obj_info->AddCodeInfo( lang->first, lang->second );
1251 				}
1252 			}
1253 		}
1254 
1255 		elem_prop = elem_prop->NextSiblingElement( PROPERTY_TAG, false );
1256 	}
1257 }
1258 
ParseEvents(ticpp::Element * elem_obj,PObjectInfo obj_info,PPropertyCategory category)1259 void ObjectDatabase::ParseEvents( ticpp::Element* elem_obj, PObjectInfo obj_info, PPropertyCategory category )
1260 {
1261 	ticpp::Element* elem_category = elem_obj->FirstChildElement( CATEGORY_TAG, false );
1262 	while ( elem_category )
1263 	{
1264 		// Category name attribute
1265 		std::string cname;
1266 		elem_category->GetAttribute( NAME_TAG, &cname );
1267 		PPropertyCategory new_cat( new PropertyCategory( _WXSTR( cname ) ) );
1268 
1269 		// Add category
1270 		category->AddCategory( new_cat );
1271 
1272 		// Recurse
1273 		ParseEvents( elem_category, obj_info, new_cat );
1274 
1275 		elem_category = elem_category->NextSiblingElement( CATEGORY_TAG, false );
1276 	}
1277 
1278 	ticpp::Element* elem_evt = elem_obj->FirstChildElement( EVENT_TAG, false );
1279 	while ( elem_evt )
1280 	{
1281 		// Event Name Attribute
1282 		std::string evt_name;
1283 		elem_evt->GetAttribute( NAME_TAG, &evt_name );
1284 		category->AddEvent( _WXSTR(evt_name) );
1285 
1286 		// Event class
1287 		std::string evt_class;
1288 		elem_evt->GetAttributeOrDefault( EVENT_CLASS_TAG, &evt_class, "wxEvent" );
1289 
1290 
1291 		// Help string
1292 		std::string description;
1293 		elem_evt->GetAttributeOrDefault( DESCRIPTION_TAG, &description, "" );
1294 
1295 		// Get default value
1296 		std::string def_value;
1297 		try
1298 		{
1299 			ticpp::Node* lastChild = elem_evt->LastChild();
1300 			ticpp::Text* text = lastChild->ToText();
1301 			def_value = text->Value();
1302 		}
1303 		catch( ticpp::Exception& ){}
1304 
1305 		// create an instance of EventInfo
1306 		PEventInfo evt_info(
1307 		  new EventInfo( _WXSTR(evt_name),  _WXSTR(evt_class), _WXSTR(def_value), _WXSTR(description)));
1308 
1309 		// add the EventInfo to the event
1310 		obj_info->AddEventInfo(evt_info);
1311 
1312 		elem_evt = elem_evt->NextSiblingElement( EVENT_TAG, false );
1313 	}
1314 }
1315 
ShowInPalette(wxString type)1316 bool ObjectDatabase::ShowInPalette(wxString type)
1317 {
1318 	return (type == wxT("form")					||
1319             type == wxT("wizard")               ||
1320             type == wxT("wizardpagesimple")     ||
1321 			type == wxT("menubar_form")			||
1322 			type == wxT("toolbar_form")			||
1323 			type == wxT("sizer")				||
1324 			type == wxT("gbsizer")				||
1325 			type == wxT("menu")					||
1326 			type == wxT("menuitem")				||
1327 			type == wxT("submenu")				||
1328 			type == wxT("tool")					||
1329 			type == wxT("ribbonbar")			||
1330 			type == wxT("ribbonpage")			||
1331 			type == wxT("ribbonpanel")      		||
1332 			type == wxT("ribbonbuttonbar")  		||
1333 			type == wxT("ribbonbutton")  			||
1334 			type == wxT("ribbondropdownbutton" )	||
1335 			type == wxT("ribbonhybridbutton" )  	||
1336 			type == wxT("ribbontogglebutton" )  	||
1337 			type == wxT("ribbontoolbar")	   		||
1338 			type == wxT("ribbontool")		   	||
1339 			type == wxT("ribbondropdowntool" )  	||
1340 			type == wxT("ribbonhybridtool" ) 		||
1341 			type == wxT("ribbontoggletool" )  		||
1342 			type == wxT("ribbongallery")  			||
1343 			type == wxT("ribbongalleryitem")		||
1344 			type == wxT("dataviewctrl")			||
1345 			type == wxT("dataviewtreectrl")		||
1346 			type == wxT("dataviewlistctrl")		||
1347 			type == wxT("dataviewlistcolumn")		||
1348 			type == wxT("notebook")				||
1349 			type == wxT("flatnotebook")			||
1350 			type == wxT("listbook")				||
1351 			type == wxT("choicebook")			||
1352 			type == wxT("auinotebook")			||
1353 			type == wxT("widget")				||
1354 			type == wxT("expanded_widget")		||
1355 			type == wxT("propgrid")		||
1356 			type == wxT("propgridman")		||
1357 			type == wxT("propgridpage")		||
1358 			type == wxT("propgriditem")		||
1359 			type == wxT("statusbar")			||
1360 			type == wxT("component")			||
1361 			type == wxT("container")			||
1362 			type == wxT("menubar")				||
1363 			type == wxT("treelistctrl")			||
1364 			type == wxT("treelistctrlcolumn")	||
1365 			type == wxT("toolbar")				||
1366 			type == wxT("nonvisual")			||
1367 			type == wxT("splitter")
1368 			);
1369 }
1370 
1371 
ImportComponentLibrary(wxString libfile,PwxFBManager manager)1372 void ObjectDatabase::ImportComponentLibrary( wxString libfile, PwxFBManager manager )
1373 {
1374 	wxString path = libfile;
1375 
1376 #if wxVERSION_NUMBER < 2900
1377 	// This will prevent loading debug libraries in release and vice versa
1378 	// That used to cause crashes when trying to debug
1379 	#ifdef __WXFB_DEBUG__
1380 //		path += wxT("d");
1381 	#endif
1382 #endif
1383 	// Find the GetComponentLibrary function - all plugins must implement this
1384 	typedef IComponentLibrary* (*PFGetComponentLibrary)( IManager* manager );
1385 
1386 	#ifdef __WXMAC__
1387 		path += wxT(".dylib");
1388 
1389 		// open the library
1390 		void* handle = dlopen( path.mb_str(), RTLD_LAZY );
1391 
1392 		if ( !handle )
1393 		{
1394 			wxString error = wxString( dlerror(), wxConvUTF8 );
1395 
1396 			THROW_WXFBEX( wxT("Error loading library ") << path << wxT(" ") << error )
1397 		}
1398 		dlerror(); // reset errors
1399 
1400 		// load the symbol
1401 
1402 		PFGetComponentLibrary GetComponentLibrary = (PFGetComponentLibrary) dlsym(handle, "GetComponentLibrary");
1403 		PFFreeComponentLibrary FreeComponentLibrary = (PFFreeComponentLibrary) dlsym(handle, "FreeComponentLibrary");
1404 
1405 		const char *dlsym_error = dlerror();
1406 		if (dlsym_error)
1407 		{
1408 			wxString error = wxString( dlsym_error, wxConvUTF8 );
1409 #if wxVERSION_NUMBER < 2900
1410 			THROW_WXFBEX( path << wxT(" is not a valid component library: ") << error )
1411 #else
1412             THROW_WXFBEX( path << " is not a valid component library: " << error )
1413 #endif
1414 			dlclose( handle );
1415 		}
1416 		else
1417 		{
1418 			m_libs.push_back( handle );
1419 		}
1420 	#else
1421 
1422 		// Attempt to load the DLL
1423 		wxDynamicLibrary* library = new wxDynamicLibrary( path );
1424 		if ( !library->IsLoaded() )
1425 		{
1426 			THROW_WXFBEX( wxT("Error loading library ") << path )
1427 		}
1428 
1429 		m_libs.push_back( library );
1430 
1431 		PFGetComponentLibrary GetComponentLibrary =	(PFGetComponentLibrary)library->GetSymbol( wxT("GetComponentLibrary") );
1432 		PFFreeComponentLibrary FreeComponentLibrary =	(PFFreeComponentLibrary)library->GetSymbol( wxT("FreeComponentLibrary") );
1433 
1434 		if ( !(GetComponentLibrary && FreeComponentLibrary) )
1435 		{
1436 #if wxVERSION_NUMBER < 2900
1437 			THROW_WXFBEX( path << wxT(" is not a valid component library") )
1438 #else
1439             THROW_WXFBEX( path << " is not a valid component library" )
1440 #endif
1441 		}
1442 
1443 #endif
1444 #if wxVERSION_NUMBER < 2900
1445 		LogDebug( wxT("[Database::ImportComponentLibrary] Importing %s library"), path.c_str() );
1446 #else
1447         LogDebug("[Database::ImportComponentLibrary] Importing " + path + " library");
1448 #endif
1449 	// Get the component library
1450 	IComponentLibrary* comp_lib = GetComponentLibrary( (IManager*)manager.get() );
1451 
1452 	// Store the function to free the library
1453 	m_componentLibs[ FreeComponentLibrary ] = comp_lib;
1454 
1455 	// Import all of the components
1456 	for ( unsigned int i = 0; i < comp_lib->GetComponentCount(); i++ )
1457 	{
1458 		wxString class_name = comp_lib->GetComponentName( i );
1459 		IComponent* comp = comp_lib->GetComponent( i );
1460 
1461 		// Look for the class in the data read from the .xml files
1462 		PObjectInfo class_info = GetObjectInfo( class_name );
1463 		if ( class_info )
1464 		{
1465 			class_info->SetComponent(comp);
1466 		}
1467 		else
1468 		{
1469 #if wxVERSION_NUMBER < 2900
1470 			LogDebug( wxT("ObjectInfo for <%s> not found while loading library <%s>"), class_name.c_str(), path.c_str() );
1471 #else
1472             LogDebug("ObjectInfo for <" + class_name + "> not found while loading library <" + path + ">");
1473 #endif
1474 		}
1475 	}
1476 
1477 	// Add all of the macros in the library to the macro dictionary
1478 	PMacroDictionary dic = MacroDictionary::GetInstance();
1479 	for ( unsigned int i = 0; i < comp_lib->GetMacroCount(); i++ )
1480 	{
1481 		wxString name = comp_lib->GetMacroName( i );
1482 		int value = comp_lib->GetMacroValue( i );
1483 		dic->AddMacro( name, value );
1484 		m_macroSet.erase( name );
1485 	}
1486 }
1487 
ParsePropertyType(wxString str)1488 PropertyType ObjectDatabase::ParsePropertyType( wxString str )
1489 {
1490 	PropertyType result;
1491 	PTMap::iterator it = m_propTypes.find(str);
1492 	if (it != m_propTypes.end())
1493 		result = it->second;
1494 	else
1495 	{
1496 		result = PT_ERROR;
1497 		THROW_WXFBEX( wxString::Format( wxT("Unknown property type \"%s\""), str.c_str() ) );
1498 	}
1499 
1500 	return result;
1501 }
1502 
ParseObjectType(wxString str)1503 wxString  ObjectDatabase::ParseObjectType( wxString str )
1504 {
1505 	return str;
1506 }
1507 
1508 
1509 #define PT(x,y) m_propTypes.insert(PTMap::value_type(x,y))
InitPropertyTypes()1510 void ObjectDatabase::InitPropertyTypes()
1511 {
1512 	PT( wxT("bool"),			PT_BOOL		);
1513 	PT( wxT("text"),			PT_TEXT		);
1514 	PT( wxT("int"),				PT_INT		);
1515 	PT( wxT("uint"),			PT_UINT		);
1516 	PT( wxT("bitlist"),		PT_BITLIST		);
1517 	PT( wxT("intlist"),		PT_INTLIST		);
1518 	PT( wxT("uintlist"),	PT_UINTLIST		);
1519 	PT( wxT("option"),		PT_OPTION		);
1520 	PT( wxT("macro"),		PT_MACRO		);
1521 	PT( wxT("path"),		PT_PATH			);
1522 	PT( wxT("file"),		PT_FILE			);
1523 	PT( wxT("wxString"), 	PT_WXSTRING		);
1524 	PT( wxT("wxPoint"),		PT_WXPOINT		);
1525 	PT( wxT("wxSize"),		PT_WXSIZE		);
1526 	PT( wxT("wxFont"),		PT_WXFONT		);
1527 	PT( wxT("wxColour"),	PT_WXCOLOUR		);
1528 	PT( wxT("bitmap"),		PT_BITMAP		);
1529 	PT( wxT("wxString_i18n"),PT_WXSTRING_I18N);
1530 	PT( wxT("stringlist"),	PT_STRINGLIST	);
1531 	PT( wxT("float"),		PT_FLOAT		);
1532 	PT( wxT("parent"),		PT_PARENT		);
1533 }
1534 
LoadObjectTypes()1535 bool ObjectDatabase::LoadObjectTypes()
1536 {
1537 	ticpp::Document doc;
1538 	wxString xmlPath = m_xmlPath + wxT("objtypes.xml");
1539 	XMLUtils::LoadXMLFile( doc, true, xmlPath );
1540 
1541 	// First load the object types, then the children
1542 	try
1543 	{
1544 		ticpp::Element* root = doc.FirstChildElement("definitions");
1545 		ticpp::Element* elem = root->FirstChildElement( "objtype" );
1546 		while ( elem )
1547 		{
1548 			bool hidden;
1549 			elem->GetAttributeOrDefault( "hidden", &hidden, false );
1550 
1551 			bool item;
1552 			elem->GetAttributeOrDefault( "item", &item, false );
1553 
1554 			wxString name = _WXSTR( elem->GetAttribute("name") );
1555 
1556 			PObjectType objType( new ObjectType( name, (int)m_types.size(), hidden, item ) );
1557 			m_types.insert( ObjectTypeMap::value_type( name, objType ) );
1558 
1559 			elem = elem->NextSiblingElement( "objtype", false );
1560 		}
1561 
1562 		// now load the children
1563 		elem = root->FirstChildElement("objtype");
1564 		while (elem)
1565 		{
1566 			wxString name = _WXSTR( elem->GetAttribute("name") );
1567 
1568 			// get the objType
1569 			PObjectType objType = GetObjectType( name );
1570 			ticpp::Element* child = elem->FirstChildElement( "childtype", false );
1571 			while ( child )
1572 			{
1573 				int nmax = -1; // no limit
1574 				int aui_nmax = -1; // no limit
1575 				child->GetAttributeOrDefault( "nmax", &nmax, -1 );
1576 				child->GetAttributeOrDefault( "aui_nmax", &aui_nmax, -1 );
1577 
1578 				wxString childname = _WXSTR( child->GetAttribute("name") );
1579 
1580 				PObjectType childType = GetObjectType( childname );
1581 				if ( !childType )
1582 				{
1583 					wxLogError( _("No Object Type found for \"%s\""), childname.c_str() );
1584 					continue;
1585 				}
1586 
1587 				objType->AddChildType( childType, nmax, aui_nmax );
1588 
1589 				child = child->NextSiblingElement( "childtype", false );
1590 			}
1591 			elem = elem->NextSiblingElement( "objtype", false );
1592 		}
1593 	}
1594 	catch( ticpp::Exception& ex )
1595 	{
1596 		wxLogError( _WXSTR( ex.m_details ) );
1597 		return false;
1598 	}
1599 
1600 	return true;
1601 }
1602 
GetObjectType(wxString name)1603 PObjectType ObjectDatabase::GetObjectType(wxString name)
1604 {
1605 	PObjectType type;
1606 	ObjectTypeMap::iterator it = m_types.find(name);
1607 	if (it != m_types.end())
1608 		type = it->second;
1609 
1610 	return type;
1611 }
1612