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, ¯o_name );
1185
1186 std::string macro_description;
1187 elem_opt->GetAttributeOrDefault( DESCRIPTION_TAG, ¯o_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