/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/01/20
// RCS-ID:      $Id: eventeditor.cpp,v 1.12 2001/04/25 02:48:13 georgetasker Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:     wxWindows license
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "editorcmn.cpp"
#pragma interface "editorcmn.cpp"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "wx/pmf/srceditordoc.h"

#include "eventeditor.h"
#include "eventgen.h"
#include "res_doc.h"
#include "txtrecset.h"

#include "membereditor.h"

#include "mimetypes.h"

// sorry, 4 .cpp's and .h's of AWT-layouts contrib. needed to compile this .cpp!

#include "wx/awtlay/awt_emul.h"
#include "wx/awtlay/gridbaglayout.h"
#include "wx/awtlay/flowlayout.h"

EventEntryInfo* CreateEventEntryInteractively( EventInfo* pInfo, const wxString& id )
{
	wxString hint = "On";
	wxString name = pInfo->mEventMacro;

	size_t i = 0; size_t len = name.Length();

	while( i < len && name[i] != '_' ) ++i;

	++i; // skip '_'

	do
	{
		if ( i < len ) 
		{
			hint += name[i]; ++i;
		}

		while( i < len && name[i] != '_' ) 
		{
			hint += wxString( name[i] ).MakeLower();
			++i;
		}

		++i; // skip '-';

	} while( i < len );

	if ( id != "" )
	{
		wxString suffix = id.Lower();
		suffix.SetChar( 0, wxString( suffix[0u] ).Upper()[0u] );

		hint += suffix;
	}

	wxTextEntryDialog dialog( wxPMBootSvc().GetMainWindow(), "Member function &name:",
	"Add Event-Handling Method", hint, wxOK|wxCANCEL);

	if (dialog.ShowModal() == wxID_OK)
	{
		// TBD:: make sure the method name is unique!

		EventEntryInfo& entry = *new EventEntryInfo();

		entry.mpEventInfo = pInfo;
		entry.mMethod = dialog.GetValue();
		entry.mId1 = id;

		return &entry;
	}

	return NULL;
}


/***** Implementation for class EventEditorService *****/

static wxCommandInfo _gEventEditorCommands[] = {

	wxCommandInfo( EventEditorService::ID_NEW_SOURCE,  "&New...", "", "" ), 
	wxCommandInfo( EventEditorService::ID_SOURCE_SETTINGS,  "&Settings...", "", "" ), 
	wxCommandInfo( EventEditorService::ID_EDIT_MEMBERS, "&Membe&rs...", "", "Ctrl+Q" ), 
	wxCommandInfo( EventEditorService::ID_EDIT_EVENTS,  "&Events...", "", "Ctrl+E" ), 
	wxCommandInfo( EventEditorService::ID_EDIT_WIDGET,  "&Window",     "", "Ctrl+W" ), 
	wxCommandInfo( EventEditorService::ID_EDIT_MENU,   "Men&u", "", "" ), 

	wxCommandInfo( 0, "" ) // terminator
};

static wxPMMergableMenuChain _gEventEditorChains[] = {

	// ag: moved back to top-level menus for now
	wxPMMergableMenuChain( "/&Source/", _gEventEditorCommands ),

	wxPMMergableMenuChain( "", NULL ) // terminator
};

IMPLEMENT_DYNAMIC_CLASS( EventEditorService, wxEvtHandler )

BEGIN_EVENT_TABLE( EventEditorService, wxEvtHandler )

	EVT_MENU( ID_NEW_SOURCE,		EventEditorService::OnNewSource )
	EVT_MENU( ID_SOURCE_SETTINGS,	EventEditorService::OnSourceSettings )
	EVT_MENU( ID_EDIT_EVENTS,		EventEditorService::OnEditEvents )
	EVT_MENU( ID_EDIT_MEMBERS,		EventEditorService::OnEditMembers )
	EVT_MENU( ID_EDIT_WIDGET,		EventEditorService::OnEditWidget )
	EVT_MENU( ID_EDIT_MENU,			EventEditorService::OnEditMenu )

	EVT_UPDATE_UI( ID_NEW_SOURCE,		EventEditorService::OnNewSourceUI )
	EVT_UPDATE_UI( ID_SOURCE_SETTINGS,	EventEditorService::OnSourceSettingsUI )
	EVT_UPDATE_UI( ID_EDIT_EVENTS,		EventEditorService::OnEditEventsUI )
	EVT_UPDATE_UI( ID_EDIT_MEMBERS,		EventEditorService::OnEditMembersUI )
	EVT_UPDATE_UI( ID_EDIT_WIDGET,		EventEditorService::OnEditWidgetUI )
	EVT_UPDATE_UI( ID_EDIT_MENU,		EventEditorService::OnEditMenuUI )

