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 "appdata.h"
27 #include "bitmaps.h"
28 #include "wxfbevent.h"
29 #include "wxfbmanager.h"
30 
31 #include "model/objectbase.h"
32 #include "utils/typeconv.h"
33 #include "utils/debug.h"
34 #include "utils/stringutils.h"
35 #include "utils/wxfbipc.h"
36 #include "utils/wxfbexception.h"
37 #include "codegen/cppcg.h"
38 #include "codegen/pythoncg.h"
39 #include "codegen/phpcg.h"
40 #include "codegen/luacg.h"
41 #include "codegen/xrccg.h"
42 #include "codegen/codewriter.h"
43 #include "rad/xrcpreview/xrcpreview.h"
44 #include "rad/dataobject/dataobject.h"
45 
46 #include <ticpp.h>
47 #include <set>
48 #include <iterator>
49 #include <sstream>
50 #include <algorithm>
51 
52 #include <wx/tokenzr.h>
53 #include <wx/ffile.h>
54 #include <wx/filename.h>
55 #include <wx/clipbrd.h>
56 #include <wx/fs_mem.h>
57 #include <wx/fs_arc.h>
58 #include <wx/fs_filter.h>
59 
60 using namespace TypeConv;
61 
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 // Comandos
65 ///////////////////////////////////////////////////////////////////////////////
66 
67 /** Command for expanding an object in the object tree */
68 
69 class ExpandObjectCmd : public Command
70 {
71 
72 	private:
73 		PObjectBase m_object;
74 		bool m_expand;
75 
76 	protected:
77 		void DoExecute();
78 		void DoRestore();
79 
80 	public:
81 		ExpandObjectCmd( PObjectBase object, bool expand );
82 };
83 
84 /**
85 * Comando para insertar un objeto en el árbol.
86 */
87 
88 class InsertObjectCmd : public Command
89 {
90 
91 	private:
92 		ApplicationData *m_data;
93 		PObjectBase m_parent;
94 		PObjectBase m_object;
95 		int m_pos;
96 		PObjectBase m_oldSelected;
97 
98 
99 	protected:
100 		void DoExecute();
101 		void DoRestore();
102 
103 	public:
104 		InsertObjectCmd( ApplicationData *data, PObjectBase object, PObjectBase parent, int pos = -1 );
105 };
106 
107 /**
108 * Comando para borrar un objeto.
109 */
110 
111 class RemoveObjectCmd : public Command
112 {
113 
114 	private:
115 		ApplicationData *m_data;
116 		PObjectBase m_parent;
117 		PObjectBase m_object;
118 		int m_oldPos;
119 		PObjectBase m_oldSelected;
120 
121 	protected:
122 		void DoExecute();
123 		void DoRestore();
124 
125 	public:
126 		RemoveObjectCmd( ApplicationData *data, PObjectBase object );
127 };
128 
129 /**
130 * Comando para modificar una propiedad.
131 */
132 
133 class ModifyPropertyCmd : public Command
134 {
135 
136 	private:
137 		PProperty m_property;
138 		wxString m_oldValue, m_newValue;
139 
140 	protected:
141 		void DoExecute();
142 		void DoRestore();
143 
144 	public:
145 		ModifyPropertyCmd( PProperty prop, wxString value );
146 };
147 
148 /**
149 * Command for modifying an event
150 */
151 
152 class ModifyEventHandlerCmd : public Command
153 {
154 
155 	private:
156 		PEvent m_event;
157 		wxString m_oldValue, m_newValue;
158 
159 	protected:
160 		void DoExecute();
161 		void DoRestore();
162 
163 	public:
164 		ModifyEventHandlerCmd( PEvent event, wxString value );
165 };
166 
167 /**
168 * Comando para mover de posición un objeto.
169 */
170 
171 class ShiftChildCmd : public Command
172 {
173 
174 	private:
175 		PObjectBase m_object;
176 		int m_oldPos, m_newPos;
177 
178 	protected:
179 		void DoExecute();
180 		void DoRestore();
181 
182 	public:
183 		ShiftChildCmd( PObjectBase object, int pos );
184 
185 };
186 
187 /**
188 * CutObjectCmd ademas de eliminar el objeto del árbol se asegura
189 * de eliminar la referencia "clipboard" deshacer el cambio.
190 */
191 
192 class CutObjectCmd : public Command
193 {
194 
195 	private:
196 		// necesario para consultar/modificar el objeto "clipboard"
197 		ApplicationData *m_data;
198 		//PObjectBase m_clipboard;
199 		PObjectBase m_parent;
200 		PObjectBase m_object;
201 		int m_oldPos;
202 		PObjectBase m_oldSelected;
203 
204 	protected:
205 		void DoExecute();
206 		void DoRestore();
207 
208 	public:
209 		CutObjectCmd( ApplicationData *data, PObjectBase object );
210 };
211 
212 /**
213 * Cambia el padre.
214 */
215 
216 class ReparentObjectCmd : public Command
217 {
218 
219 	private:
220 		PObjectBase m_sizeritem;
221 		PObjectBase m_sizer;
222 		PObjectBase m_oldSizer;
223 		int m_oldPosition;
224 
225 	protected:
226 		void DoExecute();
227 		void DoRestore();
228 
229 	public:
230 		ReparentObjectCmd ( PObjectBase sizeritem, PObjectBase sizer );
231 };
232 
233 ///////////////////////////////////////////////////////////////////////////////
234 // Implementación de los Comandos
235 ///////////////////////////////////////////////////////////////////////////////
ExpandObjectCmd(PObjectBase object,bool expand)236 ExpandObjectCmd::ExpandObjectCmd( PObjectBase object, bool expand )
237 		: m_object( object ), m_expand( expand )
238 {
239 }
240 
DoExecute()241 void ExpandObjectCmd::DoExecute()
242 {
243 	m_object->SetExpanded( m_expand );
244 }
245 
DoRestore()246 void ExpandObjectCmd::DoRestore()
247 {
248 	m_object->SetExpanded( !m_expand );
249 }
250 
InsertObjectCmd(ApplicationData * data,PObjectBase object,PObjectBase parent,int pos)251 InsertObjectCmd::InsertObjectCmd( ApplicationData *data, PObjectBase object,
252                                   PObjectBase parent, int pos )
253 		: m_data( data ), m_parent( parent ), m_object( object ), m_pos( pos )
254 {
255 	m_oldSelected = data->GetSelectedObject();
256 }
257 
DoExecute()258 void InsertObjectCmd::DoExecute()
259 {
260 	m_parent->AddChild( m_object );
261 	m_object->SetParent( m_parent );
262 
263 	if ( m_pos >= 0 )
264 		m_parent->ChangeChildPosition( m_object, m_pos );
265 
266 	PObjectBase obj = m_object;
267 	while ( obj && obj->GetObjectInfo()->GetObjectType()->IsItem() )
268 	{
269 		if ( obj->GetChildCount() > 0 )
270 			obj = obj->GetChild( 0 );
271 		else
272 			return;
273 	}
274 	m_data->SelectObject( obj, false, false );
275 }
276 
DoRestore()277 void InsertObjectCmd::DoRestore()
278 {
279 	m_parent->RemoveChild( m_object );
280 	m_object->SetParent( PObjectBase() );
281 	m_data->SelectObject( m_oldSelected );
282 }
283 
284 //-----------------------------------------------------------------------------
285 
RemoveObjectCmd(ApplicationData * data,PObjectBase object)286 RemoveObjectCmd::RemoveObjectCmd( ApplicationData *data, PObjectBase object )
287 {
288 	m_data = data;
289 	m_object = object;
290 	m_parent = object->GetParent();
291 	m_oldPos = m_parent->GetChildPosition( object );
292 	m_oldSelected = data->GetSelectedObject();
293 }
294 
DoExecute()295 void RemoveObjectCmd::DoExecute()
296 {
297 	m_parent->RemoveChild( m_object );
298 	m_object->SetParent( PObjectBase() );
299 	m_data->DetermineObjectToSelect( m_parent, m_oldPos );
300 }
301 
DoRestore()302 void RemoveObjectCmd::DoRestore()
303 {
304 	m_parent->AddChild( m_object );
305 	m_object->SetParent( m_parent );
306 
307 	// restauramos la posición
308 	m_parent->ChangeChildPosition( m_object, m_oldPos );
309 	m_data->SelectObject( m_oldSelected, true, false );
310 }
311 
312 //-----------------------------------------------------------------------------
313 
ModifyPropertyCmd(PProperty prop,wxString value)314 ModifyPropertyCmd::ModifyPropertyCmd( PProperty prop, wxString value )
315 		: m_property( prop ), m_newValue( value )
316 {
317 	m_oldValue = prop->GetValue();
318 }
319 
DoExecute()320 void ModifyPropertyCmd::DoExecute()
321 {
322 	m_property->SetValue( m_newValue );
323 }
324 
DoRestore()325 void ModifyPropertyCmd::DoRestore()
326 {
327 	m_property->SetValue( m_oldValue );
328 }
329 
330 //-----------------------------------------------------------------------------
331 
ModifyEventHandlerCmd(PEvent event,wxString value)332 ModifyEventHandlerCmd::ModifyEventHandlerCmd( PEvent event, wxString value )
333 		: m_event( event ), m_newValue( value )
334 {
335 	m_oldValue = event->GetValue();
336 }
337 
DoExecute()338 void ModifyEventHandlerCmd::DoExecute()
339 {
340 	m_event->SetValue( m_newValue );
341 }
342 
DoRestore()343 void ModifyEventHandlerCmd::DoRestore()
344 {
345 	m_event->SetValue( m_oldValue );
346 }
347 
348 //-----------------------------------------------------------------------------
349 
ShiftChildCmd(PObjectBase object,int pos)350 ShiftChildCmd::ShiftChildCmd( PObjectBase object, int pos )
351 {
352 	m_object = object;
353 	PObjectBase parent = object->GetParent();
354 
355 	assert( parent );
356 
357 	m_oldPos = parent->GetChildPosition( object );
358 	m_newPos = pos;
359 }
360 
DoExecute()361 void ShiftChildCmd::DoExecute()
362 {
363 	if ( m_oldPos != m_newPos )
364 	{
365 		PObjectBase parent ( m_object->GetParent() );
366 		parent->ChangeChildPosition( m_object, m_newPos );
367 	}
368 }
369 
DoRestore()370 void ShiftChildCmd::DoRestore()
371 {
372 	if ( m_oldPos != m_newPos )
373 	{
374 		PObjectBase parent ( m_object->GetParent() );
375 		parent->ChangeChildPosition( m_object, m_oldPos );
376 	}
377 }
378 
379 //-----------------------------------------------------------------------------
380 
CutObjectCmd(ApplicationData * data,PObjectBase object)381 CutObjectCmd::CutObjectCmd( ApplicationData *data, PObjectBase object )
382 {
383 	m_data = data;
384 	m_object = object;
385 	m_parent = object->GetParent();
386 	m_oldPos = m_parent->GetChildPosition( object );
387 	m_oldSelected = data->GetSelectedObject();
388 }
389 
DoExecute()390 void CutObjectCmd::DoExecute()
391 {
392 	// guardamos el clipboard ???
393 	//m_clipboard = m_data->GetClipboardObject();
394 
395 	m_data->SetClipboardObject( m_object );
396 	m_parent->RemoveChild( m_object );
397 	m_object->SetParent( PObjectBase() );
398 	m_data->DetermineObjectToSelect( m_parent, m_oldPos );
399 }
400 
DoRestore()401 void CutObjectCmd::DoRestore()
402 {
403 	// reubicamos el objeto donde estaba
404 	m_parent->AddChild( m_object );
405 	m_object->SetParent( m_parent );
406 	m_parent->ChangeChildPosition( m_object, m_oldPos );
407 
408 
409 
410 	// restauramos el clipboard
411 	//m_data->SetClipboardObject(m_clipboard);
412 	m_data->SetClipboardObject( PObjectBase() );
413 	m_data->SelectObject( m_oldSelected, true, false );
414 }
415 
416 //-----------------------------------------------------------------------------
417 
ReparentObjectCmd(PObjectBase sizeritem,PObjectBase sizer)418 ReparentObjectCmd ::ReparentObjectCmd ( PObjectBase sizeritem, PObjectBase sizer )
419 {
420 	m_sizeritem = sizeritem;
421 	m_sizer = sizer;
422 	m_oldSizer = m_sizeritem->GetParent();
423 	m_oldPosition = m_oldSizer->GetChildPosition(sizeritem);
424 }
425 
DoExecute()426 void ReparentObjectCmd::DoExecute()
427 {
428 	m_oldSizer->RemoveChild( m_sizeritem );
429 	m_sizeritem->SetParent( m_sizer );
430 	m_sizer->AddChild( m_sizeritem );
431 }
432 
DoRestore()433 void ReparentObjectCmd::DoRestore()
434 {
435 	m_sizer->RemoveChild( m_sizeritem );
436 	m_sizeritem->SetParent( m_oldSizer );
437 	m_oldSizer->AddChild( m_sizeritem );
438 	m_oldSizer->ChangeChildPosition( m_sizeritem, m_oldPosition);
439 }
440 
441 ///////////////////////////////////////////////////////////////////////////////
442 // ApplicationData
443 ///////////////////////////////////////////////////////////////////////////////
444 
445 ApplicationData* ApplicationData::s_instance = NULL;
446 
Get(const wxString & rootdir)447 ApplicationData* ApplicationData::Get( const wxString &rootdir )
448 {
449 	if ( !s_instance )
450 		s_instance = new ApplicationData( rootdir );
451 
452 	return s_instance;
453 }
454 
Destroy()455 void ApplicationData::Destroy()
456 
457 {
458 	if ( s_instance )
459 		delete s_instance;
460 
461 	s_instance = NULL;
462 }
463 
Initialize()464 void ApplicationData::Initialize()
465 {
466 	ApplicationData* appData = ApplicationData::Get();
467 	appData->LoadApp();
468 }
469 
ApplicationData(const wxString & rootdir)470 ApplicationData::ApplicationData( const wxString &rootdir )
471 		:
472 		m_rootDir( rootdir ),
473 		m_modFlag( false ),
474 		m_warnOnAdditionsUpdate( true ),
475 		m_objDb( new ObjectDatabase() ),
476 		m_manager( new wxFBManager ),
477 		m_ipc( new wxFBIPC ),
478 		m_fbpVerMajor( 1 ),
479 		m_fbpVerMinor( 13 )
480 {
481 	#ifdef __WXFB_DEBUG__
482 	//wxLog* log = wxLog::SetActiveTarget( NULL );
483 	m_debugLogTarget = new wxLogWindow( NULL, wxT( "Logging" ) );
484 	//wxLog::SetActiveTarget( log );
485 	#endif
486 	m_objDb->SetXmlPath( m_rootDir + wxFILE_SEP_PATH + wxT( "xml" ) + wxFILE_SEP_PATH ) ;
487 	m_objDb->SetIconPath( m_rootDir + wxFILE_SEP_PATH + wxT( "resources" ) + wxFILE_SEP_PATH + wxT( "icons" ) + wxFILE_SEP_PATH );
488 	m_objDb->SetPluginPath( m_rootDir + wxFILE_SEP_PATH + wxT( "plugins" ) + wxFILE_SEP_PATH ) ;
489 
490 	// Support loading files from memory
491 	// Used to load the XRC preview, but could be useful elsewhere
492 	wxFileSystem::AddHandler( new wxMemoryFSHandler );
493 
494 	// Support for loading files from archives
495 	wxFileSystem::AddHandler( new wxArchiveFSHandler );
496 	wxFileSystem::AddHandler( new wxFilterFSHandler );
497 }
498 
~ApplicationData()499 ApplicationData::~ApplicationData()
500 {
501 	#ifdef __WXFB_DEBUG__
502         delete m_debugLogTarget;
503         m_debugLogTarget = 0;
504 	#endif
505 }
506 
LoadApp()507 void ApplicationData::LoadApp()
508 
509 {
510 	wxString bitmapPath = m_objDb->GetXmlPath() + wxT( "icons.xml" );
511 	AppBitmaps::LoadBitmaps( bitmapPath, m_objDb->GetIconPath() );
512 	m_objDb->LoadObjectTypes();
513 	m_objDb->LoadPlugins( m_manager );
514 }
515 
GetManager()516 PwxFBManager ApplicationData::GetManager()
517 {
518 	return m_manager;
519 }
520 
GetSelectedObject()521 PObjectBase ApplicationData::GetSelectedObject()
522 {
523 	return m_selObj;
524 }
525 
GetSelectedForm()526 PObjectBase ApplicationData::GetSelectedForm()
527 {
528 	if( ( m_selObj->GetObjectTypeName() == wxT( "form" ) ) ||
529         ( m_selObj->GetObjectTypeName() == wxT("wizard") ) ||
530 		( m_selObj->GetObjectTypeName() == wxT( "menubar_form" ) ) ||
531 		( m_selObj->GetObjectTypeName() == wxT( "toolbar_form" ) ) )
532 		return m_selObj;
533 	else
534 		return m_selObj->FindParentForm();
535 }
536 
537 
GetProjectData()538 PObjectBase ApplicationData::GetProjectData()
539 {
540 	return m_project;
541 }
542 
BuildNameSet(PObjectBase obj,PObjectBase top,std::set<wxString> & name_set)543 void ApplicationData::BuildNameSet( PObjectBase obj, PObjectBase top, std::set< wxString >& name_set )
544 {
545 	if ( obj != top )
546 	{
547 		PProperty nameProp = top->GetProperty( wxT( "name" ) );
548 
549 		if ( nameProp )
550 			name_set.insert( nameProp->GetValue() );
551 	}
552 
553 	for ( unsigned int i = 0; i < top->GetChildCount(); i++ )
554 		BuildNameSet( obj, top->GetChild( i ), name_set );
555 }
556 
ResolveNameConflict(PObjectBase obj)557 void ApplicationData::ResolveNameConflict( PObjectBase obj )
558 {
559 	while ( obj && obj->GetObjectInfo()->GetObjectType()->IsItem() )
560 	{
561 		if ( obj->GetChildCount() > 0 )
562 			obj = obj->GetChild( 0 );
563 		else
564 			return;
565 	}
566 
567 	PProperty nameProp = obj->GetProperty( wxT( "name" ) );
568 
569 	if ( !nameProp )
570 		return;
571 
572 	// Save the original name for use later.
573 	wxString originalName = nameProp->GetValue();
574 
575 	// el nombre no puede estar repetido dentro del mismo form
576 	/*PObjectBase top = obj->FindNearAncestor( wxT( "form" ) );*/
577 	PObjectBase top = obj->FindParentForm();
578 
579 	if ( !top )
580 		top = m_project; // el objeto es un form.
581 
582 	// construimos el conjunto de nombres
583 	std::set<wxString> name_set;
584 
585 	BuildNameSet( obj, top, name_set );
586 
587 	// comprobamos si hay conflicto
588 	std::set<wxString>::iterator it = name_set.find( originalName );
589 
590 	int i = 0;
591 
592 	wxString name = originalName; // The name that gets incremented.
593 
594 	while ( it != name_set.end() )
595 	{
596 		i++;
597 		name = wxString::Format( wxT( "%s%i" ), originalName.c_str(), i );
598 		it = name_set.find( name );
599 	}
600 
601 	nameProp->SetValue( name );
602 }
603 
ResolveSubtreeNameConflicts(PObjectBase obj,PObjectBase topObj)604 void ApplicationData::ResolveSubtreeNameConflicts( PObjectBase obj, PObjectBase topObj )
605 {
606 	if ( !topObj )
607 	{
608 		/*topObj = obj->FindNearAncestor( wxT( "form" ) );*/
609 		topObj = obj->FindParentForm();
610 
611 		if ( !topObj )
612 			topObj = m_project; // object is the project
613 	}
614 
615 	// Ignore item objects
616 	while ( obj && obj->GetObjectInfo()->GetObjectType()->IsItem() )
617 	{
618 		if ( obj->GetChildCount() > 0 )
619 			obj = obj->GetChild( 0 );
620 		else
621 			return; // error
622 	}
623 
624 	// Resolve a possible name conflict
625 	ResolveNameConflict( obj );
626 
627 	// Recurse through all children
628 	for ( unsigned int i = 0 ; i < obj->GetChildCount() ; i++ )
629 		ResolveSubtreeNameConflicts( obj->GetChild( i ), topObj );
630 }
631 
CalcPositionOfInsertion(PObjectBase selected,PObjectBase parent)632 int ApplicationData::CalcPositionOfInsertion( PObjectBase selected, PObjectBase parent )
633 {
634 	int pos = -1;
635 
636 	if ( parent && selected )
637 	{
638 		PObjectBase parentSelected = selected->GetParent();
639 
640 		while ( parentSelected && parentSelected != parent )
641 		{
642 			selected = parentSelected;
643 			parentSelected = selected->GetParent();
644 		}
645 
646 		if ( parentSelected && parentSelected == parent )
647 			pos = parent->GetChildPosition( selected ) + 1;
648 	}
649 
650 	return pos;
651 }
652 
RemoveEmptyItems(PObjectBase obj)653 void ApplicationData::RemoveEmptyItems( PObjectBase obj )
654 {
655 	if ( !obj->GetObjectInfo()->GetObjectType()->IsItem() )
656 	{
657 		bool emptyItem = true;
658 
659 		// esto es un algoritmo ineficiente pero "seguro" con los índices
660 
661 		while ( emptyItem )
662 		{
663 			emptyItem = false;
664 
665 			for ( unsigned int i = 0; !emptyItem && i < obj->GetChildCount(); i++ )
666 			{
667 				PObjectBase child = obj->GetChild( i );
668 
669 				if ( child->GetObjectInfo()->GetObjectType()->IsItem() &&
670 				        child->GetChildCount() == 0 )
671 				{
672 					obj->RemoveChild( child ); // borramos el item
673 					child->SetParent( PObjectBase() );
674 
675 					emptyItem = true;        // volvemos a recorrer
676 					wxString msg;
677 					msg.Printf( wxT( "Empty item removed under %s" ), obj->GetPropertyAsString( wxT( "name" ) ).c_str() );
678 					wxLogWarning( msg );
679 				}
680 			}
681 		}
682 	}
683 
684 	for ( unsigned int i = 0; i < obj->GetChildCount() ; i++ )
685 		RemoveEmptyItems( obj->GetChild( i ) );
686 }
687 
SearchSizerInto(PObjectBase obj)688 PObjectBase ApplicationData::SearchSizerInto( PObjectBase obj )
689 {
690 	PObjectBase theSizer;
691 
692 	if ( obj->GetObjectInfo()->IsSubclassOf( wxT("sizer") ) || obj->GetObjectInfo()->IsSubclassOf( wxT("gbsizer") ) )
693 		theSizer = obj;
694 	else
695 	{
696 		for ( unsigned int i = 0; !theSizer && i < obj->GetChildCount(); i++ )
697 			theSizer = SearchSizerInto( obj->GetChild( i ) );
698 	}
699 
700 	return theSizer;
701 }
702 
703 ///////////////////////////////////////////////////////////////////////////////
704 
ExpandObject(PObjectBase obj,bool expand)705 void ApplicationData::ExpandObject( PObjectBase obj, bool expand )
706 {
707 	PCommand command( new ExpandObjectCmd( obj, expand ) );
708 	Execute( command );
709 
710 	// collapse also all children ...
711 	PropagateExpansion( obj, expand, !expand );
712 
713 	NotifyObjectExpanded( obj );
714 }
715 
PropagateExpansion(PObjectBase obj,bool expand,bool up)716 void ApplicationData::PropagateExpansion( PObjectBase obj, bool expand, bool up )
717 {
718 	if( obj )
719 	{
720 		if( up )
721 		{
722 			PObjectBase child;
723 
724 			for( size_t i = 0; i < obj->GetChildCount(); i++ )
725 			{
726 				child = obj->GetChild(i);
727 
728 				PCommand command( new ExpandObjectCmd( child, expand ) );
729 				Execute( command );
730 
731 				PropagateExpansion( child, expand, up );
732 			}
733 		}
734 		else
735 		{
736 			PropagateExpansion( obj->GetParent(), expand, up );
737 
738 			PCommand command( new ExpandObjectCmd( obj, expand ) );
739 			Execute( command );
740 		}
741 	}
742 }
743 
SelectObject(PObjectBase obj,bool force,bool notify)744 bool ApplicationData::SelectObject( PObjectBase obj, bool force /*= false*/, bool notify /*= true */ )
745 {
746 	if ( ( obj == m_selObj ) && !force )
747 	{
748 		return false;
749 	}
750 
751 	m_selObj = obj;
752 
753 	if ( notify )
754 	{
755 		NotifyObjectSelected( obj, force );
756 	}
757 	return true;
758 }
759 
CreateObject(wxString name)760 void ApplicationData::CreateObject( wxString name )
761 {
762 	try
763 	{
764 #if wxVERSION_NUMBER < 2900
765 		LogDebug( wxT( "[ApplicationData::CreateObject] New %s" ), name.c_str() );
766 #else
767         LogDebug("[ApplicationData::CreateObject] New " + name );
768 #endif
769 		PObjectBase old_selected = GetSelectedObject();
770 		PObjectBase parent = old_selected;
771 		PObjectBase obj;
772 
773 		if ( parent )
774 		{
775 			bool created = false;
776 
777 			// Para que sea más práctico, si el objeto no se puede crear debajo
778 			// del objeto seleccionado vamos a intentarlo en el padre del seleccionado
779 			// y seguiremos subiendo hasta que ya no podamos crear el objeto.
780 
781 			while ( parent && !created )
782 			{
783 				// además, el objeto se insertará a continuación del objeto seleccionado
784 				obj = m_objDb->CreateObject( _STDSTR( name ), parent );
785 
786 				if ( obj )
787 				{
788 					int pos = CalcPositionOfInsertion( GetSelectedObject(), parent );
789 
790 					PCommand command( new InsertObjectCmd( this, obj, parent, pos ) );
791 					Execute( command ); //m_cmdProc.Execute(command);
792 					created = true;
793 					ResolveNameConflict( obj );
794 				}
795 				else
796 				{
797 					// lo vamos a seguir intentando con el padre, pero cuidado, el padre
798 					// no puede ser un item!
799 					parent = parent->GetParent();
800 
801 					while ( parent && parent->GetObjectInfo()->GetObjectType()->IsItem() )
802 						parent = parent->GetParent();
803 				}
804 			}
805 		}
806 
807 		// Seleccionamos el objeto, si este es un item entonces se selecciona
808 		// el objeto contenido. ¿Tiene sentido tener un item debajo de un item?
809 
810 		while ( obj && obj->GetObjectInfo()->GetObjectType()->IsItem() )
811 			obj = ( obj->GetChildCount() > 0 ? obj->GetChild( 0 ) : PObjectBase() );
812 
813 		NotifyObjectCreated( obj );
814 
815 		if ( obj )
816 		{
817 			SelectObject( obj, true, true );
818 		}
819 		else
820 		{
821 			SelectObject( old_selected, true, true );
822 		}
823 	}
824 	catch ( wxFBException& ex )
825 	{
826 		wxLogError( ex.what() );
827 	}
828 }
829 
RemoveObject(PObjectBase obj)830 void ApplicationData::RemoveObject( PObjectBase obj )
831 {
832 	DoRemoveObject( obj, false );
833 }
834 
CutObject(PObjectBase obj)835 void ApplicationData::CutObject( PObjectBase obj )
836 {
837 	DoRemoveObject( obj, true );
838 }
839 
DoRemoveObject(PObjectBase obj,bool cutObject)840 void ApplicationData::DoRemoveObject( PObjectBase obj, bool cutObject )
841 {
842 	// Note:
843 	//  When removing an object it is important that the "item" objects
844 	// are not left behind
845 	PObjectBase parent = obj->GetParent();
846 	PObjectBase deleted_obj = obj;
847 
848 	if ( parent )
849 	{
850 		// Get the top item
851 		while ( parent && parent->GetObjectInfo()->GetObjectType()->IsItem() )
852 		{
853 			obj = parent;
854 			parent = obj->GetParent();
855 		}
856 
857 		if ( cutObject )
858 		{
859 			m_copyOnPaste = false;
860 			PCommand command( new CutObjectCmd( this, obj ) );
861 			Execute( command );
862 		}
863 		else
864 		{
865 			PCommand command( new RemoveObjectCmd( this, obj ) );
866 			Execute( command );
867 		}
868 
869 		NotifyObjectRemoved( deleted_obj );
870 		SelectObject( GetSelectedObject(), true, true );
871 	}
872 	else
873 	{
874 		if ( obj->GetObjectTypeName() != wxT( "project" ) )
875 			assert( false );
876 	}
877 
878 	CheckProjectTree( m_project );
879 }
880 
DetermineObjectToSelect(PObjectBase parent,unsigned int pos)881 void ApplicationData::DetermineObjectToSelect( PObjectBase parent, unsigned int pos )
882 {
883 	// get position of next control or last control
884 	PObjectBase objToSelect;
885 	unsigned int count = parent->GetChildCount();
886 	if ( 0 == count )
887 	{
888 		objToSelect = parent;
889 	}
890 	else
891 	{
892 		pos = ( pos < count ? pos : count - 1 );
893 		objToSelect = parent->GetChild( pos );
894 	}
895 
896 	while ( objToSelect && objToSelect->GetObjectInfo()->GetObjectType()->IsItem() )
897 	{
898 		objToSelect = objToSelect->GetChild( 0 );
899 	}
900 
901 	SelectObject( objToSelect );
902 }
903 
CopyObjectToClipboard(PObjectBase obj)904 void ApplicationData::CopyObjectToClipboard( PObjectBase obj )
905 {
906 	// Write some text to the clipboard
907 
908 	// Do not call Open() when the clipboard is opened
909 	if( !wxTheClipboard->IsOpened() )
910 	{
911         if ( !wxTheClipboard->Open() )
912         {
913             return;
914         }
915 	}
916 
917     // This data objects are held by the clipboard,
918     // so do not delete them in the app.
919     wxTheClipboard->SetData( new wxFBDataObject( obj ) );
920     wxTheClipboard->Close();
921 }
922 
PasteObjectFromClipboard(PObjectBase parent)923 bool ApplicationData::PasteObjectFromClipboard( PObjectBase parent )
924 {
925 	// Do not call Open() when the clipboard is opened
926 	if( !wxTheClipboard->IsOpened() )
927 	{
928         if ( !wxTheClipboard->Open() )
929         {
930             return false;
931         }
932 	}
933 
934     if ( wxTheClipboard->IsSupported( wxFBDataObjectFormat ) )
935     {
936         wxFBDataObject data;
937         if ( wxTheClipboard->GetData( data ) )
938         {
939             PObjectBase obj = data.GetObj();
940             if ( obj )
941             {
942                 wxTheClipboard->Close();
943                 return PasteObject( parent, obj );
944             }
945         }
946     }
947 
948     wxTheClipboard->Close();
949 
950 	return false;
951 }
952 
CanPasteObjectFromClipboard()953 bool ApplicationData::CanPasteObjectFromClipboard()
954 {
955 	// Do not call Open() when the clipboard is opened
956 	if( !wxTheClipboard->IsOpened() )
957 	{
958         if ( !wxTheClipboard->Open() )
959         {
960             return false;
961         }
962 	}
963 
964 	bool canPaste = wxTheClipboard->IsSupported( wxFBDataObjectFormat );
965 
966 	if( wxTheClipboard->IsOpened() )
967 		wxTheClipboard->Close();
968 
969 	return canPaste;
970 }
971 
CopyObject(PObjectBase obj)972 void ApplicationData::CopyObject( PObjectBase obj )
973 {
974 	m_copyOnPaste = true;
975 
976 	// Make a copy of the object on the clipboard, otherwise
977 	// modifications to the object after the copy will also
978 	// be made on the clipboard.
979 	m_clipboard = m_objDb->CopyObject( obj );
980 
981 	CheckProjectTree( m_project );
982 }
983 
PasteObject(PObjectBase parent,PObjectBase objToPaste)984 bool ApplicationData::PasteObject( PObjectBase parent, PObjectBase objToPaste )
985 {
986 	try
987 	{
988 		PObjectBase clipboard;
989 		if ( objToPaste )
990 		{
991 			clipboard = objToPaste;
992 		}
993 		else if ( m_clipboard )
994 		{
995 			if ( m_copyOnPaste )
996 			{
997 				clipboard = m_objDb->CopyObject( m_clipboard );
998 			}
999 			else
1000 			{
1001 				clipboard = m_clipboard;
1002 			}
1003 		}
1004 
1005 		if ( !clipboard )
1006 		{
1007 			return false;
1008 		}
1009 
1010 		// Remove parent/child relationship from clipboard object
1011 		PObjectBase clipParent = clipboard->GetParent();
1012 		if ( clipParent )
1013 		{
1014 			clipParent->RemoveChild( clipboard );
1015 			clipboard->SetParent( PObjectBase() );
1016 		}
1017 
1018 		// Vamos a hacer un pequeño truco, intentaremos crear un objeto nuevo
1019 		// del mismo tipo que el guardado en m_clipboard debajo de parent.
1020 		// El objeto devuelto quizá no sea de la misma clase que m_clipboard debido
1021 		// a que esté incluido dentro de un "item".
1022 		// Por tanto, si el objeto devuelto es no-nulo, entonces vamos a descender
1023 		// en el arbol hasta que el objeto sea de la misma clase que m_clipboard,
1024 		// momento en que cambiaremos dicho objeto por m_clipboard.
1025 		//
1026 		// Ejemplo:
1027 		//
1028 		//  m_clipboard :: wxButton
1029 		//  parent      :: wxBoxSizer
1030 		//
1031 		//  obj = CreateObject(m_clipboard->GetObjectInfo()->GetClassName(), parent)
1032 		//
1033 		//  obj :: sizeritem
1034 		//              /
1035 		//           wxButton   <- Cambiamos este por m_clipboard
1036 		PObjectBase old_parent = parent;
1037 
1038 		PObjectBase obj = m_objDb->CreateObject( _STDSTR( clipboard->GetObjectInfo()->GetClassName() ), parent );
1039 
1040 		// If the object is already contained in an item, we may need to get the object out of the first
1041 		// item before pasting
1042 		if ( !obj )
1043 		{
1044 
1045 			PObjectBase tempItem = clipboard;
1046 			while ( tempItem->GetObjectInfo()->GetObjectType()->IsItem() )
1047 			{
1048 				tempItem = tempItem->GetChild( 0 );
1049 				if ( !tempItem )
1050 				{
1051 					break;
1052 				}
1053 
1054 				obj = m_objDb->CreateObject( _STDSTR( tempItem->GetObjectInfo()->GetClassName() ), parent );
1055 				if ( obj )
1056 				{
1057 					clipboard = tempItem;
1058 					break;
1059 				}
1060 			}
1061 		}
1062 
1063 		int pos = -1;
1064 
1065 		if ( !obj )
1066 		{
1067 			// si no se ha podido crear el objeto vamos a intentar crearlo colgado
1068 			// del padre de "parent" y además vamos a insertarlo en la posición
1069 			// siguiente a "parent"
1070 			PObjectBase selected = parent;
1071 			parent = selected->GetParent();
1072 
1073 			while ( parent && parent->GetObjectInfo()->GetObjectType()->IsItem() )
1074 			{
1075 				selected = parent;
1076 				parent = selected->GetParent();
1077 			}
1078 
1079 			if ( parent )
1080 			{
1081 				obj = m_objDb->CreateObject( _STDSTR( clipboard->GetObjectInfo()->GetClassName() ), parent );
1082 				if ( obj )
1083 				{
1084 					pos = CalcPositionOfInsertion( selected, parent );
1085 				}
1086 			}
1087 		}
1088 
1089 		if ( !obj )
1090 		{
1091 			return false;
1092 		}
1093 
1094 		PObjectBase aux = obj;
1095 
1096 		while ( aux && aux->GetObjectInfo() != clipboard->GetObjectInfo() )
1097 			aux = ( aux->GetChildCount() > 0 ? aux->GetChild( 0 ) : PObjectBase() );
1098 
1099 		if ( aux && aux != obj )
1100 		{
1101 			// sustituimos aux por clipboard
1102 			PObjectBase auxParent = aux->GetParent();
1103 			auxParent->RemoveChild( aux );
1104 			aux->SetParent( PObjectBase() );
1105 
1106 			auxParent->AddChild( clipboard );
1107 			clipboard->SetParent( auxParent );
1108 		}
1109 		else
1110 			obj = clipboard;
1111 
1112 		// y finalmente insertamos en el arbol
1113 		PCommand command( new InsertObjectCmd( this, obj, parent, pos ) );
1114 
1115 		Execute( command );
1116 
1117 		if ( !m_copyOnPaste )
1118 			m_clipboard.reset();
1119 
1120 		ResolveSubtreeNameConflicts( obj );
1121 
1122 		NotifyProjectRefresh();
1123 
1124 		// vamos a mantener seleccionado el nuevo objeto creado
1125 		// pero hay que tener en cuenta que es muy probable que el objeto creado
1126 		// sea un "item"
1127 		while ( obj && obj->GetObjectInfo()->GetObjectType()->IsItem() )
1128 		{
1129 			assert( obj->GetChildCount() > 0 );
1130 			obj = obj->GetChild( 0 );
1131 		}
1132 
1133 		SelectObject( obj, true, true );
1134 
1135 		CheckProjectTree( m_project );
1136 	}
1137 	catch ( wxFBException& ex )
1138 	{
1139 		wxLogError( ex.what() );
1140 		return false;
1141 	}
1142 
1143 	return true;
1144 }
1145 
InsertObject(PObjectBase obj,PObjectBase parent)1146 void ApplicationData::InsertObject( PObjectBase obj, PObjectBase parent )
1147 {
1148 	// FIXME! comprobar obj se puede colgar de parent
1149 	//  if (parent->GetObjectInfo()->GetObjectType()->FindChildType(
1150 	//    obj->GetObjectInfo()->GetObjectType()))
1151 	//  {
1152 	PCommand command( new InsertObjectCmd( this, obj, parent ) );
1153 	Execute( command ); //m_cmdProc.Execute(command);
1154 	NotifyProjectRefresh();
1155 	//  }
1156 }
1157 
MergeProject(PObjectBase project)1158 void ApplicationData::MergeProject( PObjectBase project )
1159 {
1160 	// FIXME! comprobar obj se puede colgar de parent
1161 
1162 	for ( unsigned int i = 0; i < project->GetChildCount(); i++ )
1163 	{
1164 		//m_project->AddChild(project->GetChild(i));
1165 		//project->GetChild(i)->SetParent(m_project);
1166 
1167 		PObjectBase child = project->GetChild( i );
1168 		RemoveEmptyItems( child );
1169 
1170 		InsertObject( child, m_project );
1171 	}
1172 
1173 	// Merge bitmaps and icons properties
1174 	PObjectBase thisProject = GetProjectData();
1175 	PProperty prop = thisProject->GetProperty( _("bitmaps") );
1176 	if ( prop )
1177 	{
1178 		wxString value = prop->GetValue();
1179 		value.Trim();
1180 		value << wxT(" ") << project->GetPropertyAsString( _("bitmaps") );
1181 		prop->SetValue( value );
1182 	}
1183 	prop = thisProject->GetProperty( _("icons") );
1184 	if ( prop )
1185 	{
1186 		wxString value = prop->GetValue();
1187 		value.Trim();
1188 		value << wxT(" ") << project->GetPropertyAsString( _("icons") );
1189 		prop->SetValue( value );
1190 	}
1191 
1192 	NotifyProjectRefresh();
1193 }
1194 
ModifyProperty(PProperty prop,wxString str)1195 void ApplicationData::ModifyProperty( PProperty prop, wxString str )
1196 {
1197 	PObjectBase object = prop->GetObject();
1198 
1199 	if ( str != prop->GetValue() )
1200 	{
1201 		PCommand command( new ModifyPropertyCmd( prop, str ) );
1202 		Execute( command ); //m_cmdProc.Execute(command);
1203 
1204 		NotifyPropertyModified( prop );
1205 	}
1206 }
1207 
ModifyEventHandler(PEvent evt,wxString value)1208 void ApplicationData::ModifyEventHandler( PEvent evt, wxString value )
1209 {
1210 	PObjectBase object = evt->GetObject();
1211 
1212 	if ( value != evt->GetValue() )
1213 	{
1214 		PCommand command( new ModifyEventHandlerCmd( evt, value ) );
1215 		Execute( command ); //m_cmdProc.Execute(command);
1216 
1217 		NotifyEventHandlerModified( evt );
1218 	}
1219 }
1220 
SaveProject(const wxString & filename)1221 void ApplicationData::SaveProject( const wxString& filename )
1222 {
1223 	// Make sure this file is not already open
1224 
1225 	if ( !m_ipc->VerifySingleInstance( filename, false ) )
1226 	{
1227 		if ( wxYES == wxMessageBox( wxT( "You cannot save over a file that is currently open in another instance.\nWould you like to switch to that instance?" ),
1228 		                            wxT( "Open in Another Instance" ), wxICON_QUESTION | wxYES_NO, wxTheApp->GetTopWindow() ) )
1229 		{
1230 			m_ipc->VerifySingleInstance( filename, true );
1231 		}
1232 
1233 		return;
1234 	}
1235 
1236 	try
1237 	{
1238 		ticpp::Document doc;
1239 		m_project->Serialize( &doc );
1240 		doc.SaveFile( std::string( filename.mb_str( wxConvFile ) ) );
1241 
1242 		m_projectFile = filename;
1243 		SetProjectPath( ::wxPathOnly( filename ) );
1244 		m_modFlag = false;
1245 		m_cmdProc.SetSavePoint();
1246 		NotifyProjectSaved();
1247 	}
1248 	catch ( ticpp::Exception& ex )
1249 	{
1250 		wxString message = _WXSTR( ex.m_details );
1251 
1252 		if ( message.empty() )
1253 		{
1254 			message = wxString( ex.m_details.c_str(), wxConvFile );
1255 		}
1256 
1257 		THROW_WXFBEX( message )
1258 	}
1259 }
1260 
LoadProject(const wxString & file,bool checkSingleInstance)1261 bool ApplicationData::LoadProject( const wxString &file, bool checkSingleInstance )
1262 
1263 {
1264 	LogDebug( wxT( "LOADING" ) );
1265 
1266 	if ( !wxFileName::FileExists( file ) )
1267 	{
1268 		wxLogError( wxT( "This file does not exist: %s" ), file.c_str() );
1269 		return false;
1270 	}
1271 
1272 	if ( checkSingleInstance )
1273 	{
1274 		if ( !m_ipc->VerifySingleInstance( file ) )
1275 		{
1276 			return false;
1277 		}
1278 	}
1279 
1280 	try
1281 	{
1282 		ticpp::Document doc;
1283 		XMLUtils::LoadXMLFile( doc, false, file );
1284 
1285 		ticpp::Element* root = doc.FirstChildElement();
1286 
1287 		m_objDb->ResetObjectCounters();
1288 
1289 		int fbpVerMajor = 0;
1290 		int fbpVerMinor = 0;
1291 
1292 		if ( root->Value() != std::string( "object" ) )
1293 		{
1294 			try
1295 			{
1296 				ticpp::Element* fileVersion = root->FirstChildElement( "FileVersion" );
1297 				fileVersion->GetAttributeOrDefault( "major", &fbpVerMajor, 0 );
1298 				fileVersion->GetAttributeOrDefault( "minor", &fbpVerMinor, 0 );
1299 			}
1300 			catch( ticpp::Exception& )
1301 			{
1302 			}
1303 		}
1304 
1305 		bool older = false;
1306 		bool newer = false;
1307 
1308 		if ( m_fbpVerMajor == fbpVerMajor )
1309 		{
1310 			older = ( fbpVerMinor < m_fbpVerMinor );
1311 			newer = ( fbpVerMinor > m_fbpVerMinor );
1312 		}
1313 		else
1314 		{
1315 			older = ( fbpVerMajor < m_fbpVerMajor );
1316 			newer = ( fbpVerMajor > m_fbpVerMajor );
1317 		}
1318 
1319 		if ( newer )
1320 		{
1321 			wxMessageBox( wxT( "This project file is newer than this version of wxFormBuilder.\n" )
1322 			              wxT( "It cannot be opened.\n\n" )
1323 			              wxT( "Please download an updated version from http://www.wxFormBuilder.org" ), _( "New Version" ), wxICON_ERROR );
1324 			return false;
1325 		}
1326 
1327 		if ( older )
1328 		{
1329 			if ( wxYES == wxMessageBox( wxT( "This project file is not of the current version.\n" )
1330 			                            wxT( "Would you to attempt automatic conversion?\n\n" )
1331 			                            wxT( "NOTE: This will modify your project file on disk!" ), _( "Old Version" ), wxYES_NO ) )
1332 			{
1333 				// we make a backup of the project
1334 				::wxCopyFile( file, file + wxT( ".bak" ) );
1335 
1336 				if ( !ConvertProject( file, fbpVerMajor, fbpVerMinor ) )
1337 				{
1338 					wxLogError( wxT( "Unable to convert project" ) );
1339 					return false;
1340 				}
1341 
1342 				XMLUtils::LoadXMLFile( doc, false, file );
1343 				root = doc.FirstChildElement();
1344 			}
1345 			else
1346 			{
1347 				return false;
1348 			}
1349 		}
1350 
1351 		ticpp::Element* object = root->FirstChildElement( "object" );
1352 		PObjectBase proj;
1353 
1354 		try
1355 		{
1356 			proj = m_objDb->CreateObject( object );
1357 		}
1358 		catch ( wxFBException& ex )
1359 		{
1360 			wxLogError( ex.what() );
1361 			return false;
1362 		}
1363 
1364 		if ( proj && proj->GetObjectTypeName() == wxT( "project" ) )
1365 		{
1366 			PObjectBase old_proj = m_project;
1367 			m_project = proj;
1368 			m_selObj = m_project;
1369 			m_modFlag = false;
1370 			m_cmdProc.Reset();
1371 			m_projectFile = file;
1372 			SetProjectPath( ::wxPathOnly( file ) );
1373 			NotifyProjectLoaded();
1374 			NotifyProjectRefresh();
1375 		}
1376 	}
1377 	catch( ticpp::Exception& ex )
1378 	{
1379 		wxLogError( _WXSTR( ex.m_details ) );
1380 		return false;
1381 	}
1382 
1383 	return true;
1384 }
1385 
ConvertProject(const wxString & path,int fileMajor,int fileMinor)1386 bool ApplicationData::ConvertProject( const wxString& path, int fileMajor, int fileMinor )
1387 {
1388 	try
1389 	{
1390 		ticpp::Document doc;
1391 		XMLUtils::LoadXMLFile( doc, false, path );
1392 
1393 		ticpp::Element* root = doc.FirstChildElement();
1394 
1395 		if ( root->Value() == std::string( "object" ) )
1396 		{
1397 			ConvertProjectProperties( root, path, fileMajor, fileMinor );
1398 			ConvertObject( root, fileMajor, fileMinor );
1399 
1400 			// Create a clone of now-converted object tree, so it can be linked
1401 			// underneath the root element
1402 			std::auto_ptr< ticpp::Node > objectTree = root->Clone();
1403 
1404 			// Clear the document to add the declatation and the root element
1405 			doc.Clear();
1406 
1407 			// Add the declaration
1408 			doc.LinkEndChild( new ticpp::Declaration( "1.0", "UTF-8", "yes" ) );
1409 
1410 			// Add the root element, with file version
1411 			ticpp::Element* newRoot = new ticpp::Element( "wxFormBuilder_Project" );
1412 
1413 			ticpp::Element* fileVersion = new ticpp::Element( "FileVersion" );
1414 			fileVersion->SetAttribute( "major", m_fbpVerMajor );
1415 			fileVersion->SetAttribute( "minor", m_fbpVerMinor );
1416 
1417 			newRoot->LinkEndChild( fileVersion );
1418 
1419 			// Add the object tree
1420 			newRoot->LinkEndChild( objectTree.release() );
1421 
1422 			doc.LinkEndChild( newRoot );
1423 		}
1424 		else
1425 		{
1426 			// Handle project separately because it only occurs once
1427 			ticpp::Element* project = root->FirstChildElement( "object" );
1428 			ConvertProjectProperties( project, path, fileMajor, fileMinor );
1429 			ConvertObject( project, fileMajor, fileMinor );
1430 			ticpp::Element* fileVersion = root->FirstChildElement( "FileVersion" );
1431 			fileVersion->SetAttribute( "major", m_fbpVerMajor );
1432 			fileVersion->SetAttribute( "minor", m_fbpVerMinor );
1433 		}
1434 
1435 		doc.SaveFile();
1436 	}
1437 	catch ( ticpp::Exception& ex )
1438 	{
1439 		wxLogError( _WXSTR( ex.m_details ) );
1440 		return false;
1441 	}
1442 
1443 	return true;
1444 }
1445 
ConvertProjectProperties(ticpp::Element * project,const wxString & path,int fileMajor,int fileMinor)1446 void ApplicationData::ConvertProjectProperties( ticpp::Element* project, const wxString& path, int fileMajor, int fileMinor )
1447 
1448 {
1449 	// Ensure that this is the "project" element
1450 	std::string objClass;
1451 	project->GetAttribute( "class", &objClass );
1452 
1453 	if ( objClass != "Project" )
1454 	{
1455 		return;
1456 	}
1457 
1458 	// Reusable sets for finding properties
1459 	std::set< std::string > oldProps;
1460 	std::set< ticpp::Element* > newProps;
1461 
1462 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 5 ) )
1463 	{
1464 		// Find the user_headers property
1465 
1466 		oldProps.insert( "user_headers" );
1467 		GetPropertiesToConvert( project, oldProps, &newProps );
1468 
1469 		std::string user_headers;
1470 		if ( !newProps.empty() )
1471 		{
1472 			user_headers = ( *newProps.begin() )->GetText( false );
1473 			project->RemoveChild( *newProps.begin() );
1474 		}
1475 
1476 		if ( !user_headers.empty() )
1477 		{
1478 			wxString 	msg  = _( "The \"user_headers\" property has been removed.\n" );
1479 			msg += _( "Its purpose was to provide a place to include precompiled headers or\n" );
1480 			msg += _( "headers for subclasses.\n" );
1481 			msg += _( "There is now a \"precompiled_header\" property and a \"header\" subitem\n" );
1482 			msg += _( "on the subclass property.\n\n" );
1483 			msg += _( "Would you like the current value of the \"user_headers\" property to be saved\n" );
1484 			msg += _( "to a file so that you can distribute the headers among the \"precompiled_header\"\n" );
1485 			msg += _( "and \"subclass\" properties\?" );
1486 
1487 			if ( wxYES == wxMessageBox( msg, _( "The \"user_headers\" property has been removed" ), wxICON_QUESTION | wxYES_NO | wxYES_DEFAULT, wxTheApp->GetTopWindow() ) )
1488 			{
1489 				wxString name;
1490 				wxFileName::SplitPath( path, NULL, NULL, &name, NULL );
1491 				wxFileDialog dialog( wxTheApp->GetTopWindow(), _( "Save \"user_headers\"" ), ::wxPathOnly( path ),
1492 				                     name + wxT( "_user_headers.txt" ), wxT( "All files (*.*)|*.*" ), wxFD_SAVE );
1493 
1494 				if ( dialog.ShowModal() == wxID_OK )
1495 				{
1496 					wxString wxuser_headers = _WXSTR( user_headers );
1497 					wxString filename = dialog.GetPath();
1498 					bool success = false;
1499 					wxFFile output( filename, wxT( "w" ) );
1500 
1501 					if ( output.IsOpened() )
1502 					{
1503 						if ( output.Write( wxuser_headers ) )
1504 						{
1505 							output.Close();
1506 							success = true;
1507 						}
1508 					}
1509 
1510 					if ( !success )
1511 					{
1512 						wxLogError( _( "Unable to open %s for writing.\nUser Headers:\n%s" ), filename.c_str(), wxuser_headers.c_str() );
1513 					}
1514 				}
1515 			}
1516 		}
1517 	}
1518 
1519 
1520 	// The pch property is now the exact code to be generated, not just the header filename
1521 	// The goal of this conversion block is to determine which of two possible pch blocks to use
1522 	// The pch block that wxFB generated changed in version 1.6
1523 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 8 ) )
1524 	{
1525 		oldProps.clear();
1526 		newProps.clear();
1527 		oldProps.insert( "precompiled_header" );
1528 		GetPropertiesToConvert( project, oldProps, &newProps );
1529 
1530 		if ( !newProps.empty() )
1531 		{
1532 			std::string pch = ( *newProps.begin() )->GetText( false );
1533 			if ( !pch.empty() )
1534 			{
1535 				if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 6 ) )
1536 				{
1537 					// use the older block
1538 					( *newProps.begin() )->SetText(
1539 														  "#include \"" + pch + "\""
1540 														"\n"
1541 														"\n#ifdef __BORLANDC__"
1542 														"\n#pragma hdrstop"
1543 														"\n#endif //__BORLANDC__"
1544 														"\n"
1545 														"\n#ifndef WX_PRECOMP"
1546 														"\n#include <wx/wx.h>"
1547 														"\n#endif //WX_PRECOMP"
1548 													);
1549 				}
1550 				else
1551 				{
1552 					// use the newer block
1553 					( *newProps.begin() )->SetText(
1554 														  "#ifdef WX_PRECOMP"
1555 														"\n"
1556 														"\n#include \"" + pch + "\""
1557 														"\n"
1558 														"\n#ifdef __BORLANDC__"
1559 														"\n#pragma hdrstop"
1560 														"\n#endif //__BORLANDC__"
1561 														"\n"
1562 														"\n#else"
1563 														"\n#include <wx/wx.h>"
1564 														"\n#endif //WX_PRECOMP"
1565 													);
1566 				}
1567 			}
1568 		}
1569 	}
1570 
1571 	// The format of string list properties changed in version 1.9
1572 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 9 ) )
1573 	{
1574 		oldProps.clear();
1575 		newProps.clear();
1576 		oldProps.insert( "namespace" );
1577 		oldProps.insert( "bitmaps" );
1578 		oldProps.insert( "icons" );
1579 		GetPropertiesToConvert( project, oldProps, &newProps );
1580 
1581 		std::set< ticpp::Element* >::iterator prop;
1582 		for ( prop = newProps.begin(); prop != newProps.end(); ++prop )
1583 		{
1584 			std::string value = ( *prop )->GetText( false );
1585 			if ( !value.empty() )
1586 			{
1587 				wxArrayString array = TypeConv::OldStringToArrayString( _WXSTR( value ) );
1588 				( *prop )->SetText( _STDSTR( TypeConv::ArrayStringToString( array ) ) );
1589 			}
1590 		}
1591 	}
1592 
1593 	// event_handler moved to the forms in version 1.10
1594 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 10 ) )
1595 	{
1596 		oldProps.clear();
1597 		newProps.clear();
1598 		oldProps.insert( "event_handler" );
1599 		GetPropertiesToConvert( project, oldProps, &newProps );
1600 
1601 
1602 		if ( !newProps.empty() )
1603 		{
1604 			ticpp::Iterator< ticpp::Element > object( "object" );
1605 			for ( object = project->FirstChildElement( "object", false ); object != object.end(); ++object )
1606 			{
1607 				object->LinkEndChild( ( *newProps.begin() )->Clone().get() );
1608 			}
1609 
1610 			project->RemoveChild( *newProps.begin() );
1611 		}
1612 	}
1613 }
1614 
ConvertObject(ticpp::Element * parent,int fileMajor,int fileMinor)1615 void ApplicationData::ConvertObject( ticpp::Element* parent, int fileMajor, int fileMinor )
1616 {
1617 	ticpp::Iterator< ticpp::Element > object( "object" );
1618 
1619 	for ( object = parent->FirstChildElement( "object", false ); object != object.end(); ++object )
1620 	{
1621 		ConvertObject( object.Get(), fileMajor, fileMinor );
1622 	}
1623 
1624 	// Reusable sets to find properties with
1625 	std::set< std::string > oldProps;
1626 
1627 	std::set< ticpp::Element* > newProps;
1628 
1629 	std::set< ticpp::Element* >::iterator newProp;
1630 
1631 	// Get the class of the object
1632 	std::string objClass;
1633 
1634 	parent->GetAttribute( "class", &objClass );
1635 
1636 	/* The changes below will convert an unversioned file to version 1.3 */
1637 
1638 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 3 ) )
1639 	{
1640 		// The property 'option' became 'proportion'
1641 
1642 		if ( objClass == "sizeritem" ||  objClass == "gbsizeritem" || objClass == "spacer" )
1643 		{
1644 			oldProps.clear();
1645 			newProps.clear();
1646 			oldProps.insert( "option" );
1647 			GetPropertiesToConvert( parent, oldProps, &newProps );
1648 
1649 			if ( !newProps.empty() )
1650 			{
1651 				// One in, one out
1652 				( *newProps.begin() )->SetAttribute( "name", "proportion" );
1653 			}
1654 		}
1655 
1656 		// The 'style' property used to have both wxWindow styles and the styles of the specific controls
1657 		// now it only has the styles of the specfic controls, and wxWindow styles are saved in window_style
1658 		// This also applies to 'extra_style', which was once combined with 'style'.
1659 		// And they were named 'WindowStyle' and one point, too...
1660 
1661 		std::set< wxString > windowStyles;
1662 		windowStyles.insert( wxT( "wxSIMPLE_BORDER" ) );
1663 		windowStyles.insert( wxT( "wxDOUBLE_BORDER" ) );
1664 		windowStyles.insert( wxT( "wxSUNKEN_BORDER" ) );
1665 		windowStyles.insert( wxT( "wxRAISED_BORDER" ) );
1666 		windowStyles.insert( wxT( "wxSTATIC_BORDER" ) );
1667 		windowStyles.insert( wxT( "wxNO_BORDER" ) );
1668 		windowStyles.insert( wxT( "wxTRANSPARENT_WINDOW" ) );
1669 		windowStyles.insert( wxT( "wxTAB_TRAVERSAL" ) );
1670 		windowStyles.insert( wxT( "wxWANTS_CHARS" ) );
1671 		windowStyles.insert( wxT( "wxVSCROLL" ) );
1672 		windowStyles.insert( wxT( "wxHSCROLL" ) );
1673 		windowStyles.insert( wxT( "wxALWAYS_SHOW_SB" ) );
1674 		windowStyles.insert( wxT( "wxCLIP_CHILDREN" ) );
1675 		windowStyles.insert( wxT( "wxFULL_REPAINT_ON_RESIZE" ) );
1676 
1677 		// Transfer the window styles
1678 		oldProps.clear();
1679 		newProps.clear();
1680 
1681 		oldProps.insert( "style" );
1682 
1683 		oldProps.insert( "WindowStyle" );
1684 
1685 		GetPropertiesToConvert( parent, oldProps, &newProps );
1686 
1687 		for ( newProp = newProps.begin(); newProp != newProps.end(); ++newProp )
1688 		{
1689 			TransferOptionList( *newProp, &windowStyles, "window_style" );
1690 		}
1691 
1692 
1693 		std::set< wxString > extraWindowStyles;
1694 		extraWindowStyles.insert( wxT( "wxWS_EX_VALIDATE_RECURSIVELY" ) );
1695 		extraWindowStyles.insert( wxT( "wxWS_EX_BLOCK_EVENTS" ) );
1696 		extraWindowStyles.insert( wxT( "wxWS_EX_TRANSIENT" ) );
1697 		extraWindowStyles.insert( wxT( "wxWS_EX_PROCESS_IDLE" ) );
1698 		extraWindowStyles.insert( wxT( "wxWS_EX_PROCESS_UI_UPDATES" ) );
1699 
1700 		// Transfer the window extra styles
1701 		oldProps.clear();
1702 		newProps.clear();
1703 
1704 		oldProps.insert( "style" );
1705 
1706 		oldProps.insert( "extra_style" );
1707 
1708 		oldProps.insert( "WindowStyle" );
1709 
1710 		GetPropertiesToConvert( parent, oldProps, &newProps );
1711 
1712 		for ( newProp = newProps.begin(); newProp != newProps.end(); ++newProp )
1713 		{
1714 			TransferOptionList( *newProp, &extraWindowStyles, "window_extra_style" );
1715 		}
1716 	}
1717 
1718 	/* The file is now at least version 1.3 */
1719 
1720 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 4 ) )
1721 	{
1722 		if ( objClass == "wxCheckList" )
1723 		{
1724 			// The class we once named "wxCheckList" really represented a "wxCheckListBox", now that we use the #class macro in
1725 			// code generation, it generates the wrong code
1726 			parent->SetAttribute( "class", "wxCheckListBox" );
1727 		}
1728 	}
1729 
1730 	/* The file is now at least version 1.4 */
1731 
1732 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 6 ) )
1733 	{
1734 		if ( objClass == "spacer" )
1735 		{
1736 			// spacer used to be represented by its own class, it is now under a sizeritem like everything else.
1737 			// no need to check for a wxGridBagSizer, because it was introduced at the same time.
1738 
1739 			// the goal is to change the class to sizeritem, then create a spacer child, then move "width" and "height" to the spacer
1740 			parent->SetAttribute( "class", "sizeritem" );
1741 			ticpp::Element spacer( "object" );
1742 			spacer.SetAttribute( "class", "spacer" );
1743 
1744 			oldProps.clear();
1745 			newProps.clear();
1746 			oldProps.insert( "width" );
1747 			GetPropertiesToConvert( parent, oldProps, &newProps );
1748 
1749 			if ( !newProps.empty() )
1750 			{
1751 				// One in, one out
1752 				ticpp::Element* width = *newProps.begin();
1753 				spacer.LinkEndChild( width->Clone().release() );
1754 				parent->RemoveChild( width );
1755 			}
1756 
1757 			oldProps.clear();
1758 			newProps.clear();
1759 			oldProps.insert( "height" );
1760 			GetPropertiesToConvert( parent, oldProps, &newProps );
1761 
1762 			if ( !newProps.empty() )
1763 			{
1764 				// One in, one out
1765 				ticpp::Element* height = *newProps.begin();
1766 				spacer.LinkEndChild( height->Clone().release() );
1767 				parent->RemoveChild( height );
1768 			}
1769 			parent->LinkEndChild( &spacer );
1770 		}
1771 	}
1772 
1773 	/* The file is now at least version 1.6 */
1774 
1775 	// Version 1.7 now stores all font properties.
1776 	// The font property conversion is automatic because it is just an extension of the old values.
1777 
1778 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 7 ) )
1779 	{
1780 		// Remove deprecated 2.6 things
1781 
1782 		// wxDialog styles wxTHICK_FRAME and wxNO_3D
1783 		if ( objClass == "Dialog" )
1784 		{
1785 			oldProps.clear();
1786 			newProps.clear();
1787 			oldProps.insert( "style" );
1788 			GetPropertiesToConvert( parent, oldProps, &newProps );
1789 
1790 			if ( !newProps.empty() )
1791 			{
1792 				ticpp::Element* style = *newProps.begin();
1793 				wxString styles = _WXSTR( style->GetText( false ) );
1794 				if ( !styles.empty() )
1795 				{
1796 					if ( TypeConv::FlagSet( wxT("wxTHICK_FRAME"), styles ) )
1797 					{
1798 						styles = TypeConv::ClearFlag( wxT("wxTHICK_FRAME"), styles );
1799 						styles = TypeConv::SetFlag( wxT("wxRESIZE_BORDER"), styles );
1800 					}
1801 
1802 					styles = TypeConv::ClearFlag( wxT("wxNO_3D"), styles );
1803 					style->SetText( _STDSTR( styles ) );
1804 				}
1805 			}
1806 		}
1807 	}
1808 
1809 	/* The file is now at least version 1.7 */
1810 
1811 	// The update to 1.8 only affected project properties
1812 	// See ConvertProjectProperties
1813 
1814 	/* The file is now at least version 1.8 */
1815 
1816 	// stringlist properties are stored in a different format as of version 1.9
1817 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 9 ) )
1818 	{
1819 		oldProps.clear();
1820 		newProps.clear();
1821 
1822 		if  (	objClass == "wxComboBox"	||
1823 				objClass == "wxChoice"		||
1824 				objClass == "wxListBox"		||
1825 				objClass == "wxRadioBox"	||
1826 				objClass == "wxCheckListBox"
1827 			)
1828 		{
1829 			oldProps.insert( "choices" );
1830 		}
1831 		else if ( objClass == "wxGrid" )
1832 		{
1833 			oldProps.insert( "col_label_values" );
1834 			oldProps.insert( "row_label_values" );
1835 		}
1836 
1837 		if ( !oldProps.empty() )
1838 		{
1839 			GetPropertiesToConvert( parent, oldProps, &newProps );
1840 
1841 			std::set< ticpp::Element* >::iterator prop;
1842 			for ( prop = newProps.begin(); prop != newProps.end(); ++prop )
1843 			{
1844 				std::string value = ( *prop )->GetText( false );
1845 				if ( !value.empty() )
1846 				{
1847 					wxArrayString array = TypeConv::OldStringToArrayString( _WXSTR( value ) );
1848 					( *prop )->SetText( _STDSTR( TypeConv::ArrayStringToString( array ) ) );
1849 				}
1850 			}
1851 		}
1852 	}
1853 
1854 	/* The file is now at least version 1.9 */
1855 
1856 	// Version 1.11 now stores bitmap property in the following format:
1857 	// 'source'; 'data' instead of old form 'data'; 'source'.
1858 
1859 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 11 ) )
1860 	{
1861 		oldProps.clear();
1862 		newProps.clear();
1863 		oldProps.insert( "bitmap" );
1864 		GetPropertiesToConvert( parent, oldProps, &newProps );
1865 
1866 		std::set< ticpp::Element* >::iterator prop;
1867 		for ( prop = newProps.begin(); prop != newProps.end(); ++prop )
1868 		{
1869 			ticpp::Element* bitmap = *prop;
1870 
1871 			wxString image = _WXSTR( bitmap->GetText( false ) );
1872 			if ( !image.empty() )
1873 			{
1874 				if( image.AfterLast( ';' ).Contains( _("Load From") ) )
1875 				{
1876 					wxString source = image.AfterLast( ';' ).Trim().Trim(false);
1877 					wxString data = image.BeforeLast( ';' ).Trim().Trim(false);
1878 
1879 					bitmap->SetText( _STDSTR( source + wxT("; ") + data ) );
1880 				}
1881 			}
1882 		}
1883 
1884 		/* oldProps.clear();
1885 		newProps.clear();
1886 		oldProps.insert( "choices" );
1887 		GetPropertiesToConvert( parent, oldProps, &newProps );
1888 
1889 		for ( prop = newProps.begin(); prop != newProps.end(); ++prop )
1890 		{
1891 			ticpp::Element* choices = *prop;
1892 
1893 			wxString content = _WXSTR( choices->GetText( false ) );
1894 			if ( !content.empty() )
1895 			{
1896 				content.Replace( wxT("\" \""), wxT(";") );
1897 				content.Replace( wxT("\""), wxT("") );
1898 
1899 				choices->SetText( _STDSTR( content ) );
1900 			}
1901 		}*/
1902 	}
1903 
1904 	/* The file is now at least version 1.11 */
1905 	if ( fileMajor < 1 || ( 1 == fileMajor && fileMinor < 12 ) )
1906 	{
1907 		bool classUpdated = false;
1908 		if( "wxScintilla" == objClass )
1909 		{
1910 			objClass = "wxStyledTextCtrl";
1911 			parent->SetAttribute( "class", objClass );
1912 			classUpdated = true;
1913 		}
1914 		if( "wxTreeListCtrl" == objClass )
1915 		{
1916 			objClass = "wxadditions::wxTreeListCtrl";
1917 			parent->SetAttribute( "class", objClass );
1918 			classUpdated = true;
1919 		}
1920 		if( "wxTreeListCtrlColumn" == objClass )
1921 		{
1922 			objClass = "wxadditions::wxTreeListCtrlColumn";
1923 			parent->SetAttribute( "class", objClass );
1924 			classUpdated = true;
1925 		}
1926 		if( m_warnOnAdditionsUpdate && classUpdated )
1927 		{
1928 			m_warnOnAdditionsUpdate = false;
1929 			wxLogWarning( _("Updated classes from wxAdditions. You must use the latest version of wxAdditions to continue.\nNote wxScintilla is now wxStyledListCtrl, wxTreeListCtrl is now wxadditions::wxTreeListCtrl, and wxTreeListCtrlColumn is now wxadditions::wxTreeListCtrlColumn") );
1930 		}
1931 
1932 		typedef std::map< std::string, std::set< std::string > > PropertiesToRemove;
1933 
1934 		static std::set< std::string > propertyRemovalWarnings;
1935 		const PropertiesToRemove& propertiesToRemove = GetPropertiesToRemove_v1_12();
1936 		PropertiesToRemove::const_iterator it = propertiesToRemove.find( objClass );
1937 		if( it != propertiesToRemove.end() )
1938 		{
1939 			RemoveProperties( parent, it->second );
1940 			if( 0 == propertyRemovalWarnings.count( objClass ) )
1941 			{
1942 				std::stringstream ss;
1943 				std::ostream_iterator< std::string > out_it (ss, ", ");
1944 				std::copy( it->second.begin(), it->second.end(), out_it );
1945 
1946 				wxLogMessage( _("Removed properties for class %s because they are no longer supported: %s"), objClass, ss.str() );
1947 				propertyRemovalWarnings.insert( objClass );
1948 			}
1949 		}
1950 	}
1951 	/* The file is now at least version 1.12 */
1952 }
1953 
GetPropertiesToConvert(ticpp::Node * parent,const std::set<std::string> & names,std::set<ticpp::Element * > * properties)1954 void ApplicationData::GetPropertiesToConvert( ticpp::Node* parent, const std::set< std::string >& names, std::set< ticpp::Element* >* properties )
1955 {
1956 	// Clear result set
1957 	properties->clear();
1958 
1959 	ticpp::Iterator< ticpp::Element > prop( "property" );
1960 
1961 	for ( prop = parent->FirstChildElement( "property", false ); prop != prop.end(); ++prop )
1962 	{
1963 		std::string name;
1964 		prop->GetAttribute( "name", &name );
1965 
1966 		if ( names.find( name ) != names.end() )
1967 		{
1968 			properties->insert( prop.Get() );
1969 		}
1970 	}
1971 }
1972 
RemoveProperties(ticpp::Node * parent,const std::set<std::string> & names)1973 void ApplicationData::RemoveProperties( ticpp::Node* parent, const std::set< std::string >& names )
1974 {
1975 	ticpp::Iterator< ticpp::Element > prop( "property" );
1976 
1977 	for ( prop = parent->FirstChildElement( "property", false ); prop != prop.end(); )
1978 	{
1979 		ticpp::Element element = *prop;
1980 		++prop;
1981 
1982 		std::string name;
1983 		element.GetAttribute( "name", &name );
1984 
1985 		if ( names.find( name ) != names.end() )
1986 		{
1987 			parent->RemoveChild( &element );
1988 		}
1989 	}
1990 }
1991 
TransferOptionList(ticpp::Element * prop,std::set<wxString> * options,const std::string & newPropName)1992 void ApplicationData::TransferOptionList( ticpp::Element* prop, std::set< wxString >* options, const std::string& newPropName )
1993 
1994 {
1995 	wxString value = _WXSTR( prop->GetText( false ) );
1996 
1997 	std::set< wxString > transfer;
1998 
1999 	std::set< wxString > keep;
2000 
2001 	// Sort options - if in the 'options' set, they should be transferred to a property named 'newPropName'
2002 	// otherwise, they should stay
2003 	wxStringTokenizer tkz( value, wxT( "|" ), wxTOKEN_RET_EMPTY_ALL );
2004 
2005 	while ( tkz.HasMoreTokens() )
2006 	{
2007 		wxString option = tkz.GetNextToken();
2008 		option.Trim( false );
2009 		option.Trim( true );
2010 
2011 		if ( options->find( option ) != options->end() )
2012 		{
2013 			// Needs to be transferred
2014 			transfer.insert( option );
2015 		}
2016 		else
2017 		{
2018 			// Should be kept
2019 			keep.insert( option );
2020 		}
2021 	}
2022 
2023 	// Reusable sets to find properties with
2024 	std::set< std::string > oldProps;
2025 
2026 	std::set< ticpp::Element* > newProps;
2027 
2028 	// If there are any to transfer, add to the target property, or make a new one
2029 	ticpp::Node* parent = prop->Parent();
2030 
2031 	if ( !transfer.empty() )
2032 	{
2033 		// Check for the target property
2034 		ticpp::Element* newProp;
2035 		wxString newOptionList;
2036 
2037 		oldProps.clear();
2038 		oldProps.insert( newPropName );
2039 		GetPropertiesToConvert( parent, oldProps, &newProps );
2040 
2041 		if ( !newProps.empty() )
2042 		{
2043 			newProp = *newProps.begin();
2044 			newOptionList << wxT( "|" ) << _WXSTR( newProp->GetText( false ) );
2045 		}
2046 		else
2047 		{
2048 			newProp = new ticpp::Element( "property" );
2049 			newProp->SetAttribute( "name", newPropName );
2050 		}
2051 
2052 		std::set< wxString >::iterator option;
2053 
2054 		for ( option = transfer.begin(); option != transfer.end(); ++option )
2055 		{
2056 			newOptionList << wxT( "|" ) << *option;
2057 		}
2058 
2059 		newProp->SetText( _STDSTR( newOptionList.substr( 1 ) ) );
2060 
2061 		if ( newProps.empty() )
2062 		{
2063 			parent->InsertBeforeChild( prop, *newProp );
2064 			delete newProp;
2065 		}
2066 	}
2067 
2068 	// Set the value of the property to whatever is left
2069 	if ( keep.empty() )
2070 	{
2071 		parent->RemoveChild( prop );
2072 	}
2073 	else
2074 	{
2075 
2076 		std::set< wxString >::iterator option;
2077 
2078 		wxString newOptionList;
2079 
2080 		for ( option = keep.begin(); option != keep.end(); ++option )
2081 		{
2082 			newOptionList << wxT( "|" ) << *option;
2083 		}
2084 
2085 		prop->SetText( _STDSTR( newOptionList.substr( 1 ) ) );
2086 	}
2087 }
2088 
NewProject()2089 void ApplicationData::NewProject()
2090 
2091 {
2092 	m_project = m_objDb->CreateObject( "Project" );
2093 	m_selObj = m_project;
2094 	m_modFlag = false;
2095 	m_cmdProc.Reset();
2096 	m_projectFile = wxT( "" );
2097 	SetProjectPath( wxT( "" ) );
2098 	m_ipc->Reset();
2099 	NotifyProjectRefresh();
2100 }
2101 
GenerateCode(bool panelOnly)2102 void ApplicationData::GenerateCode( bool panelOnly )
2103 {
2104 #ifdef USE_FLATNOTEBOOK
2105 	NotifyCodeGeneration( panelOnly );
2106 #else
2107 	NotifyCodeGeneration( panelOnly, true );
2108 #endif
2109 }
2110 
GenerateInheritedClass(PObjectBase form,wxString className,wxString path,wxString file)2111 void ApplicationData::GenerateInheritedClass( PObjectBase form, wxString className, wxString path, wxString file )
2112 {
2113 	try
2114 	{
2115 		PObjectBase project = GetProjectData();
2116 		if ( !project )
2117 		{
2118 			wxLogWarning( _("No Project?!") );
2119 			return;
2120 		}
2121 
2122 		if ( !::wxDirExists( path ) )
2123 		{
2124 			wxLogWarning( _("Invalid Path: %s"), path.c_str() );
2125 			return;
2126 		}
2127 
2128 		PObjectBase obj = m_objDb->CreateObject( "UserClasses", PObjectBase() );
2129 
2130 		PProperty baseNameProp = obj->GetProperty( wxT( "basename" ) );
2131 		PProperty nameProp = obj->GetProperty( wxT( "name" ) );
2132 		PProperty fileProp = obj->GetProperty( wxT( "file" ) );
2133 		PProperty genfileProp = obj->GetProperty( wxT( "gen_file" ) );
2134 		PProperty typeProp = obj->GetProperty( wxT( "type" ) );
2135 
2136 		if ( !( baseNameProp && nameProp && fileProp && typeProp && genfileProp ) )
2137 		{
2138 			wxLogWarning( wxT("Missing Property") );
2139 			return;
2140 		}
2141 
2142         wxFileName inherFile( file );
2143         if ( !inherFile.MakeAbsolute( path ) )
2144         {
2145             wxLogWarning( _("Unable to make \"%s\" absolute to \"%s\""), file.c_str(), path.c_str() );
2146             return;
2147         }
2148 
2149         const wxString& genFileValue = project->GetPropertyAsString( _("file") );
2150         wxFileName genFile( genFileValue );
2151         if ( !genFile.MakeAbsolute( path ) )
2152         {
2153             wxLogWarning( _("Unable to make \"%s\" absolute to \"%s\""), genFileValue.c_str(), path.c_str() );
2154             return;
2155         }
2156 
2157         const wxString& genFileFullPath = genFile.GetFullPath();
2158         if ( !genFile.MakeRelativeTo( inherFile.GetPath( wxPATH_GET_VOLUME ) ) )
2159         {
2160             wxLogWarning( _("Unable to make \"%s\" relative to \"%s\""), genFileFullPath.c_str(), inherFile.GetPath( wxPATH_GET_VOLUME ).c_str() );
2161             return;
2162         }
2163 
2164 		baseNameProp->SetValue( form->GetPropertyAsString( _("name") ) );
2165 		nameProp->SetValue( className );
2166 		fileProp->SetValue( inherFile.GetName() );
2167 		genfileProp->SetValue( genFile.GetFullPath() );
2168 		typeProp->SetValue( form->GetClassName() );
2169 
2170 		// Determine if Microsoft BOM should be used
2171 		bool useMicrosoftBOM = false;
2172 		PProperty pUseMicrosoftBOM = project->GetProperty( _("use_microsoft_bom") );
2173 
2174 		if ( pUseMicrosoftBOM )
2175 		{
2176 			useMicrosoftBOM = ( pUseMicrosoftBOM->GetValueAsInteger() != 0 );
2177 		}
2178 
2179 		// Determine if Utf8 or Ansi is to be created
2180 		bool useUtf8 = false;
2181 		PProperty pUseUtf8 = project->GetProperty( _("encoding") );
2182 
2183 		if ( pUseUtf8 )
2184 		{
2185 			useUtf8 = ( pUseUtf8->GetValueAsString() != wxT("ANSI") );
2186 		}
2187 
2188 		PProperty pCodeGen = project->GetProperty( wxT( "code_generation" ) );
2189 		if ( pCodeGen && TypeConv::FlagSet( wxT("C++"), pCodeGen->GetValue() ) )
2190 		{
2191 			CppCodeGenerator codegen;
2192 			const wxString& fullPath = inherFile.GetFullPath();
2193 			codegen.ParseFiles(fullPath + wxT(".h"), fullPath + wxT(".cpp"));
2194 
2195 			PCodeWriter h_cw( new FileCodeWriter( fullPath + wxT(".h"), useMicrosoftBOM, useUtf8 ) );
2196 			PCodeWriter cpp_cw( new FileCodeWriter( fullPath + wxT(".cpp"), useMicrosoftBOM, useUtf8 ) );
2197 
2198 			codegen.SetHeaderWriter( h_cw );
2199 			codegen.SetSourceWriter( cpp_cw );
2200 
2201 			codegen.GenerateInheritedClass( obj, form );
2202 		}
2203 		else if( pCodeGen && TypeConv::FlagSet( wxT("Python"), pCodeGen->GetValue() ) )
2204 		{
2205 			PythonCodeGenerator codegen;
2206 
2207 			const wxString& fullPath = inherFile.GetFullPath();
2208 			PCodeWriter python_cw( new FileCodeWriter( fullPath + wxT(".py"), useMicrosoftBOM, useUtf8 ) );
2209 
2210 			codegen.SetSourceWriter( python_cw );
2211 
2212 			codegen.GenerateInheritedClass( obj, form );
2213 		}
2214 		else if( pCodeGen && TypeConv::FlagSet( wxT("PHP"), pCodeGen->GetValue() ) )
2215 		{
2216 			PHPCodeGenerator codegen;
2217 
2218 			const wxString& fullPath = inherFile.GetFullPath();
2219 			PCodeWriter php_cw( new FileCodeWriter( fullPath + wxT(".php"), useMicrosoftBOM, useUtf8 ) );
2220 
2221 			codegen.SetSourceWriter( php_cw );
2222 
2223 			codegen.GenerateInheritedClass( obj, form );
2224 		}
2225 		else if( pCodeGen && TypeConv::FlagSet( wxT("Lua"), pCodeGen->GetValue() ) )
2226 		{
2227 			LuaCodeGenerator codegen;
2228 
2229 			const wxString& fullPath = inherFile.GetFullPath();
2230 			PCodeWriter lua_cw( new FileCodeWriter( fullPath + wxT(".lua"), useMicrosoftBOM, useUtf8 ) );
2231 
2232 			codegen.SetSourceWriter( lua_cw );
2233 
2234 			codegen.GenerateInheritedClass( obj, form, genFileFullPath );
2235 		}
2236 
2237 		wxLogStatus( wxT( "Class generated at \'%s\'." ), path.c_str() );
2238 	}
2239 	catch( wxFBException& ex )
2240 	{
2241 		wxLogError( ex.what() );
2242 	}
2243 }
2244 
MovePosition(PObjectBase obj,bool right,unsigned int num)2245 void ApplicationData::MovePosition( PObjectBase obj, bool right, unsigned int num )
2246 {
2247 	PObjectBase noItemObj = obj;
2248 
2249 	PObjectBase parent = obj->GetParent();
2250 
2251 	if ( parent )
2252 	{
2253 		// Si el objeto está incluido dentro de un item hay que desplazar
2254 		// el item
2255 
2256 		while ( parent && parent->GetObjectInfo()->GetObjectType()->IsItem() )
2257 		{
2258 			obj = parent;
2259 			parent = obj->GetParent();
2260 		}
2261 
2262 		unsigned int pos = parent->GetChildPosition( obj );
2263 
2264 		// nos aseguramos de que los límites son correctos
2265 
2266 		unsigned int children_count = parent->GetChildCount();
2267 
2268 		if ( ( right && num + pos < children_count ) ||
2269 		        ( !right  && ( num <= pos ) ) )
2270 		{
2271 			pos = ( right ? pos + num : pos - num );
2272 
2273 			PCommand command( new ShiftChildCmd( obj, pos ) );
2274 			Execute( command ); //m_cmdProc.Execute(command);
2275 			NotifyProjectRefresh();
2276 			SelectObject( noItemObj, true );
2277 
2278 		}
2279 	}
2280 }
2281 
MoveHierarchy(PObjectBase obj,bool up)2282 void ApplicationData::MoveHierarchy( PObjectBase obj, bool up )
2283 {
2284 	PObjectBase sizeritem = obj->GetParent();
2285 	if ( !( sizeritem && sizeritem->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) ) )
2286 	{
2287 		return;
2288 	}
2289 
2290 	PObjectBase nextSizer = sizeritem->GetParent(); // points to the object's sizer
2291 	if ( nextSizer )
2292 	{
2293 		if ( up )
2294 		{
2295 			do
2296 			{
2297 				nextSizer = nextSizer->GetParent();
2298 			}
2299 			while ( nextSizer && !nextSizer->GetObjectInfo()->IsSubclassOf( wxT("sizer") ) && !nextSizer->GetObjectInfo()->IsSubclassOf( wxT("gbsizer") ) );
2300 
2301 			if ( nextSizer && ( nextSizer->GetObjectInfo()->IsSubclassOf( wxT("sizer") ) || nextSizer->GetObjectInfo()->IsSubclassOf( wxT("gbsizer") ) ) )
2302 			{
2303 				PCommand cmdReparent( new ReparentObjectCmd( sizeritem, nextSizer ) );
2304 				Execute( cmdReparent );
2305 				NotifyProjectRefresh();
2306 				SelectObject( obj, true );
2307 			}
2308 		}
2309 		else
2310 		{
2311 			// object will be move to the top sizer of the next sibling object
2312 			// subtree.
2313 			unsigned int pos = nextSizer->GetChildPosition( sizeritem ) + 1;
2314 
2315 			if ( pos < nextSizer->GetChildCount() )
2316 			{
2317 				nextSizer = SearchSizerInto( nextSizer->GetChild( pos ) );
2318 
2319 				if ( nextSizer )
2320 				{
2321 					PCommand cmdReparent( new ReparentObjectCmd( sizeritem, nextSizer ) );
2322 					Execute( cmdReparent );
2323 					NotifyProjectRefresh();
2324 					SelectObject( obj, true );
2325 				}
2326 			}
2327 		}
2328 	}
2329 }
2330 
2331 
Undo()2332 void ApplicationData::Undo()
2333 {
2334 	m_cmdProc.Undo();
2335 	m_modFlag = !m_cmdProc.IsAtSavePoint();
2336 	NotifyProjectRefresh();
2337 	CheckProjectTree( m_project );
2338 	NotifyObjectSelected( GetSelectedObject() );
2339 }
2340 
Redo()2341 void ApplicationData::Redo()
2342 {
2343 	m_cmdProc.Redo();
2344 	m_modFlag = !m_cmdProc.IsAtSavePoint();
2345 	NotifyProjectRefresh();
2346 	CheckProjectTree( m_project );
2347 	NotifyObjectSelected( GetSelectedObject() );
2348 }
2349 
2350 
ToggleExpandLayout(PObjectBase obj)2351 void ApplicationData::ToggleExpandLayout( PObjectBase obj )
2352 {
2353 	if ( !obj )
2354 	{
2355 		return;
2356 	}
2357 
2358 	PObjectBase parent = obj->GetParent();
2359 	if ( !parent )
2360 	{
2361 		return;
2362 	}
2363 
2364 	if ( !parent->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
2365 	{
2366 		return;
2367 	}
2368 
2369 	PProperty propFlag = parent->GetProperty( wxT("flag") );
2370 
2371 	if( !propFlag )
2372 	{
2373 		return;
2374 	}
2375 
2376 	wxString value;
2377 	wxString currentValue = propFlag->GetValueAsString();
2378 
2379 	value =
2380 	    ( TypeConv::FlagSet( wxT("wxEXPAND"), currentValue ) ?
2381 	      TypeConv::ClearFlag( wxT("wxEXPAND"), currentValue ) :
2382 	      TypeConv::SetFlag( wxT("wxEXPAND"), currentValue ) );
2383 
2384 	ModifyProperty( propFlag, value );
2385 }
2386 
ToggleStretchLayout(PObjectBase obj)2387 void ApplicationData::ToggleStretchLayout( PObjectBase obj )
2388 {
2389 	if ( !obj )
2390 	{
2391 		return;
2392 	}
2393 
2394 	PObjectBase parent = obj->GetParent();
2395 	if ( !parent )
2396 	{
2397 		return;
2398 	}
2399 
2400 	if ( parent->GetObjectTypeName() != wxT("sizeritem") && parent->GetObjectTypeName() != wxT("gbsizeritem") )
2401 	{
2402 		return;
2403 	}
2404 
2405 	PProperty proportion = parent->GetProperty( wxT("proportion") );
2406 	if ( !proportion )
2407 	{
2408 		return;
2409 	}
2410 
2411 	wxString value = ( proportion->GetValue() != wxT("0") ? wxT( "0" ) : wxT( "1" ) );
2412 	ModifyProperty( proportion, value );
2413 }
2414 
CheckProjectTree(PObjectBase obj)2415 void ApplicationData::CheckProjectTree( PObjectBase obj )
2416 {
2417 	assert( obj );
2418 
2419 	for ( unsigned int i = 0; i < obj->GetChildCount(); i++ )
2420 	{
2421 		PObjectBase child = obj->GetChild( i );
2422 
2423 		if ( child->GetParent() != obj )
2424         {
2425 #if wxVERSION_NUMBER < 2900
2426 			wxLogError( wxString::Format( wxT( "Parent of object \'%s\' is wrong!" ), child->GetPropertyAsString( wxT( "name" ) ).c_str() ) );
2427 #else
2428 			wxLogError( wxString::Format("Parent of object \'" + child->GetPropertyAsString("name") + "\' is wrong!") );
2429 #endif
2430         }
2431 		CheckProjectTree( child );
2432 	}
2433 }
2434 
GetLayoutSettings(PObjectBase obj,int * flag,int * option,int * border,int * orient)2435 bool ApplicationData::GetLayoutSettings( PObjectBase obj, int *flag, int *option, int *border, int* orient )
2436 {
2437 	if ( !obj )
2438 	{
2439 		return false;
2440 	}
2441 
2442 	PObjectBase parent = obj->GetParent();
2443 	if ( !parent )
2444 	{
2445 		return false;
2446 	}
2447 
2448 	if ( parent->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
2449 	{
2450 		PProperty propOption = parent->GetProperty( wxT("proportion") );
2451 		if ( propOption )
2452 		{
2453 			*option = propOption->GetValueAsInteger();
2454 		}
2455 
2456 		*flag = parent->GetPropertyAsInteger( wxT("flag") );
2457 		*border = parent->GetPropertyAsInteger( wxT("border") );
2458 
2459 		PObjectBase sizer = parent->GetParent();
2460 		if ( sizer )
2461 		{
2462 			wxString parentName = sizer->GetClassName();
2463 			if ( wxT("wxBoxSizer") == parentName || wxT("wxStaticBoxSizer") == parentName )
2464 			{
2465 				PProperty propOrient = sizer->GetProperty( wxT("orient") );
2466 				if ( propOrient )
2467 				{
2468 					*orient = propOrient->GetValueAsInteger();
2469 				}
2470 			}
2471 		}
2472 		return true;
2473 	}
2474 
2475 	return false;
2476 }
2477 
ChangeAlignment(PObjectBase obj,int align,bool vertical)2478 void ApplicationData::ChangeAlignment ( PObjectBase obj, int align, bool vertical )
2479 {
2480 	if ( !obj )
2481 	{
2482 		return;
2483 	}
2484 
2485 	PObjectBase parent = obj->GetParent();
2486 	if ( !parent )
2487 	{
2488 		return;
2489 	}
2490 
2491 	if ( !parent->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
2492 	{
2493 		return;
2494 	}
2495 
2496 	PProperty propFlag = parent->GetProperty( wxT( "flag" ) );
2497 
2498 	if ( !propFlag )
2499 	{
2500 		return;
2501 	}
2502 
2503 	wxString value = propFlag->GetValueAsString();
2504 
2505 	// Primero borramos los flags de la configuración previa, para así
2506 	// evitar conflictos de alineaciones.
2507 
2508 	if ( vertical )
2509 	{
2510 		value = TypeConv::ClearFlag( wxT( "wxALIGN_TOP" ), value );
2511 		value = TypeConv::ClearFlag( wxT( "wxALIGN_BOTTOM" ), value );
2512 		value = TypeConv::ClearFlag( wxT( "wxALIGN_CENTER_VERTICAL" ), value );
2513 	}
2514 	else
2515 	{
2516 		value = TypeConv::ClearFlag( wxT( "wxALIGN_LEFT" ), value );
2517 		value = TypeConv::ClearFlag( wxT( "wxALIGN_RIGHT" ), value );
2518 		value = TypeConv::ClearFlag( wxT( "wxALIGN_CENTER_HORIZONTAL" ), value );
2519 	}
2520 
2521 	wxString alignStr;
2522 
2523 	switch ( align )
2524 	{
2525 
2526 		case wxALIGN_RIGHT:
2527 			alignStr = wxT( "wxALIGN_RIGHT" );
2528 
2529 			break;
2530 
2531 		case wxALIGN_CENTER_HORIZONTAL:
2532 			alignStr = wxT( "wxALIGN_CENTER_HORIZONTAL" );
2533 
2534 			break;
2535 
2536 		case wxALIGN_BOTTOM:
2537 			alignStr = wxT( "wxALIGN_BOTTOM" );
2538 
2539 			break;
2540 
2541 		case wxALIGN_CENTER_VERTICAL:
2542 			alignStr = wxT( "wxALIGN_CENTER_VERTICAL" );
2543 
2544 			break;
2545 	}
2546 
2547 	value = TypeConv::SetFlag( alignStr, value );
2548 
2549 	ModifyProperty( propFlag, value );
2550 }
2551 
ToggleBorderFlag(PObjectBase obj,int border)2552 void ApplicationData::ToggleBorderFlag( PObjectBase obj, int border )
2553 {
2554 	if ( !obj )
2555 	{
2556 		return;
2557 	}
2558 
2559 	PObjectBase parent = obj->GetParent();
2560 	if ( !parent )
2561 	{
2562 		return;
2563 	}
2564 
2565 	if ( !parent->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
2566 	{
2567 		return;
2568 	}
2569 
2570 	PProperty propFlag = parent->GetProperty( wxT( "flag" ) );
2571 
2572 	if ( !propFlag )
2573 	{
2574 		return;
2575 	}
2576 
2577 	wxString value = propFlag->GetValueAsString();
2578 
2579 	value = TypeConv::ClearFlag( wxT( "wxALL" ), value );
2580 	value = TypeConv::ClearFlag( wxT( "wxTOP" ), value );
2581 	value = TypeConv::ClearFlag( wxT( "wxBOTTOM" ), value );
2582 	value = TypeConv::ClearFlag( wxT( "wxRIGHT" ), value );
2583 	value = TypeConv::ClearFlag( wxT( "wxLEFT" ), value );
2584 
2585 	int intVal = propFlag->GetValueAsInteger();
2586 	intVal ^= border;
2587 
2588 	if ( ( intVal & wxALL ) == wxALL )
2589 		value = TypeConv::SetFlag( wxT( "wxALL" ), value );
2590 	else
2591 	{
2592 		if ( ( intVal & wxTOP ) != 0 ) value = TypeConv::SetFlag( wxT( "wxTOP" ), value );
2593 
2594 		if ( ( intVal & wxBOTTOM ) != 0 ) value = TypeConv::SetFlag( wxT( "wxBOTTOM" ), value );
2595 
2596 		if ( ( intVal & wxRIGHT ) != 0 ) value = TypeConv::SetFlag( wxT( "wxRIGHT" ), value );
2597 
2598 		if ( ( intVal & wxLEFT ) != 0 ) value = TypeConv::SetFlag( wxT( "wxLEFT" ), value );
2599 	}
2600 
2601 	ModifyProperty( propFlag, value );
2602 }
2603 
CreateBoxSizerWithObject(PObjectBase obj)2604 void ApplicationData::CreateBoxSizerWithObject( PObjectBase obj )
2605 {
2606 	PObjectBase parent = obj->GetParent();
2607 	if ( !parent )
2608 	{
2609 		return;
2610 	}
2611 
2612 	PObjectBase grandParent = parent->GetParent();
2613 	if ( !grandParent )
2614 	{
2615 		return;
2616 	}
2617 
2618 	int childPos = -1;
2619 	if ( parent->GetObjectInfo()->IsSubclassOf( wxT("sizeritembase") ) )
2620 	{
2621 		childPos = (int)grandParent->GetChildPosition( parent );
2622 		parent = grandParent;
2623 	}
2624 
2625 	// Must first cut the old object in case it is the only allowable object
2626 	PObjectBase clipboard = m_clipboard;
2627 	CutObject( obj );
2628 
2629 	// Create the wxBoxSizer
2630 	PObjectBase newSizer = m_objDb->CreateObject( "wxBoxSizer", parent );
2631 
2632 	if ( newSizer )
2633 	{
2634 		PCommand cmd( new InsertObjectCmd( this, newSizer, parent, childPos ) );
2635 		Execute( cmd );
2636 
2637 		if ( newSizer->GetObjectTypeName() == wxT("sizeritem") )
2638 			newSizer = newSizer->GetChild( 0 );
2639 
2640 		PasteObject( newSizer );
2641 		m_clipboard = clipboard;
2642 
2643 		//NotifyProjectRefresh();
2644 	}
2645 	else
2646 	{
2647 		Undo();
2648 		m_clipboard = clipboard;
2649 	}
2650 }
2651 
ShowXrcPreview()2652 void ApplicationData::ShowXrcPreview()
2653 {
2654 	PObjectBase form = GetSelectedForm();
2655 
2656 	if ( form == NULL )
2657 	{
2658 		wxMessageBox( wxT( "Please select a form and try again." ), wxT( "XRC Preview" ), wxICON_ERROR );
2659 		return;
2660 	}
2661 	else if( form->GetPropertyAsInteger( wxT("aui_managed") ) )
2662 	{
2663 		wxMessageBox( wxT( "XRC preview doesn't support AUI-managed frames." ), wxT( "XRC Preview" ), wxICON_ERROR );
2664 		return;
2665 	}
2666 
2667 	XRCPreview::Show( form, GetProjectPath() );
2668 }
2669 
CanPasteObject()2670 bool ApplicationData::CanPasteObject()
2671 {
2672 	PObjectBase obj = GetSelectedObject();
2673 
2674 	if ( obj && obj->GetObjectTypeName() != wxT( "project" ) )
2675 		return ( m_clipboard != NULL );
2676 
2677 	return false;
2678 }
2679 
CanCopyObject()2680 bool ApplicationData::CanCopyObject()
2681 {
2682 	PObjectBase obj = GetSelectedObject();
2683 
2684 	if ( obj && obj->GetObjectTypeName() != wxT( "project" ) )
2685 		return true;
2686 
2687 	return false;
2688 }
2689 
IsModified()2690 bool ApplicationData::IsModified()
2691 {
2692 	return m_modFlag;
2693 }
2694 
Execute(PCommand cmd)2695 void ApplicationData::Execute( PCommand cmd )
2696 {
2697 	m_modFlag = true;
2698 	m_cmdProc.Execute( cmd );
2699 }
2700 
2701 //////////////////////////////////////////////////////////////////////////////
AddHandler(wxEvtHandler * handler)2702 void ApplicationData::AddHandler( wxEvtHandler* handler )
2703 {
2704 	m_handlers.push_back( handler );
2705 }
2706 
RemoveHandler(wxEvtHandler * handler)2707 void ApplicationData::RemoveHandler( wxEvtHandler* handler )
2708 {
2709 	for ( HandlerVector::iterator it = m_handlers.begin(); it != m_handlers.end(); ++it )
2710 	{
2711 		if ( *it == handler )
2712 		{
2713 			m_handlers.erase( it );
2714 			break;
2715 		}
2716 	}
2717 }
2718 
NotifyEvent(wxFBEvent & event,bool forcedelayed)2719 void ApplicationData::NotifyEvent( wxFBEvent& event, bool forcedelayed )
2720 {
2721 
2722 	if ( !forcedelayed )
2723 	{
2724 		LogDebug( "event: %s", event.GetEventName().c_str() );
2725 
2726 		std::vector< wxEvtHandler* >::iterator handler;
2727 
2728 		for ( handler = m_handlers.begin(); handler != m_handlers.end(); handler++ )
2729 		{
2730 			( *handler )->ProcessEvent( event );
2731 		}
2732 	}
2733 	else
2734 	{
2735 		LogDebug( "Pending event: %s", event.GetEventName().c_str() );
2736 
2737 		std::vector< wxEvtHandler* >::iterator handler;
2738 
2739 		for ( handler = m_handlers.begin(); handler != m_handlers.end(); handler++ )
2740 		{
2741 			( *handler )->AddPendingEvent( event );
2742 		}
2743 	}
2744 }
2745 
NotifyProjectLoaded()2746 void ApplicationData::NotifyProjectLoaded()
2747 {
2748 	wxFBEvent event( wxEVT_FB_PROJECT_LOADED );
2749 	NotifyEvent( event );
2750 }
2751 
NotifyProjectSaved()2752 void ApplicationData::NotifyProjectSaved()
2753 {
2754 	wxFBEvent event( wxEVT_FB_PROJECT_SAVED );
2755 	NotifyEvent( event );
2756 }
2757 
NotifyObjectExpanded(PObjectBase obj)2758 void ApplicationData::NotifyObjectExpanded( PObjectBase obj )
2759 {
2760 	wxFBObjectEvent event( wxEVT_FB_OBJECT_EXPANDED, obj );
2761 	NotifyEvent( event );
2762 }
2763 
NotifyObjectSelected(PObjectBase obj,bool force)2764 void ApplicationData::NotifyObjectSelected( PObjectBase obj, bool force )
2765 {
2766 	wxFBObjectEvent event( wxEVT_FB_OBJECT_SELECTED, obj );
2767 	if( force ) event.SetString( wxT("force") );
2768 
2769 	NotifyEvent( event );
2770 }
2771 
NotifyObjectCreated(PObjectBase obj)2772 void ApplicationData::NotifyObjectCreated( PObjectBase obj )
2773 {
2774 	wxFBObjectEvent event( wxEVT_FB_OBJECT_CREATED, obj );
2775 	NotifyEvent( event );
2776 }
2777 
NotifyObjectRemoved(PObjectBase obj)2778 void ApplicationData::NotifyObjectRemoved( PObjectBase obj )
2779 {
2780 	wxFBObjectEvent event( wxEVT_FB_OBJECT_REMOVED, obj );
2781 	NotifyEvent( event );
2782 }
2783 
NotifyPropertyModified(PProperty prop)2784 void ApplicationData::NotifyPropertyModified( PProperty prop )
2785 {
2786 	wxFBPropertyEvent event( wxEVT_FB_PROPERTY_MODIFIED, prop );
2787 	NotifyEvent( event );
2788 }
2789 
NotifyEventHandlerModified(PEvent evtHandler)2790 void ApplicationData::NotifyEventHandlerModified( PEvent evtHandler )
2791 {
2792 	wxFBEventHandlerEvent event( wxEVT_FB_EVENT_HANDLER_MODIFIED, evtHandler );
2793 	NotifyEvent( event );
2794 }
2795 
NotifyCodeGeneration(bool panelOnly,bool forcedelayed)2796 void ApplicationData::NotifyCodeGeneration( bool panelOnly, bool forcedelayed )
2797 {
2798 	wxFBEvent event( wxEVT_FB_CODE_GENERATION );
2799 
2800 	// Using the previously unused Id field in the event to carry a boolean
2801 	event.SetId( ( panelOnly ? 1 : 0 ) );
2802 
2803 	NotifyEvent( event, forcedelayed );
2804 }
2805 
NotifyProjectRefresh()2806 void ApplicationData::NotifyProjectRefresh()
2807 {
2808 	wxFBEvent event( wxEVT_FB_PROJECT_REFRESH );
2809 	NotifyEvent( event );
2810 }
2811 
VerifySingleInstance(const wxString & file,bool switchTo)2812 bool ApplicationData::VerifySingleInstance( const wxString& file, bool switchTo )
2813 {
2814 	return m_ipc->VerifySingleInstance( file, switchTo );
2815 }
2816 
GetPathProperty(const wxString & pathName)2817 wxString ApplicationData::GetPathProperty( const wxString& pathName )
2818 {
2819 	PObjectBase project = GetProjectData();
2820 	wxFileName path;
2821 	// Get the output path
2822 	PProperty ppath = project->GetProperty( pathName );
2823 
2824 	if ( ppath )
2825 	{
2826 		wxString pathEntry = ppath->GetValue();
2827 
2828 		if ( pathEntry.empty() )
2829 		{
2830 			THROW_WXFBEX( wxT( "You must set the \"") + pathName + wxT("\" property of the project to a valid path for output files" ) );
2831 		}
2832 
2833 		path = wxFileName::DirName( pathEntry );
2834 
2835 		if ( !path.IsAbsolute() )
2836 		{
2837 			wxString projectPath = AppData()->GetProjectPath();
2838 
2839 			if ( projectPath.empty() )
2840 			{
2841 				THROW_WXFBEX( wxT( "You must save the project when using a relative path for output files" ) );
2842 			}
2843 
2844 			path = wxFileName(  projectPath +
2845 								wxFileName::GetPathSeparator() +
2846 								pathEntry +
2847 								wxFileName::GetPathSeparator() );
2848 
2849 			path.Normalize();
2850 
2851 			// this approach is probably incorrect if the fb project is located under a symlink
2852 			/*path.SetCwd( projectPath );
2853 			path.MakeAbsolute();*/
2854 		}
2855 	}
2856 
2857 	if ( !path.DirExists() )
2858 	{
2859 		THROW_WXFBEX( wxT( "Invalid Path: " ) << path.GetPath() << wxT( "\nYou must set the \"") + pathName + wxT("\" property of the project to a valid path for output files" ) );
2860 	}
2861 
2862 	return path.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2863 }
2864 
GetOutputPath()2865 wxString ApplicationData::GetOutputPath()
2866 {
2867 	return GetPathProperty( wxT("path") );
2868 }
2869 
GetEmbeddedFilesOutputPath()2870 wxString ApplicationData::GetEmbeddedFilesOutputPath()
2871 {
2872 	return GetPathProperty( wxT("embedded_files_path") );
2873 }
2874 
GetPropertiesToRemove_v1_12(void) const2875 ApplicationData::PropertiesToRemove& ApplicationData::GetPropertiesToRemove_v1_12( void ) const
2876 {
2877 	static PropertiesToRemove propertiesToRemove;
2878 	if( propertiesToRemove.empty() )
2879 	{
2880 		propertiesToRemove[ "Dialog" ].insert( "BottomDockable" );
2881 		propertiesToRemove[ "Dialog" ].insert( "LeftDockable" );
2882 		propertiesToRemove[ "Dialog" ].insert( "RightDockable" );
2883 		propertiesToRemove[ "Dialog" ].insert( "TopDockable" );
2884 		propertiesToRemove[ "Dialog" ].insert( "caption_visible" );
2885 		propertiesToRemove[ "Dialog" ].insert( "center_pane" );
2886 		propertiesToRemove[ "Dialog" ].insert( "close_button" );
2887 		propertiesToRemove[ "Dialog" ].insert( "default_pane" );
2888 		propertiesToRemove[ "Dialog" ].insert( "dock" );
2889 		propertiesToRemove[ "Dialog" ].insert( "dock_fixed" );
2890 		propertiesToRemove[ "Dialog" ].insert( "docking" );
2891 		propertiesToRemove[ "Dialog" ].insert( "floatable" );
2892 		propertiesToRemove[ "Dialog" ].insert( "gripper" );
2893 		propertiesToRemove[ "Dialog" ].insert( "maximize_button" );
2894 		propertiesToRemove[ "Dialog" ].insert( "minimize_button" );
2895 		propertiesToRemove[ "Dialog" ].insert( "moveable" );
2896 		propertiesToRemove[ "Dialog" ].insert( "pane_border" );
2897 		propertiesToRemove[ "Dialog" ].insert( "pin_button" );
2898 		propertiesToRemove[ "Dialog" ].insert( "resize" );
2899 		propertiesToRemove[ "Dialog" ].insert( "show" );
2900 		propertiesToRemove[ "Dialog" ].insert( "toolbar_pane" );
2901 		propertiesToRemove[ "Dialog" ].insert( "validator_style" );
2902 		propertiesToRemove[ "Dialog" ].insert( "validator_type" );
2903 		propertiesToRemove[ "Dialog" ].insert( "aui_name" );
2904 
2905 		propertiesToRemove[ "Panel" ].insert( "BottomDockable" );
2906 		propertiesToRemove[ "Panel" ].insert( "LeftDockable" );
2907 		propertiesToRemove[ "Panel" ].insert( "RightDockable" );
2908 		propertiesToRemove[ "Panel" ].insert( "TopDockable" );
2909 		propertiesToRemove[ "Panel" ].insert( "caption_visible" );
2910 		propertiesToRemove[ "Panel" ].insert( "center_pane" );
2911 		propertiesToRemove[ "Panel" ].insert( "close_button" );
2912 		propertiesToRemove[ "Panel" ].insert( "default_pane" );
2913 		propertiesToRemove[ "Panel" ].insert( "dock" );
2914 		propertiesToRemove[ "Panel" ].insert( "dock_fixed" );
2915 		propertiesToRemove[ "Panel" ].insert( "docking" );
2916 		propertiesToRemove[ "Panel" ].insert( "floatable" );
2917 		propertiesToRemove[ "Panel" ].insert( "gripper" );
2918 		propertiesToRemove[ "Panel" ].insert( "maximize_button" );
2919 		propertiesToRemove[ "Panel" ].insert( "minimize_button" );
2920 		propertiesToRemove[ "Panel" ].insert( "moveable" );
2921 		propertiesToRemove[ "Panel" ].insert( "pane_border" );
2922 		propertiesToRemove[ "Panel" ].insert( "pin_button" );
2923 		propertiesToRemove[ "Panel" ].insert( "resize" );
2924 		propertiesToRemove[ "Panel" ].insert( "show" );
2925 		propertiesToRemove[ "Panel" ].insert( "toolbar_pane" );
2926 		propertiesToRemove[ "Panel" ].insert( "validator_style" );
2927 		propertiesToRemove[ "Panel" ].insert( "validator_type" );
2928 
2929 		propertiesToRemove[ "wxStaticText" ].insert( "validator_style" );
2930 		propertiesToRemove[ "wxStaticText" ].insert( "validator_type" );
2931 		propertiesToRemove[ "CustomControl" ].insert( "validator_style" );
2932 		propertiesToRemove[ "CustomControl" ].insert( "validator_type" );
2933 		propertiesToRemove[ "wxAuiNotebook" ].insert( "validator_style" );
2934 		propertiesToRemove[ "wxAuiNotebook" ].insert( "validator_type" );
2935 		propertiesToRemove[ "wxPanel" ].insert( "validator_style" );
2936 		propertiesToRemove[ "wxPanel" ].insert( "validator_type" );
2937 		propertiesToRemove[ "wxToolBar" ].insert( "validator_style" );
2938 		propertiesToRemove[ "wxToolBar" ].insert( "validator_type" );
2939 		propertiesToRemove[ "wxStyledTextCtrl" ].insert( "use_wxAddition" );
2940 		propertiesToRemove[ "wxStyledTextCtrl" ].insert( "validator_style" );
2941 		propertiesToRemove[ "wxStyledTextCtrl" ].insert( "validator_type" );
2942 		propertiesToRemove[ "wxPropertyGridManager" ].insert( "use_wxAddition" );
2943 		propertiesToRemove[ "wxPropertyGridManager" ].insert( "validator_style" );
2944 		propertiesToRemove[ "wxPropertyGridManager" ].insert( "validator_type" );
2945 
2946 		propertiesToRemove[ "wxadditions::wxTreeListCtrl" ].insert( "validator_style" );
2947 		propertiesToRemove[ "wxadditions::wxTreeListCtrl" ].insert( "validator_type" );
2948 	}
2949 	return propertiesToRemove;
2950 }
2951