END_EVENT_TABLE()

EventEditorService::EventEditorService()

	: mpProc( NULL )
{
	SetRefData( (wxObjectRefData*)(wxPMService*)this );
}

EventEditorService::~EventEditorService()
{
	SetRefData( NULL );

	if ( mpProc ) delete mpProc;
}

bool EventEditorService::Start()
{
	mpProc = new GenSourceProcessor();

	wxString sd = wxPMBootSvc().GetStartupDir();

    wxString fname = sd + wxString(wxFILE_SEP_PATH) + "config_srctempl.txt";

	wxString txt = LoadFileContent( fname );

    if ( !mpProc->ProcessConfigContent( txt ) )
    {
        wxString errmsgStr;
        errmsgStr.Printf("Source-generation templates file '%s'\nwas unable to be loaded.\n\nIt may be missing or corrupt.  Please check that\nthis file is in the wxWorkshop program directory.",fname.c_str());
        wxMessageBox(errmsgStr.c_str(),wxT("ATTENTION!"));
		return FALSE;
    }

	return TRUE;
}

bool EventEditorService::Stop()
{
	return TRUE;
}

wxObject* EventEditorService::GetWxObject()
{
	return (wxObject*)this;
}

wxPMMergableMenuChain* EventEditorService::GetMergableMenuChain()
{
	return _gEventEditorChains;
}

GenSourceProcessor& EventEditorService::GetSrcProcessor()
{
	return *mpProc;
}

void EventEditorService::EditEventBody( const wxString& id, 
										const wxString& eventMacro )
{
	if ( !ValidateDocument() ) return;

	if ( !ProcessDocument() ) return;

	EventEntryInfoListT& entries = mpProc->GetEvents();

	EventEntryInfo* pEntry = NULL;

	for( size_t i = 0; i != entries.Count(); ++i )
	{
		EventEntryInfo& entry = *entries[i];

		if ( entry.mpEventInfo && entry.mpEventInfo->mEventMacro == eventMacro 
			 && entry.mId1 == id )
		{
			pEntry = &entry;
			break;
		}
	}

	if ( !pEntry )
	{
		EventInfo* pEventInfo = EventInfo::FindEventInfoByMacro( eventMacro );
		pEntry = CreateEventEntryInteractively( pEventInfo, id );

		if ( !pEntry )

			return;

		entries.Add( pEntry );

		mpProc->ReGenerateSources();
		ApplySourceChanges();
	}

	size_t lineNo = mpProc->GetSourceCodeLineNoForEvent( pEntry );

	if ( lineNo != (size_t)(-1) )
	{
		// FIMXE:: HACK:: more hacks...

		size_t pos = 1;
		if ( mpProc->GetImpSource().mpTempl->mLang == "Python" )

			pos = 4;

		GotoSourceLine( mpProc->GetImpSource().mFName, lineNo, pos );
	}
	else
		wxMessageBox( wxT("ERROR: body of event-handler method not found!") );
}

// event handlers

void EventEditorService::OnNewSource( wxCommandEvent& event )
{
	mpProc->InitScaner();

	SourceConfigInfo cfg;
	SourceConfigDialog dlg( wxPMBootSvc().GetMainWindow(),
							&cfg, this, "New source", TRUE );

	int result = dlg.ShowModal();

	if ( result == wxID_OK )
	{
		dlg.ExchangeValuesBack();

		GenSourceTemplate* pTempl = mpProc->FindTemplate( cfg.mTemplate );

		if ( !pTempl )
		{
			wxMessageBox( wxT("You must select a valid template") );

			return;
		}

		mpProc->GenerateNewSources( cfg.mFName, cfg.mClassName,
									cfg.mResFile, cfg.mWindow,
									cfg.mMenu, *pTempl );

		wxString cwd = ::wxGetCwd();

		if ( cwd.Length() && cwd[ cwd.Length() - 1 ] != wxFILE_SEP_PATH )

			cwd += wxFILE_SEP_PATH;

		wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();

		wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

		wxPMFileInfo* pImpFile = new wxPMFileInfo( cwd + mpProc->GetImpSource().mFName );
		wxPMFileInfo* pHdrFile = NULL;

		if ( !pPrj->AddFile( pImpFile ) )

			return;
		
		if ( pTempl->mHasHeader )
		{
			pHdrFile = new wxPMFileInfo( cwd + mpProc->GetHdrSource().mFName );

			if ( !pPrj->AddFile( pHdrFile ) )

				return;
		}

		mpProc->FlushSourcesToDisk();

		mgr.OpenDocument( *pImpFile, pPrj );

		if ( pHdrFile )

			mgr.OpenDocument( *pHdrFile, pPrj );

		ResDocument* pResDoc = (ResDocument*)cfg.mpResDoc;
		wxASSERT( pResDoc ); // DBG::
		pResDoc->SetItemSubclass( cfg.mWindow, cfg.mClassName );

		mpProc->InitScaner(); // reset temporary data
	}
}

void EventEditorService::OnSourceSettings( wxCommandEvent& event )
{
	if ( !ValidateDocument() )
        return;

	if ( !ProcessDocument() )
        return;

	SourceConfigInfo cfg;
	GenSourceInfo& info = mpProc->GetImpSource();

	cfg.mTemplate = info.mpTempl->mName;
	cfg.mResFile = info.mResFile;
	cfg.mWindow = info.mWndRes;
	cfg.mMenu = info.mMenuRes;
	cfg.mClassName = info.mClassName;
	cfg.mFName = wxPMFileInfo( info.mFName ).GetNameWithoutExtension();

	SourceConfigDialog dlg( wxPMBootSvc().GetMainWindow(),
							&cfg, this, "Source settings", FALSE );

	if ( dlg.ShowModal() == wxID_OK )
	{
		dlg.ExchangeValuesBack();

		mpProc->SetResourceFile( cfg.mResFile );
		mpProc->SetWindowResource( cfg.mWindow );
		mpProc->SetMenuResource( cfg.mMenu );

		mpProc->ReGenerateSources();

		ApplySourceChanges();

		ResDocument* pResDoc = (ResDocument*)cfg.mpResDoc;
		wxASSERT( pResDoc ); // DBG::
		pResDoc->SetItemSubclass( cfg.mWindow, cfg.mClassName );
	}
}

void EventEditorService::OnEditEvents( wxCommandEvent& event )
{
	DoEditSource( FALSE );
}

void EventEditorService::OnEditMembers( wxCommandEvent& event )
{
	DoEditSource( TRUE );
}

void EventEditorService::DoEditSource( bool editMembers )
{
	if ( !ValidateDocument() )
        return;

	if ( !ProcessDocument() )
        return;

	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();

	wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

	wxPMFileInfo* pFile = pPrj->FindFile( mpProc->GetImpSource().mResFile );

	if ( !pFile )
        return;

	wxPMDocument* pDoc = mgr.OpenDocument( *pFile, pPrj, 
										   FALSE // instructs opening it scilently,
												 // without activating
										 );

	if ( !pDoc )
        return;

	wxASSERT( pDoc->IsKindOf( CLASSINFO( ResDocument ) ) );

	ResDocument* pResDoc = (ResDocument*)pDoc;
	    
	ResourceItemInfo parentRes;
	parentRes.mId = mpProc->GetImpSource().mWndRes;
	parentRes.mClass = pResDoc->GetItemClassById( parentRes.mId );

	wxStringList ids, classes, subclasses;
	pResDoc->GetSubItemIds( parentRes.mId, ids, classes, subclasses );
	pResDoc->GetSubItemIds( mpProc->GetImpSource().mMenuRes, ids, classes, subclasses );

	ResourceItemInfoListT& resLst = mpProc->GetResourceItems();

    size_t i;
	for( i = 0; i != (size_t)ids.Number(); ++i )
	{
		ResourceItemInfo* pInfo = new ResourceItemInfo();
		pInfo->mClass = classes[i];
		pInfo->mSubclass = subclasses[i];
		pInfo->mId = ids[i];

		resLst.Add( pInfo );
	}

	mpProc->PrepareResourceItems();
	mpProc->SetCommonSourceVars( mpProc->GetImpSource(), *mpProc->GetProcessorTemplate() );
	mpProc->ProcessBindings( mpProc->GetImpSource() );

	if ( mpProc->GetImpSource().mpTempl->mHasHeader  )

		mpProc->ProcessBindings( mpProc->GetHdrSource() );

	SourceWizardDialog* pDlg = new SourceWizardDialog( wxPMBootSvc().GetMainWindow(), mpProc, &parentRes, editMembers );
	
	int result = pDlg->ShowModal();

	if ( result == wxID_OK || result == ID_EDIT_CODE )
	{
		wxString id, macro;
		EventEntryInfo* pEntry = pDlg->GetEventEditor()->GetSelectedEntry();

		if ( pEntry )
		{
			id = pEntry->mId1;
			macro = pEntry->mpEventInfo->mEventMacro;
		}

		mpProc->ReGenerateSources();
		ApplySourceChanges();

		if ( result == ID_EDIT_CODE )
		
			EditEventBody( id, macro );

		wxPMBootSvc().GetMainWindow()->Refresh();
	}


	mpProc->InitScaner(); // reset temporary data

	WX_CLEAR_ARRAY( resLst );
	pDlg->Destroy();
}

void EventEditorService::OnEditWidget( wxCommandEvent& event )
{
	if ( !ValidateDocument() )
        return;
	if ( !ProcessDocument() )
        return;

	GenSourceInfo& info = mpProc->GetImpSource();

	if ( info.mWndRes == "" )
	{
		wxMessageBox( mpProc->GetImpSource().mClassName + 
					  " is not bound to any window-resource\n. Use Source-Settings to associated it with resource item" );

		return;
	}

	ResDocument* pDoc = FindResourceDocument( info.mResFile );
	
	if ( !pDoc )
	{
		wxMessageBox( "ERROR: resource file " + info.mResFile +
					  " not found in this project!" );

		return;
	}

	pDoc->ActivateEditorForItem( info.mWndRes );
}

void EventEditorService::OnEditMenu( wxCommandEvent& event )
{
	if ( !ValidateDocument() )
        return;
	if ( !ProcessDocument() )
        return;

	GenSourceInfo& info = mpProc->GetImpSource();

	if ( info.mMenuRes == "" )
	{
		wxMessageBox( info.mClassName + 
					  " is not bound to any menubar-resource\n. Use Source-Settings to associated it with resource item" );

		return;
	}

	ResDocument* pDoc = FindResourceDocument( info.mResFile );
	
	if ( !pDoc )
	{
		wxMessageBox( "ERROR: resource file " + info.mResFile +
					  " not found in this project!" );

		return;
	}

	pDoc->ActivateEditorForItem( info.mMenuRes );
}

void EventEditorService::OnNewSourceUI( wxUpdateUIEvent& event )
{
	event.Enable( TRUE );
}

void EventEditorService::OnSourceSettingsUI( wxUpdateUIEvent& event )
{
	if ( !ValidateDocument( event ) )
        return;
}

void EventEditorService::OnEditEventsUI( wxUpdateUIEvent& event )
{
	if ( !ValidateDocument( event ) )
        return;
}

void EventEditorService::OnEditMembersUI( wxUpdateUIEvent& event )
{
	if ( !ValidateDocument( event ) )
        return;
}

void EventEditorService::OnEditWidgetUI( wxUpdateUIEvent& event )
{
	if ( !ValidateDocument( event ) )
        return;
}

void EventEditorService::OnEditMenuUI( wxUpdateUIEvent& event )
{
	if ( !ValidateDocument( event ) )
        return;
}

bool EventEditorService::ValidateDocument()
{
	wxPMDocument* pDoc = (wxPMDocument*)wxPMBootSvc().GetDocManager()->GetCurrentDocument();

	if ( !pDoc || !pDoc->IsKindOf( CLASSINFO( wxSourceCodeDocument ) ) )
	
		return FALSE;
	
	wxSourceCodeDocument* pSrcDoc = (wxSourceCodeDocument*)pDoc;

	mSource = ((wxSourceCodeDocument*)pDoc)->GetAllText();

	if ( !mpProc->IsGeneratedSource( mSource ) ) 

		return FALSE;

	return TRUE;
}

bool EventEditorService::ValidateDocument( wxUpdateUIEvent& event )
{
	bool ok =  ValidateDocument();

	event.Enable( ok );

	return ok;
}

bool EventEditorService::ProcessDocument()
{
	wxPMDocument* pDoc = (wxPMDocument*)wxPMBootSvc().GetDocManager()->GetCurrentDocument();

	wxSourceCodeDocument* pSrcDoc = (wxSourceCodeDocument*)pDoc;

	wxString fname = pSrcDoc->GetFileInfo()->GetNameWithoutPath();

	// FOR NOW:: simplistic...

	bool isHeader = IsHeaderFile( fname );

	mpProc->InitScaner();

	if ( isHeader )
	{					 
		mpProc->ScanHeader( fname, mSource );

		if ( !ScanRelatedDocument( mpProc->GetHdrSource().mOtherFName ) )

			return FALSE;
	}
	else
	{
		mpProc->ScanImplementation( fname, mSource );

		bool hasHeader = mpProc->GetImpSource().mpTempl->mHasHeader;

		if ( hasHeader && !ScanRelatedDocument( mpProc->GetImpSource().mOtherFName ) )

			return FALSE;
	}

	return TRUE;
}

bool EventEditorService::ScanRelatedDocument( const wxString& fname )
{
	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();

	wxPMDocument* pDoc = (wxPMDocument*)mgr.GetCurrentDocument();

	wxASSERT( pDoc->GetParentDocument() ->IsKindOf( CLASSINFO( wxPMProject ) ) ); // DBG::

	wxPMProject* pPrj = (wxPMProject*)pDoc->GetParentDocument();

	PMFileInfoListT& lst = pPrj->GetFiles();

	wxPMFileInfo* pFile = pPrj->FindFile( fname );

	if ( pFile )
	{
		wxPMDocument* pRelatedDoc = mgr.OpenDocument( *pFile, pPrj, FALSE );

		if ( !pRelatedDoc )
            return FALSE;

		wxASSERT( pRelatedDoc->IsKindOf( CLASSINFO(wxSourceCodeDocument) ) ); // DBG::

		wxSourceCodeDocument* pSrcDoc = (wxSourceCodeDocument*)pRelatedDoc;

		wxString shortName = pFile->GetNameWithoutPath();
		wxString srcText = pSrcDoc->GetAllText();

		if ( IsHeaderFile( shortName ) )
			return mpProc->ScanHeader( shortName, srcText );
		else
			return mpProc->ScanImplementation( shortName, srcText );
	}

	return FALSE;
}

bool EventEditorService::IsHeaderFile( const wxString& fname )
{
	// FOR NOW:: simplistic...

	return fname.Find( ".h" )   != -1 || 
		   fname.Find( ".hpp" ) != -1;
}

bool EventEditorService::NeedsHeaderFile( const wxString& fname )
{
	return fname.Find( ".c" )   != -1 || 
		   fname.Find( ".cpp" )	!= -1 ||
		   fname.Find( ".C" )   != -1;
}

void EventEditorService::ApplySourceChanges()
{
	GenSourceInfo& imp = mpProc->GetImpSource();
	GenSourceInfo& hdr = mpProc->GetHdrSource();

	ApplyChangesToFile( imp.mFName, imp.mText );

	if ( imp.mpTempl->mHasHeader )

		ApplyChangesToFile( hdr.mFName, hdr.mText );
}

wxSourceCodeDocument* EventEditorService::FindSourceDocument( const wxString& fname )
{
	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();
	wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

	if ( !pPrj )
        return NULL;

	wxPMFileInfo* pFile = pPrj->FindFile( fname );

	if ( !pFile )
        return NULL;

	wxPMDocument* pDoc = mgr.OpenDocument( *pFile, pPrj, FALSE );

	if ( !pDoc )
        return NULL;

	wxASSERT( pDoc->IsKindOf( CLASSINFO( wxSourceCodeDocument ) ) );

	return (wxSourceCodeDocument*)pDoc;
}

ResDocument* EventEditorService::FindResourceDocument( const wxString& fname )
{
	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();
	wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

	if ( !pPrj )
        return NULL;

	wxPMFileInfo* pFile = pPrj->FindFile( fname );

	if ( !pFile )
        return NULL;

	wxPMDocument* pDoc = mgr.OpenDocument( *pFile, pPrj, FALSE );

	if ( !pDoc )
        return NULL;

	wxASSERT( pDoc->IsKindOf( CLASSINFO( ResDocument ) ) );

	return (ResDocument*)pDoc;
}

void EventEditorService::ApplyChangesToFile( const wxString& fname, const wxString& sourceText )
{
	wxSourceCodeDocument* pDoc = FindSourceDocument( fname );

	if ( !pDoc )
        return;

	pDoc->ReplaceAllText( sourceText );
}

void EventEditorService::GotoSourceLine( const wxString& fname, int line, int col )
{
	wxSourceCodeDocument* pDoc = FindSourceDocument( fname );
	if ( !pDoc )
        return;

	pDoc->GotoLine( line, col );

	wxPMBootSvc().GetDocManager()->ActivateDocument( pDoc );
}


/***** Implementation for class SourceConfigInfo *****/
SourceConfigInfo::SourceConfigInfo()
	: mpResDoc(NULL)
{
}


/***** Implementation for class SourceConfigDialog *****/

BEGIN_EVENT_TABLE( SourceConfigDialog, wxDialog )

	EVT_LISTBOX( ID_TEMPLATE_LIST, SourceConfigDialog::OnTemplateSelected )
	EVT_CHOICE( ID_RES_FILE_LIST, SourceConfigDialog::OnResFileSelected )
    EVT_BUTTON( wxID_OK,  SourceConfigDialog::OnOkButton )

END_EVENT_TABLE()

SourceConfigDialog::SourceConfigDialog( wxWindow* pParent, 
									    SourceConfigInfo* pCfgInfo,
										EventEditorService* pSvc,
										const wxString& dlgTitle, 
										bool selectTemplate )

	: wxDialog( pParent, -1, dlgTitle, wxDefaultPosition, wxSize( 350, 420 ),
				wxSYSTEM_MENU | wxCAPTION | 
				wxTAB_TRAVERSAL | wxTHICK_FRAME | wxRESIZE_BORDER ),
	  mpSvc( pSvc ),
	  mpCfgInfo( pCfgInfo ),
	  mSelectTemplate( selectTemplate )
{
	mpTemplates = new wxListBox( this, ID_TEMPLATE_LIST );
	mpClassName = new wxTextCtrl( this, -1 );
	mpFName     = new wxTextCtrl( this, -1 );
	mpResFiles  = new wxChoice( this, ID_RES_FILE_LIST, wxDefaultPosition, wxDefaultSize, 0, NULL );
	mpWindows   = new wxChoice( this, -1, wxDefaultPosition, wxDefaultSize, 0, NULL );
	mpMenus     = new wxChoice( this, -1, wxDefaultPosition, wxDefaultSize, 0, NULL );

	// ohh boy........

	Container& cont = *new Container( this );
	cont.setLayout( new GridBagLayout() );

	Container* selPanel = new Container();
	selPanel->setInsets( Insets(5,5,5,5) );
	selPanel->setLayout( new GridBagLayout() );

	GridBagConstraints c;
	int rmd = GridBagConstraints::REMAINDER;
	c.fill  = GridBagConstraints::HORIZONTAL;
	c.anchor = GridBagConstraints::WEST;
	c.weightx = 0.0; c.weighty = 0.0; c.insets = Insets( 5,5,0,0 );

	c.weightx = 0.0; c.gridwidth = 1;
	selPanel->add( new wxStaticText( this, -1, "Templates:", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER; c.weighty = 1.0; 
	c.fill  = GridBagConstraints::BOTH;
	selPanel->add( mpTemplates, &c ); c.fill  = GridBagConstraints::HORIZONTAL;

	c.weightx = 0.0; c.gridwidth = 1; c.weighty = 0.0; 
	selPanel->add( new wxStaticText( this, -1, "ClassName:", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER;
	selPanel->add( mpClassName, &c );

	c.weightx = 0.0; c.gridwidth = 1; c.weighty = 0.0; 
	selPanel->add( new wxStaticText( this, -1, "File (no ext.):", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER;
	selPanel->add( mpFName, &c );

	c.weightx = 0.0; c.gridwidth = 1;
	selPanel->add( new wxStaticText( this, -1, "Resource:", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER;
	selPanel->add( mpResFiles, &c );

	c.weightx = 0.0; c.gridwidth = 1;
	selPanel->add( new wxStaticText( this, -1, "Window:", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER;
	selPanel->add( mpWindows, &c );

	c.weightx = 0.0; c.gridwidth = 1;
	selPanel->add( new wxStaticText( this, -1, "Menu:", wxDefaultPosition ), &c );
	c.weightx = 1.0; c.gridwidth = GridBagConstraints::REMAINDER;
	selPanel->add( mpMenus, &c );

	c.weightx = 1.0; c.weighty = 1.0; c.insets = Insets( 5,5,5,5 );
	c.fill  = GridBagConstraints::BOTH;
	cont.add( selPanel, &c );

	Container* btnPanel = new Container();
	btnPanel->setInsets( Insets(5,5,5,5) );
	btnPanel->setLayout( new FlowLayout );

	wxButton* okBtn = new wxButton( this, wxID_OK, "&Ok", wxDefaultPosition );
	okBtn->SetDefault();
	btnPanel->add( okBtn );
	btnPanel->add( new wxButton( this, wxID_CANCEL, "C&ancel", wxDefaultPosition ) );

	c.weighty = 0.0; 
	cont.add( btnPanel, &c );

	if ( !selectTemplate )
	{
		mpTemplates->Enable( FALSE );
		mpFName->Enable( FALSE );
		mpClassName->Enable( FALSE );
	}
	else
	{
		mpFName->Enable(FALSE);
		mpClassName->Enable(FALSE);
		mpMenus->Enable(FALSE);
		mpWindows->Enable(FALSE);
		mpResFiles->Enable(FALSE);
	}

	RefillAll();

	if ( selectTemplate )
		mpTemplates->SetFocus();
	else
		mpResFiles->SetFocus();

	cont.doLayout();

	Center( wxBOTH );
}

SourceConfigDialog::~SourceConfigDialog()
{
}


void SourceConfigDialog::OnTemplateSelected( wxCommandEvent& event )
{
	mpClassName->Enable(TRUE);
	mpFName->Enable(TRUE);
	mpMenus->Enable(TRUE);
	mpWindows->Enable(TRUE);
	mpResFiles->Enable(TRUE);

	mpClassName->SetFocus();
}


void SourceConfigDialog::OnResFileSelected( wxCommandEvent& event )
{
	RefillResLists();

	event.Skip();
}


void SourceConfigDialog::OnOkButton( wxCommandEvent& event )
{
	if (!ValidateValues())
		return;

	event.Skip();
}


void SourceConfigDialog::ExchangeValuesBack()
{
	mpCfgInfo->mFName = mpFName->GetValue();
	mpCfgInfo->mClassName = mpClassName->GetValue();
	mpCfgInfo->mMenu = mpMenus->GetStringSelection();
	mpCfgInfo->mWindow = mpWindows->GetStringSelection();
	mpCfgInfo->mResFile = mpResFiles->GetStringSelection();
	mpCfgInfo->mTemplate = mpTemplates->GetStringSelection();
}

/*** protected methods ***/

//
// This function should be called before allowing the dialog to be closed
// with the OK button to be certain that the values selected/set in the
// dialog's widgets are valid, and have valid combinations with each other
//
// Return value of TRUE means that the current values have passed all tests
//
// Return value of FALSE means that some value specified is not valid with
// all other selections (or it has no value selected currently), and that
// the press of the OK button should not be allowed.  Cursor focus will be 
// set to the first widget determined to have invalid data in it, and
// a system bell will sound
//
bool SourceConfigDialog::ValidateValues()
{
	// Copy the values out of the widgets for evaluation
	mpCfgInfo->mFName = mpFName->GetValue();
	mpCfgInfo->mClassName = mpClassName->GetValue();
	mpCfgInfo->mResFile = mpResFiles->GetStringSelection();
	mpCfgInfo->mTemplate = mpTemplates->GetStringSelection();

	mpCfgInfo->mWindow = mpWindows->GetStringSelection();
	mpCfgInfo->mMenu = mpMenus->GetStringSelection();

	// Check for empty values in widgets first
	if (mpCfgInfo->mTemplate.IsEmpty())
	{
		wxBell();
		wxMessageBox(wxT("You must select a template before continuing"), wxT("Invalid selection"));
		mpTemplates->SetFocus();
		return FALSE;
	}
	if (mpCfgInfo->mClassName.IsEmpty())
	{
		wxBell();
		wxMessageBox(wxT("You must specify a name for the class being created before continuing"), wxT("Invalid selection"));
		mpClassName->SetFocus();
		return FALSE;
	}
	if (mpCfgInfo->mFName.IsEmpty())
	{
		wxBell();
		wxMessageBox(wxT("You must specify a filename to which the resource will be written before continuing"), wxT("Invalid selection"));
		mpFName->SetFocus();
		return FALSE;
	}

	if (mpCfgInfo->mResFile.IsEmpty())
	{
		wxBell();
		wxMessageBox(wxT("You must select an existing resource from one of\nthe project resource files before continuing"), wxT("Invalid selection"));
		mpResFiles->SetFocus();
		return FALSE;
	}

	if (mpCfgInfo->mWindow.IsEmpty() && mpCfgInfo->mMenu.IsEmpty())
	{
		wxBell();
		wxMessageBox(wxT("You must select a dialog/frame/menu to generate source for"), wxT("Invalid selection"));  // TBD: is this the right message
		mpWindows->SetFocus();
		return FALSE;
	}

	// All widget values are valid as far as we can tell
	// at this point.  Calling routine is responsible 
	// for checking that selections made on this dialog are 
	// still valid (like resources existing, etc).
	return TRUE;
}


void SourceConfigDialog::RefillAll()
{
	mpTemplates->Clear();

	GenSourceProcessor& proc = mpSvc->GetSrcProcessor();

	GenSourceTemplateListT& lst = proc.GetTemplates();

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{
		mpTemplates->Append( lst[i]->mName );

		if ( lst[i]->mName == mpCfgInfo->mTemplate )

			mpTemplates->SetSelection( i );
	}

	mpFName->SetValue( mpCfgInfo->mFName );
	mpClassName->SetValue( mpCfgInfo->mClassName );

	RefillResFileList();
	RefillResLists();
}

void SourceConfigDialog::RefillResLists()
{
	mpMenus->Clear();
	mpWindows->Clear();

	if ( !mpResFiles->Number() )
        return;

	wxString fname = mpResFiles->GetStringSelection();

	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();

	wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

	wxPMFileInfo* pFile = pPrj->FindFile( fname );

	if ( !pFile )
        return;

	wxPMDocument* pDoc = mgr.OpenDocument( *pFile, pPrj, 
										   FALSE // instructs opening it silently,
												   // without activating
										 );

	if ( !pDoc )
        return;

	wxASSERT( pDoc->IsKindOf( CLASSINFO( ResDocument ) ) ); // DBG::

	mpCfgInfo->mpResDoc = pDoc;

	ResDocument* pResDoc = (ResDocument*)pDoc;

	wxStringList menus;

	Record* pRoot = pResDoc->GetRootRecord();

	if ( !pRoot )
        return;

	size_t i;
	for( i = 0; i != pRoot->GetFieldCount(); ++i )
	{
		wxString type = pRoot->GetFieldByIndex(i).GetName();
		wxString name = pRoot->GetRecordByIndex(i)[ "name" ];

		if ( type == "menubar" )
		{
			mpMenus->Append( name );

			if ( name == mpCfgInfo->mMenu )

				mpMenus->SetSelection( mpMenus->Number() - 1 );
		}
		else
		{
			mpWindows->Append( name );

			if ( name == mpCfgInfo->mWindow )

				mpWindows->SetSelection( mpWindows->Number() - 1 );
		}
	}
}

void SourceConfigDialog::RefillResFileList()
{
	mpResFiles->Clear();

	wxPMDocManager& mgr = *wxPMBootSvc().GetDocManager();

	wxPMProject* pPrj = wxPMBootSvc().GetWorkplace()->GetActiveProject();

	if ( !pPrj )
        return;

	PMFileInfoListT lst;

	pPrj->FindFilesByMimeType( wxwMIME_WX_RESOURCE, lst );

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{
		wxString fname = lst[i]->GetNameWithoutPath();

		mpResFiles->Append( fname );

		if ( fname == mpCfgInfo->mResFile )

			mpResFiles->SetSelection( i );
	}
}
