// Commands.cpp : Implementierungsdatei
//

#include "stdafx.h"
#include <afxdlgs.h>
#include <afxtempl.h>
#include "QMsDev.h"
#include "Commands.h"
#include "newqtprojectdialog.h"
#include "qmsdevtemplates.h"
#include <direct.h>
#include <process.h>
#include <windows.h>
#include <oleauto.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static bool dontOpen = FALSE;

/////////////////////////////////////////////////////////////////////////////
// CCommands

CCommands::CCommands()
{
    m_pApplication = NULL;
    m_pApplicationEventsObj = NULL;
    m_pDebuggerEventsObj = NULL;
}

CCommands::~CCommands()
{
    ASSERT (m_pApplication != NULL);
    m_pApplication->Release();
}

void CCommands::SetApplicationObject(IApplication* pApplication)
{
    // Diese Funktion geht davon aus, dass AddRef bereits auf pApplication angewendet wurde,
    //  was CDSAddIn durch den Aufruf von QueryInterface direkt vor dem Aufruf dieser
    //  Funktion bereits erledigt hat.
    m_pApplication = pApplication;

    // Ereignis-Handler für Anwendung erzeugen
    XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
    m_pApplicationEventsObj->AddRef();
    m_pApplicationEventsObj->Connect(m_pApplication);
    m_pApplicationEventsObj->m_pCommands = this;

    // Ereignis-Handler für Debugger erzeugen
    CComPtr<IDispatch> pDebugger;
    if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger)) 
	    && pDebugger != NULL)
    {
	XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
	m_pDebuggerEventsObj->AddRef();
	m_pDebuggerEventsObj->Connect(pDebugger);
	m_pDebuggerEventsObj->m_pCommands = this;
    }
}

void CCommands::UnadviseFromEvents()
{
    ASSERT (m_pApplicationEventsObj != NULL);
    m_pApplicationEventsObj->Disconnect(m_pApplication);
    m_pApplicationEventsObj->Release();
    m_pApplicationEventsObj = NULL;

    if (m_pDebuggerEventsObj != NULL)
    {
	// Da wir die Verbindung zu den Debugger-Ereignissen herstellen konnten, 
	//  sollte es auch möglich sein, erneut auf das Debugger-Objekt zuzugreifen, 
	//  um die Verbindung zu seinen Ereignissen zu trennen (daher das VERIFY_OK weiter unten -- siehe stdafx.h).
	CComPtr<IDispatch> pDebugger;
	VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
	ASSERT (pDebugger != NULL);
	m_pDebuggerEventsObj->Disconnect(pDebugger);
	m_pDebuggerEventsObj->Release();
	m_pDebuggerEventsObj = NULL;
    }
}


/////////////////////////////////////////////////////////////////////////////
// Ereignis-Handler

// ZU ERLEDIGEN: Füllen Sie die Implementierung für die Ereignisse aus, die Sie behandeln wollen
//  Verwenden Sie m_pCommands->GetApplicationObject(), um auf das Objekt
//  "Developer Studio Application" zuzugreifen

//Application-Ereignisse

HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch* theDocument)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    dontOpen = TRUE;
    if ( !theDocument )
	return S_OK;

    CComQIPtr<ITextDocument, &IID_ITextDocument> pText(theDocument);
    if ( pText ) {
	CString file;
	CString filepath;
	CString filename;
	CString fileext;
	CComBSTR bszStr;
	pText->get_FullName(&bszStr);
	file = bszStr;
    	m_pCommands->splitFileName( file, filepath, filename, fileext );
	if ( fileext == "ui" ) {
	    DsSaveStatus saved;
	    pText->Close( CComVariant(dsSaveChangesNo), &saved );
	    m_pCommands->runDesigner( filepath + file );
	} else if ( fileext == "ts" ) {
	    DsSaveStatus saved;
	    pText->Close( CComVariant(dsSaveChangesNo), &saved );
	    m_pCommands->runLinguist( filepath + file );
	}
    }

    return S_OK;
}

HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch* theDocument)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    dontOpen = TRUE;
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch* theDocument)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch* theDocument)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch* theWindow)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // only run if it was intended
    if ( dontOpen ) {
	dontOpen = FALSE;
	return S_OK;
    }
    
    CComQIPtr<IGenericWindow, &IID_IGenericWindow> pGenericWindow(theWindow);
    if ( !pGenericWindow )
	return S_OK;

    BSTR type;
    pGenericWindow->get_Type( &type );
    if ( CString(type) != "Text" )
	return S_OK;

    CComPtr<IDispatch> pDocument;
    pGenericWindow->get_Parent(&pDocument);
    CComQIPtr<ITextDocument, &IID_ITextDocument> pTextDocument(pDocument);
    if ( pTextDocument ) {
	CString file;
	CString filepath;
	CString filename;
	CString fileext;
	CComBSTR bszStr;
	pTextDocument->get_FullName(&bszStr);
	file = bszStr;

	m_pCommands->splitFileName( file, filepath, filename, fileext );
	if ( fileext == "ui" )
	    m_pCommands->runDesigner( filepath + file );
	else if ( fileext == "ts" )
	    m_pCommands->runLinguist( filepath + file );
    }

    return S_OK;
}

HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch* theWindow)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::WorkspaceClose()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

HRESULT CCommands::XApplicationEvents::NewWorkspace()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

// Debugger-Ereignis

HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch* pBreakpoint)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// Little helpers
CString CCommands::getActiveFileName()
{
    CString file;
    CComPtr<IDispatch> pActiveDocument;
    m_pApplication->get_ActiveDocument(&pActiveDocument);
    if (pActiveDocument) {
	CComQIPtr<ITextDocument, &IID_ITextDocument> pText(pActiveDocument);
	if ( pText ) {
	    CComBSTR bszStr;
	    pText->get_FullName(&bszStr);
	    file = bszStr;
	}
    }
    return file;
}

void CCommands::splitFileName( CString &file, CString &filepath, CString &filetitle, CString &fileext )
{
    // cut file into filepath and file
    int pathpos = file.ReverseFind( '\\' );
    if ( pathpos != -1 ) {
	filepath = file.Left( pathpos +1 );
	file = file.Mid(pathpos + 1);
    }
    // cut file into filetitle and fileext (without dot)
    int extpos = file.ReverseFind( '.' );
    if ( extpos != -1 ) {
	filetitle = file.Left( extpos );
	fileext = file.Mid( extpos + 1 );	
    }
}

int CCommands::getActiveProject(CComQIPtr<IBuildProject, &IID_IBuildProject>& project )
{
    CComPtr<IDispatch> pDispProject;
    m_pApplication->get_ActiveProject(&pDispProject);
    project = CComQIPtr<IBuildProject, &IID_IBuildProject>(pDispProject);
    if ( !project )
	return S_FALSE;

    return S_OK;
}

int CCommands::getConfigurations(CComQIPtr<IBuildProject, &IID_IBuildProject> project, CComQIPtr<IConfigurations, &IID_IConfigurations>& configs )
{
    project->get_Configurations( &configs );
    if ( !configs ) {
	m_pApplication->PrintToOutputWindow( CComBSTR("NO CONFIGURATIONS IN THIS PROJECT") );
	return S_FALSE;
    }
    return S_OK;
}

bool getGlobalQtSettings( bool &shared )
{
    shared = FALSE; 
    bool thread = FALSE;
    try {
	CStdioFile file( CString(_T(getenv("QTDIR")) + CString("\\.qtwinconfig")), CFile::modeRead );
	CString line;
	BOOL eof;
	do {
	    eof = !file.ReadString( line );
	    if ( eof )
		break;
	    if ( line.Find( "shared" ) != -1 ) {
		shared = TRUE;
	    }
	    if ( line.Find( "thread" ) != -1 ) {
		thread = TRUE;
	    }
	} while ( !eof );
    }
    catch ( CFileException* e ) {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
    }
    return thread;
}
void CCommands::addSharedSettings( CComPtr<IConfiguration> pConfig, bool useThreads )
{
    const CComBSTR compiler("cl.exe");
    const CComBSTR linker("link.exe");
    LPCTSTR dllDefs;
    dllDefs = "/D QT_DLL";

    const CComBSTR dllDefine( dllDefs );
    const CComBSTR incPath(" /I$(QTDIR)\\include");
    CString version;
    try {
	CStdioFile file( CString(_T(getenv("QTDIR")) + CString("\\.qmake.cache")), CFile::modeRead );
	CString line;
	BOOL eof;
	do {
	    eof = !file.ReadString( line );
	    if ( eof )
		break;
	    if ( line.Find( "QMAKE_QT_VERSION_OVERRIDE=" ) != -1 ) {
		version = line.Right(3);
		break;
	    }
	} while ( !eof );
    }
    catch ( CFileException* e ) {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
    }
    CString sharedLibText;
#if defined(QT_TRIAL)
    if ( useThreads )
	sharedLibText = CString("$(QTDIR)\\lib\\qt-mteval") + version + CString(".lib");
    else
	sharedLibText = CString("$(QTDIR)\\lib\\qteval") + version + CString(".lib");
#else
    if ( useThreads )
	sharedLibText = CString("$(QTDIR)\\lib\\qt-mt") + version + CString(".lib");
    else
	sharedLibText = CString("$(QTDIR)\\lib\\qt") + version + CString(".lib");
#endif
    const CComBSTR sharedLib(sharedLibText + CString(" $(QTDIR)\\lib\\qtmain.lib"));
    const CComBSTR defLibs( "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib" );
    const CComBSTR sysLibs( "kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib wsock32.lib winspool.lib winmm.lib" );

    CComBSTR threadLib;
    CComBSTR correctLib;
    CComBSTR configname;
    pConfig->get_Name(&configname);
    CString config = (CString)configname;
    if ( config.Right(5) == "Debug" ) {
	threadLib = "/MLd";
	correctLib = "/MDd";
    } else {
	threadLib = "/ML";
	correctLib = "/MD";
    }

    VERIFY_OK(pConfig->AddToolSettings( compiler, dllDefine, CComVariant(VARIANT_FALSE) ));
    if ( useThreads )
	VERIFY_OK(pConfig->AddToolSettings( compiler, CComBSTR("/D QT_THREAD_SUPPORT"), CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( compiler, incPath, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->RemoveToolSettings( linker, defLibs, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( linker, sysLibs, CComVariant(VARIANT_FALSE) ));    
    VERIFY_OK(pConfig->RemoveToolSettings( linker, CComBSTR("$(QTDIR)\\lib\\qt-mt.lib"), CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->RemoveToolSettings( linker, CComBSTR("$(QTDIR)\\lib\\qt.lib"), CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( linker, sharedLib, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->RemoveToolSettings( compiler, threadLib, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( compiler, correctLib, CComVariant(VARIANT_FALSE) ));
    m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded Qt shared library") );
}

void CCommands::addStaticSettings( CComPtr<IConfiguration> pConfig, bool useThreads )
{
    const CComBSTR compiler("cl.exe");
    const CComBSTR linker("link.exe");
    LPCTSTR dllDefs;
    dllDefs = "/D QT_DLL";

    const CComBSTR dllDefine( dllDefs );
    const CComBSTR incPath(" /I$(QTDIR)\\include");
    CComBSTR staticLib = useThreads ? "$(QTDIR)\\lib\\qt-mt.lib" : "$(QTDIR)\\lib\\qt.lib";
    staticLib += CComBSTR(" $(QTDIR)\\lib\\qtmain.lib");
    CString version;
    try {
	CStdioFile file( CString(_T(getenv("QTDIR")) + CString("\\.qmake.cache")), CFile::modeRead );
	CString line;
	BOOL eof;
	do {
	    eof = !file.ReadString( line );
	    if ( eof )
		break;
	    if ( line.Find( "QMAKE_QT_VERSION_OVERRIDE=" ) != -1 ) {
		version = line.Right(3);
		break;
	    }
	} while ( !eof );
    }
    catch ( CFileException* e ) {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
    }
    CString sharedLibText;
#if defined(QT_TRIAL)
    if ( useThreads )
	sharedLibText = CString("$(QTDIR)\\lib\\qt-mteval") + version + CString(".lib");
    else
	sharedLibText = CString("$(QTDIR)\\lib\\qteval") + version + CString(".lib");
#else
    if ( useThreads )
	sharedLibText = CString("$(QTDIR)\\lib\\qt-mt") + version + CString(".lib");
    else
	sharedLibText = CString("$(QTDIR)\\lib\\qt") + version + CString(".lib");
#endif
    const CComBSTR sharedLib(sharedLibText);
    CComBSTR threadLib;
    CComBSTR correctLib;
    CComBSTR configname;
    pConfig->get_Name(&configname);
    CString config = (CString)configname;
    if ( config.Right(5) == "Debug" ) {
	threadLib = "/MLd";
	correctLib = "/MDd";
    } else {
	threadLib = "/ML";
	correctLib = "/MD";
    }
    const CComBSTR defLibs( "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib" );
    const CComBSTR sysLibs( "kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib wsock32.lib winspool.lib winmm.lib" );

    VERIFY_OK(pConfig->RemoveToolSettings( compiler, dllDefine, CComVariant(VARIANT_FALSE) ));
    if ( useThreads )
	VERIFY_OK(pConfig->AddToolSettings( compiler, CComBSTR("/D QT_THREAD_SUPPORT"), CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( compiler, incPath, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->RemoveToolSettings( linker, defLibs, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( linker, sysLibs, CComVariant(VARIANT_FALSE) ));    
    VERIFY_OK(pConfig->RemoveToolSettings( linker, sharedLib, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( linker, staticLib, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->RemoveToolSettings( compiler, threadLib, CComVariant(VARIANT_FALSE) ));
    VERIFY_OK(pConfig->AddToolSettings( compiler, correctLib, CComVariant(VARIANT_FALSE) ));
    m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded Qt static library") );
}

void CCommands::addMOC( CComQIPtr<IBuildProject, &IID_IBuildProject> pProject, CString file )
{
    CString fileext;
    CString filename;
    CString filepath;
    CString inputfile;
    CString mocfile;
    CString fileToMoc;
    const CString moccommand = "%qtdir%\\bin\\moc.exe ";

    splitFileName( file, filepath, filename, fileext );

    bool specialFile = FALSE;
    if ( !fileext.IsEmpty() && fileext[0] == 'c' ) {
	fileToMoc = filepath + filename + ".moc";
	mocfile = filepath + filename + ".moc";
	specialFile = TRUE;
    } else {
	fileToMoc = filepath + file;
	mocfile = filepath + "moc_"+ filename + ".cpp";
    }

    // Add the files to the project
    if ( pProject->AddFile( CComBSTR(fileToMoc), CComVariant(VARIANT_TRUE) ) == S_OK )
        m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+file) );
    if ( pProject->AddFile( CComBSTR(mocfile), CComVariant(VARIANT_TRUE) ) == S_OK )
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+mocfile) );

    // Get the list of configurations in the active project
    CComQIPtr<IConfigurations, &IID_IConfigurations> pConfigs;
    if ( getConfigurations( pProject, pConfigs ) != S_OK ) {
	m_pApplication->PrintToOutputWindow( CComBSTR("FAILED TO ADD MOC!") );
	return;
    }

    if ( !fileext.IsEmpty() && fileext[0] == 'c' ) {
	fileToMoc = filepath + filename + ".moc";
	mocfile = "$(InputDir)\\$(InputName).moc";
	specialFile = TRUE;
    } else {
	fileToMoc = filepath + file;
	mocfile = "$(InputDir)\\moc_$(InputName).cpp";
    }
    inputfile = "$(InputDir)\\$(InputName)." + fileext;

    // Add the moc step to the file
    long cCount;
    VERIFY_OK( pConfigs->get_Count(&cCount));
    for (long c = 0; c < cCount; c++ ) {
	CComVariant Varc = c+1;
	CComPtr<IConfiguration> pConfig;
	VERIFY_OK(pConfigs->Item(Varc, &pConfig));
	VERIFY_OK(pConfig->AddCustomBuildStepToFile(CComBSTR(fileToMoc), CComBSTR(moccommand + inputfile + " -o " + mocfile), 
					  CComBSTR(mocfile), CComBSTR("MOCing "+file+"..."), 
					  CComVariant(VARIANT_FALSE)));
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded MOC preprocessor") );
    }

    if ( specialFile ) {
//	    VERIFY_OK(pConfig->AddFileDependency( CComBSTR(mocfile), CComBSTR(filepath+file)));
    }
}

void CCommands::addUIC( CComQIPtr<IBuildProject, &IID_IBuildProject> pProject, CString file )
{
    CString fileext;
    CString filename;
    CString filepath;

    splitFileName( file, filepath, filename, fileext );

    const CString uiFile(filepath + file);
    const CString impFile(filepath + filename + ".cpp");
    const CString decFile(filepath + filename + ".h");
    const CString incFile( filename+".h" );
    const CString mocFile(filepath + "moc_" + filename + ".cpp");
    const CString uiccommand("%qtdir%\\bin\\uic.exe ");
    const CString moccommand("%qtdir%\\bin\\moc.exe ");

    // Add the file and the all output to the project
    if ( pProject->AddFile( CComBSTR(uiFile), CComVariant(VARIANT_TRUE) ) == S_OK )
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+uiFile) );
    if ( pProject->AddFile( CComBSTR(impFile), CComVariant(VARIANT_TRUE) ) == S_OK )
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+impFile) );
    if (pProject->AddFile( CComBSTR(decFile), CComVariant(VARIANT_TRUE) ) == S_OK )
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+decFile) );
    if (pProject->AddFile( CComBSTR(mocFile), CComVariant(VARIANT_TRUE) ) == S_OK )
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded "+mocFile) );

    // Get the list of configurations in the active project
    CComQIPtr<IConfigurations, &IID_IConfigurations> pConfigs;
    if ( getConfigurations( pProject, pConfigs ) != S_OK ) {
	m_pApplication->PrintToOutputWindow( CComBSTR("FAILED TO ADD UIC!") );
    }
    // Add the moc step to the file
    long cCount;
    VERIFY_OK( pConfigs->get_Count(&cCount));
    for (long c = 0; c < cCount; c++ ) {
	CComVariant Varc = c+1;
	CComPtr<IConfiguration> pConfig;
	VERIFY_OK(pConfigs->Item(Varc, &pConfig));
	CComBSTR command = uiccommand+"$(InputPath) -o $(InputDir)\\$(InputName).h\n" +
			   uiccommand+"$(InputPath) -i $(InputName).h -o $(InputDir)\\$(InputName).cpp\n" + 
			   moccommand+"$(InputDir)\\$(InputName).h -o $(InputDir)\\moc_$(InputName).cpp";
	CComBSTR output = "$(InputDir)\\$(InputName).h\n$(InputDir)\\$(InputName).cpp\n$(InputDir)\\moc_$(InputName).cpp";
	VERIFY_OK(pConfig->AddCustomBuildStepToFile(CComBSTR(uiFile), command, output, CComBSTR("UICing "+file+"..."), CComVariant(VARIANT_FALSE)));
	m_pApplication->PrintToOutputWindow( CComBSTR("\t\tadded UIC preprocessor step") );
    }
}

CString CCommands::replaceTemplateStrings( const CString& t, const CString& classheader, 
					   const CString& classname, const CString& instance, 
					   const CString& instcall, const CString& projekt,
					   const CString& runapp)
{
    CString r = t;
    r.Replace( "$QMSDEVCLASSHEADER", classheader );
    r.Replace( "$QMSDEVCLASSNAME", classname );
    r.Replace( "$QMSDEVINSTANCE", instance );
    r.Replace( "$QMSDEVINSTCALL", instcall );
    r.Replace( "$QMSDEVPROJECTNAME", projekt );
    r.Replace( "$QMSDEVRUNAPP", runapp );
    return r;
}

void CCommands::runDesigner( const CString &file )
{
    CString path;
    CString command;

    path = getenv("QTDIR");
    if ( path.IsEmpty() ) {
	// Get the location from the registry
	CRegKey key;
	char* value = new char[256];
	unsigned long length;
	if (key.Open(HKEY_CURRENT_USER, "Software\\Trolltech\\Qt Designer") == ERROR_SUCCESS) {
	    length = 255;
	    key.QueryValue( value, "PathToExe", &length );
	    path = value;
	    length = 255;
	    key.QueryValue( value, "NameOfExe", &length );
	    command = value;
	    key.Close();
	} else {
	    ::MessageBox(NULL, "Can't locate Qt Designer", 
			       "Error", MB_OK | MB_ICONINFORMATION);
	    return;
	}
	delete[] value;
    } else {
	command = "designer.exe";
	path+="\\bin";
    }

    // Run the designer with options -client and "file"

    if ( spawnl(_P_NOWAIT, path+"\\"+command, command, "-client", file, 0 ) == -1 ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	::MessageBox(NULL, "Failed to run Qt Designer: "+command, 
			   "Start Designer", MB_OK | MB_ICONINFORMATION);
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    }
}

void CCommands::runLinguist( const CString &file )
{
    CString path;
    CString command;

    path = getenv("QTDIR");
    if ( path.IsEmpty() ) {
	// Get the location from the registry
	CRegKey key;
	char* value = new char[256];
	unsigned long length;
	if (key.Open(HKEY_CURRENT_USER, "Software\\Trolltech\\Qt Linguist") == ERROR_SUCCESS) {
	    length = 255;
	    key.QueryValue( value, "PathToExe", &length );
	    path = value;
	    length = 255;
	    key.QueryValue( value, "NameOfExe", &length );
	    command = value;
	    key.Close();
	} else {
	    ::MessageBox(NULL, "Can't locate Qt Linguist", 
			       "Error", MB_OK | MB_ICONINFORMATION);
	    return;
	}
	delete[] value;
    } else {
	command = "linguist.exe";
	path+="\\bin";
    }

    // Run the linguist with option "file"

    if ( spawnl(_P_NOWAIT, path+"\\"+command, command, file, 0 ) == -1 ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	::MessageBox(NULL, "Failed to run Qt Linguist: "+command, 
			   "Start Designer", MB_OK | MB_ICONINFORMATION);
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    }
}


/////////////////////////////////////////////////////////////////////////////
// Ccommands-Methoden

STDMETHODIMP CCommands::QMsDevStartDesigner() 
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CString file;
    CString filepath;
    CString filename;
    CString fileext;

    // Get the active file
    file = getActiveFileName();
    splitFileName( file, filepath, filename, fileext );

    // Check if we can use the file
    if ( file.IsEmpty() || fileext != "ui" )
	file = "NewDialog.ui";

    runDesigner( filepath + file );

    return S_OK;
}

STDMETHODIMP CCommands::QMsDevUseQt()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    m_pApplication->PrintToOutputWindow( CComBSTR("Adding Qt support to project") );
    // Check for active Project
    CComQIPtr<IBuildProject, &IID_IBuildProject> pProject;
    if ( getActiveProject( pProject ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	if ( ::MessageBox( NULL, "There is no active project.\nDo you want to create a new Qt Project?", 
	    "Use Qt in project", MB_YESNOCANCEL | MB_ICONQUESTION ) == IDYES )
	    QMsDevNewQtProject();

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    bool shared;
    bool threaded = getGlobalQtSettings( shared );

    // Get the list of configurations in the active project
    CComQIPtr<IConfigurations, &IID_IConfigurations> pConfigs;
    if ( getConfigurations( pProject, pConfigs ) != S_OK )
	return S_FALSE;

    // Add the specific settings to compiler and linker
    // TODO: read .qtwinconfig
    
    const CComBSTR compiler("cl.exe");
    const CComBSTR ipath("/I_$(QTDIR)\\include");

    long cCount;
    VERIFY_OK( pConfigs->get_Count(&cCount));
    for (long c = 0; c < cCount; c++ ) {
	CComVariant Varc = c+1;
	CComPtr<IConfiguration> pConfig;
	VERIFY_OK(pConfigs->Item(Varc, &pConfig));
	VERIFY_OK(pConfig->AddToolSettings( compiler, ipath, CComVariant(VARIANT_FALSE) ));
	if ( shared )
	    addSharedSettings( pConfig, threaded );
	else
	    addStaticSettings( pConfig, threaded );
    }

    return S_OK;
    m_pApplication->PrintToOutputWindow( CComBSTR("Finished!\n") );
}

STDMETHODIMP CCommands::QMsDevAddMOCStep()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

    // Check for active Project
    CComQIPtr<IBuildProject, &IID_IBuildProject> pProject;
    if ( getActiveProject( pProject ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	if ( ::MessageBox( NULL, "There is no active project.\nDo you want to create a new Qt Project?", 
	    "Add MOC to file", MB_YESNOCANCEL | MB_ICONQUESTION ) == IDYES )
	    QMsDevNewQtProject();

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    CString file;
    CString fileext;
    CString filename;
    CString filepath;

    file = getActiveFileName();

    if ( file.IsEmpty() ) {
	CFileDialog fd( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
	    "Header files (*.h; *.hxx; *.hpp)|*.h; *.hxx; *.hpp|"
	    "Implementation files (*.c; *.cpp; *.cxx)|*.c; *.cpp; *.cxx|"
	    "C++ files (*.h; *.hxx; *.hpp; *.c; *.cpp; *.cxx)|*.h; *.hxx; *.hpp; *.c; *.cpp; *.cxx|"
	    "All Files (*.*)|*.*||", NULL);
	int result = fd.DoModal();
        
	if ( result == IDCANCEL ) {
	    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	    return S_OK;
	}
	file = fd.GetPathName();
    }

    splitFileName( file, filepath, filename, fileext );

    m_pApplication->PrintToOutputWindow( CComBSTR("Add MOC buildstep for "+file+"...") );
    addMOC( pProject, filepath+file );
    m_pApplication->PrintToOutputWindow( CComBSTR("Finished!\n") );
    
    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

    return S_OK;
}

STDMETHODIMP CCommands::QMsDevGenerateQtProject()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

    CComQIPtr<IBuildProject, &IID_IBuildProject> pProject;
    if ( getActiveProject( pProject ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	if ( ::MessageBox( NULL, "There is no active project.\nDo you want to create a new Qt Project?", 
	    "Write Qt Project", MB_YESNOCANCEL | MB_ICONQUESTION ) == IDYES )
	    QMsDevNewQtProject();

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    CComBSTR fp;
    pProject->get_FullName( &fp );
    CString dspfile( fp );
    CString dspfilepath, dspfilename, dspfileext;
    splitFileName( dspfile, dspfilepath, dspfilename, dspfileext );

    CFileDialog fd( FALSE, "*.pro", dspfilepath + dspfilename + ".pro", OFN_HIDEREADONLY, 
	"Qt Project (*.pro)|*.pro|"
	"All Files (*.*)|*.*||", NULL);
    int result = fd.DoModal();
    if ( result == IDCANCEL ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
    }

    CString profile = fd.GetPathName();
    CString profilepath, profilename, profileext;
    splitFileName( profile, profilepath, profilename, profileext );

    CMapStringToString filelists;
    CString group;
    CString file;
    CString filepath, filename, fileext;
    try {
	CStdioFile dsp( dspfilepath + dspfilename + "." + dspfileext , CFile::modeRead );
	CString string;
	while ( dsp.ReadString( string ) )
	{
	    if ( group.IsEmpty() && string.Find( "# Begin Group" ) == 0 ) {
		group = string.Mid( 15, string.GetLength() - 16 );
		group.MakeUpper();
	    } else if ( string.Find( "SOURCE=" ) == 0 ) {
		bool ignore = FALSE;
		file = string.Right( string.GetLength() - 7 );
		file.TrimLeft();
		file.TrimRight();
		splitFileName( file, filepath, filename, fileext );
		if ( filepath.Left( 2 ) == ".\\" )
		    filepath = filepath.Right( filepath.GetLength() - 2 );
		ignore = filename.Left( 4 ) == "moc_" || fileext == "moc" || group == "GENERATED" || fileext == "ui";

		if ( !ignore ) {
		    if ( fileext == "ui" )
			group = "FORMS";
		    else if ( fileext == "h" || fileext == "hxx" || fileext == "hpp" )
			group = "HEADERS";
		    else if ( fileext == "cpp" || fileext == "cxx" || fileext == "c" )
			group = "SOURCES";
		    else if ( fileext == "y" )
			group = "YACCSOURCES";
		    else if ( fileext == "l" )
			group = "LEXSOURCES";
		    else if ( fileext == "ts" )
			group = "TRANSLATIONS";
		    else
			break;
		    CString temp;
		    filelists.Lookup( group, temp );
		    filepath.Replace( "\\", "/" );
		    temp += " \\\n\t\t" + filepath + filename + "." + fileext;
		    filelists.SetAt( group, temp );
		}
	    } else if ( !group.IsEmpty() && string.Find( "# End Group" ) == 0 ) {
		group.Empty();
	    }
	}
    }
    catch ( CFileException* e )
    {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    chdir( profilepath );

    CStdioFile pro;
    try {
	CString string, tstring;
	CString newstring;
	bool newproject = TRUE;

	// read the existing pro-file and replace SOURCES etc. with map contents
	if ( pro.Open( profilepath + profilename + "." + profileext, CFile::modeReadWrite ) ) {
	    newproject = FALSE;
	    while ( pro.ReadString( string ) ) {
		if ( !string.IsEmpty() ) {
		    tstring += string;
		    tstring.TrimRight();
		}
		if ( tstring.Right( 1 ) != "\\" ) {
		    int firstSep = tstring.FindOneOf( "+=" );
		    if ( firstSep != -1 ) {
			CString group = tstring.Left( firstSep );
			group.TrimRight();
			if ( filelists.Lookup( group, file ) ) {
			    tstring = group + " = " + file;
			    filelists.RemoveKey( group );
			}
		    }
		    newstring += tstring + "\n";
		    tstring.Empty();
		} else {
		    if ( string.IsEmpty() )		    // bad pro-file
			break;
		    tstring += "\n\t";
		}
	    }
	    pro.Close();
	}
	// add remaining new files and groups
	POSITION pos = filelists.GetStartPosition();
	while ( pos ) {
	    filelists.GetNextAssoc( pos, group, file );
	    newstring += group + " = " + file + "\n\n";
	}
	// new project, so read (or rather guess) default settings for TEMPLATE etc.
	if ( !newstring.IsEmpty() && pro.Open( profilepath + profilename + "." + profileext, CFile::modeCreate | CFile::modeReadWrite | CFile::typeText ) ) {
	    if ( newproject ) {
		CString header;
		header += "# qmake project generated by QMsDev\n#\n# General settings\n\n";
		if ( newstring.Find( "main.cpp" ) != -1 ) {
		    header += "TEMPLATE = app\n";
		    header += "CONFIG  += qt warn_off\n";
		} else {
		    header += "TEMPLATE = lib\n";
		    header += "CONFIG  += qt warn_off dll\n"; // nobody uses static libs anyway...
		}

		BSTR pname;
		pProject->get_Name( &pname );
		CString name( pname );
		header += "TARGET  += " + name + "\n";
		header += "\n\n# Input\n\n";
		pro.WriteString( header );
	    }	    
	    pro.WriteString( newstring );
	}
    }
    catch ( CFileException* e )
    {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    return S_OK;
}

STDMETHODIMP CCommands::QMsDevNewQtProject()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));

    NewQtProjectDialog dialog;
    if ( dialog.DoModal() == IDCANCEL ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    if ( mkdir( dialog.m_location ) < 0 ) {
	::MessageBox(NULL, "Couldn't create Directory\n"+dialog.m_location, "New Qt Project", MB_OK | MB_ICONINFORMATION );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    m_pApplication->PrintToOutputWindow( CComBSTR("Creating Qt Project \"" + dialog.m_name + "\"...") );

    CString filename = dialog.m_location;

    if ( filename[ filename.GetLength() -1 ] != '\\' )
	filename+="\\";
    filename += dialog.m_name + ".dsp";
    if ( m_pApplication->AddProject( CComBSTR(filename), CComBSTR(dialog.m_location), CComBSTR("Application"), VARIANT_TRUE ) != S_OK ) {
	CComBSTR err;
	GetLastErrorDescription( err );
	::MessageBox(NULL, (LPCTSTR)err.m_str, "New Qt Project", MB_OK | MB_ICONINFORMATION );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    // Get project object we just created
    CComQIPtr<IBuildProject, &IID_IBuildProject> pProject;
    if ( getActiveProject( pProject ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	::MessageBox(NULL, "Project creation failed!", "QMsDev", MB_OK | MB_ICONINFORMATION );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }
    // Get the list of configurations
    CComQIPtr<IConfigurations, &IID_IConfigurations> pConfigs;
    if ( getConfigurations( pProject, pConfigs ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    long cCount;
    VERIFY_OK( pConfigs->get_Count(&cCount));

    for (long c = 0; c < cCount; c++ ) {
	CComVariant Varc = c+1;
	CComPtr<IConfiguration> pConfig;
	VERIFY_OK(pConfigs->Item(Varc, &pConfig));
	BSTR bstr;
	pConfig->get_Name(&bstr);
	bool shared;
        bool useThreads = getGlobalQtSettings( shared );
	if ( shared ) {
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding Qt shared library to "+ CString(bstr) + "...") );
	    addSharedSettings( pConfig, useThreads );
	} else {
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding Qt static library to "+ CString(bstr) + "...") );
	    addStaticSettings( pConfig, useThreads );
	}
    }

    CString projectName = dialog.m_name;
    dialog.m_name.MakeLower();
    CString classheader;
    CString classname;
    CString instancename;
    CString instancecall;
    CString runapp;
    if ( dialog.m_dialog ) {
	classheader = dialog.m_name + "dialog";
	classname = projectName + "Dialog";
	instancename = "dialog";
	instancecall = "( 0, 0, TRUE )";
	runapp = "dialog.exec();\n\n\treturn 0;";
    } else {
	classheader = dialog.m_name + "mainwindow";
	classname = projectName + "MainWindow";
	instancename = "mainwindow";
	instancecall = "";
	runapp = "mainwindow.show();\n\n\treturn app.exec();";
    }

    CString baseDir = dialog.m_location + "\\";
    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating basic files...") );
    
    // Write files and replace $MSDEV... strings with project-specific stuff
    try {
	CStdioFile mainFile( baseDir + "main.cpp", CFile::modeCreate | CFile::modeWrite );

	mainFile.WriteString( replaceTemplateStrings(main_cpp, classheader, 
						     classname, instancename, instancecall, projectName, runapp) );
	mainFile.Close();

	CStdioFile infoFile( baseDir + "readme.txt", CFile::modeCreate | CFile::modeWrite );
	CString readme( readme_txt );

	if ( dialog.m_dialog ) {
	    readme.Replace( "$QMSDEVUITYPE", "Dialog interface" );
	    readme.Replace( "$QMSDEVFILELIST", classheader+"base.ui\n\tA dialog with basic buttons.\n"
					       "\tUse the Qt GUI Designer change the layout.\n" );
	    readme.Replace( "$QMSDEVQTFILELIST", classheader+"base.h\n"+classheader+"base.cpp\nmoc_"+
						 classheader+"base.cpp\nmoc_"+classheader+".cpp\n" );
	} else if ( dialog.m_mdi ) {
	    readme.Replace( "$QMSDEVUITYPE", "Multi Document interface (MDI)" );
	    readme.Replace( "$QMSDEVFILELIST", "" );
	    readme.Replace( "$QMSDEVQTFILELIST", "moc_"+classheader+".cpp\n" );
	} else {
	    readme.Replace( "$QMSDEVUITYPE", "Main Window interface" );
	    readme.Replace( "$QMSDEVFILELIST", classheader+"base.ui\n\tA main window.\n"
					       "\tUse the Qt GUI Designer change the layout.\n" );
	    readme.Replace( "$QMSDEVQTFILELIST", classheader+"base.h\n"+classheader+"base.cpp\nmoc_"+
						 classheader+"base.cpp\nmoc_"+classheader+".cpp\n" );
	}

	infoFile.WriteString( replaceTemplateStrings(readme, classheader, 
						     classname, instancename, instancecall, projectName) );
	infoFile.Close();

	if ( dialog.m_dialog ) {
	    CString uiFileName(dialog.m_name+"dialogbase.ui");
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating basic dialog UI...") );
	    
	    CStdioFile uiFile( baseDir + uiFileName, CFile::modeCreate | CFile::modeWrite );
	    uiFile.WriteString( replaceTemplateStrings(dialogbase_ui, classheader, 
						       classname, instancename, instancecall, projectName) );
	    uiFile.Close();

	    CString hFileName(classheader+".h");
	    CString iFileName(classheader+".cpp");
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating basic dialog implementation...") );
	    CStdioFile hFile( baseDir + hFileName, CFile::modeCreate | CFile::modeWrite );
	    hFile.WriteString( replaceTemplateStrings(dialog_h, classheader, 
						      classname, instancename, instancecall, projectName) );
	    hFile.Close();

	    CStdioFile iFile( baseDir + iFileName, CFile::modeCreate | CFile::modeWrite );
	    iFile.WriteString( replaceTemplateStrings(dialog_cpp, classheader, 
						      classname, instancename, instancecall, projectName) );
	    iFile.Close();

	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding files...") );
	    pProject->AddFile( CComBSTR(uiFileName), CComVariant(VARIANT_TRUE) );
	    pProject->AddFile( CComBSTR(hFileName), CComVariant(VARIANT_TRUE) );
	    pProject->AddFile( CComBSTR(iFileName), CComVariant(VARIANT_TRUE) );
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding build steps...") );
	    addUIC( pProject, uiFileName );
	    addMOC( pProject, hFileName );
	    runDesigner( baseDir + uiFileName );
	} else if ( dialog.m_mdi ) {
	    CString hFileName;
	    CString iFileName;
	    hFileName = classheader+".h";
	    iFileName = classheader+".cpp";
	    
	    CStdioFile hFile( baseDir + hFileName, CFile::modeCreate | CFile::modeWrite );
	    CStdioFile iFile( baseDir + iFileName, CFile::modeCreate | CFile::modeWrite );
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating MDI interface...") );
	    hFile.WriteString( replaceTemplateStrings(mdi_h, classheader, 
		classname, instancename, instancecall, projectName) );
	    iFile.WriteString( replaceTemplateStrings(mdi_cpp, classheader, 
		classname, instancename, instancecall, projectName) );

	    hFile.Close();
	    iFile.Close();

	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding files...") );
	    pProject->AddFile( CComBSTR(hFileName), CComVariant(VARIANT_TRUE) );
	    pProject->AddFile( CComBSTR(iFileName), CComVariant(VARIANT_TRUE) );
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding build steps...") );
	    addMOC( pProject, hFileName);
	} else {
	    CString uiFileName(dialog.m_name+"mainwindowbase.ui");
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating basic main window UI...") );
	    
	    CStdioFile uiFile( baseDir + uiFileName, CFile::modeCreate | CFile::modeWrite );
	    uiFile.WriteString( replaceTemplateStrings(mainwinbase_ui, classheader, 
		classname, instancename, instancecall, projectName) );
	    uiFile.Close();
	    
	    CString hFileName(classheader+".h");
	    CString iFileName(classheader+".cpp");
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating basic main window implementation...") );
	    CStdioFile hFile( baseDir + hFileName, CFile::modeCreate | CFile::modeWrite );
	    hFile.WriteString( replaceTemplateStrings(window_h, classheader, 
		classname, instancename, instancecall, projectName) );
	    hFile.Close();
	    
	    CStdioFile iFile( baseDir + iFileName, CFile::modeCreate | CFile::modeWrite );
	    iFile.WriteString( replaceTemplateStrings(window_cpp, classheader, 
		classname, instancename, instancecall, projectName) );
	    iFile.Close();
	    
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding files...") );
	    pProject->AddFile( CComBSTR(uiFileName), CComVariant(VARIANT_TRUE) );
	    pProject->AddFile( CComBSTR(hFileName), CComVariant(VARIANT_TRUE) );
	    pProject->AddFile( CComBSTR(iFileName), CComVariant(VARIANT_TRUE) );
	    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding build steps...") );
	    addUIC( pProject, uiFileName );
	    addMOC( pProject, hFileName );
	    runDesigner( baseDir + uiFileName );
	}
    }
    catch ( CFileException* e )
    {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }
    
    pProject->AddFile( CComBSTR("main.cpp"), CComVariant(VARIANT_TRUE) );
    pProject->AddFile( CComBSTR("readme.txt"), CComVariant(VARIANT_TRUE) );
    
    m_pApplication->PrintToOutputWindow( CComBSTR(dialog.m_name+" finished!\n") );

    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    return S_OK;
}

STDMETHODIMP CCommands::QMsDevNewQtDialog()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    
    CComQIPtr<IBuildProject, &IID_IBuildProject> pProject;
    if ( getActiveProject( pProject ) != S_OK ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	if ( ::MessageBox( NULL, "There is no active project.\nDo you want to create a new Qt Project?", 
	    "New Dialog", MB_YESNOCANCEL | MB_ICONQUESTION ) == IDYES )
	    QMsDevNewQtProject();

	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    CComBSTR fp;
    pProject->get_FullName( &fp );
    CString file(fp);
    CString filepath;
    CString filename;
    CString fileext;
    CString classname;
    
    splitFileName( file, filepath, filename, fileext );

    // TODO: ask for classname
    CFileDialog fd( TRUE, "ui", "NewDialog.ui", OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, 
	"User Interface File (*.ui)|*.ui|"
	"All Files (*.*)|*.*||", NULL);
    fd.m_ofn.lpstrInitialDir = filepath;
    int result = fd.DoModal();
    if ( result == IDCANCEL ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
    }

    file = fd.GetPathName();
    splitFileName( file, filepath, filename, fileext );
    if ( CFileFind().FindFile( file ) ) {
	m_pApplication->PrintToOutputWindow( CComBSTR("Add UIC buildstep for "+file+"...") );
	m_pApplication->PrintToOutputWindow( CComBSTR("Add buildstep for "+file+"...") );
	addUIC( pProject, filepath + file );
	m_pApplication->PrintToOutputWindow( CComBSTR("Finished!\n") );
    
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
    }

    classname = filename;
    filename.MakeLower();

    m_pApplication->PrintToOutputWindow( CComBSTR("Adding new dialog \"" + classname + "\"...") );
    m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating dialog...") );

    file = filename+".ui";
    file.MakeLower();
    CStdioFile uiFile( filepath + file , CFile::modeCreate | CFile::modeWrite );
    uiFile.WriteString( replaceTemplateStrings(dialogbase_ui, "", 
					       classname, "", "", classname) );
    uiFile.Close();

    m_pApplication->PrintToOutputWindow( CComBSTR("\tadding files...") );
    addUIC( pProject, filepath+file );

    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
    if ( ::MessageBox( NULL, "Do you want me to add a basic implementation for your dialog?", 
	"Question", MB_YESNOCANCEL | MB_ICONQUESTION ) == IDYES ) {
	m_pApplication->PrintToOutputWindow( CComBSTR("\tcreating implementation...") );
	int error = system( "uic -subdecl "+classname+" "+filename+".h "+filepath+filename+".ui -o "+filepath+filename+"impl.h" );
	error +=    system( "uic -subimpl "+classname+" "+filename+"impl.h "+filepath+filename+".ui -o "+filepath+filename+"impl.cpp" );
	if ( error ) {
	    ::MessageBox( NULL, "Failed to create subclass implementation!", "Error", MB_OK );
	    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	    return S_FALSE;
	}
	m_pApplication->PrintToOutputWindow( CComBSTR("\tadding implementation files...") );
	pProject->AddFile( CComBSTR(filepath+filename+"impl.h"), CComVariant(VARIANT_TRUE));
	addMOC( pProject, filepath+filename+"impl.h" );
	pProject->AddFile( CComBSTR(filepath+filename+"impl.cpp"), CComVariant(VARIANT_TRUE));
    }

    m_pApplication->PrintToOutputWindow( CComBSTR("New Dialog \"" + classname + "\" finished!") );

    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    return S_OK;
}

bool projectIsLibrary( CString projectPath )
{
    AFX_MANAGE_STATE( AfxGetStaticModuleState() );

    CFile inFile;

    CString buffer;
    char c;

    if( inFile.Open( projectPath, CFile::modeRead ) ) {
	while( inFile.Read( &c, sizeof( c ) ) ) {
	    if( c != '\n' )
		buffer += c;
	    else {
		// A complete line has been read.
		if( buffer.Left( 8 ) == "TEMPLATE" ) {
		    // This is the template line
		    if( buffer.Find( "lib" ) != -1 )
			return true;
		    break;
		}
		buffer.Empty();
	    }
	}
    }

    return false;
}

STDMETHODIMP CCommands::QMsDevCreateDSP()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));

    CString file;
    CString filepath;
    CString filename;
    CString fileext;

    CFileDialog fd( TRUE, NULL, NULL, OFN_HIDEREADONLY, 
	"Qt Project (*.pro)|*.pro|"
	"All Files (*.*)|*.*||", NULL);
    int result = fd.DoModal();
    if ( result == IDCANCEL ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_OK;
    }

    file = fd.GetPathName();
    splitFileName( file, filepath, filename, fileext );

    chdir( filepath );
    CString tFile = "vcapp.t";
    try {
	CStdioFile file( filepath + file, CFile::modeRead );
	CString line;
	BOOL eof;
	do {
	    eof = !file.ReadString( line );
	    if ( eof )
		break;
	    if ( line.Find( "TEMPLATE" ) != -1 ) {
		if ( ( line.Find( "lib" ) != -1 ) || 
		    ( line.Find( "vclib" ) != -1 ) )
		    tFile = "vclib.t";
		break;
	    }
	} while ( !eof );
    }
    catch ( CFileException* e ) {
	char err[256];
	e->GetErrorMessage( (char*)&err, 255, NULL );
	::MessageBox( NULL, err, "Error", MB_OK );
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
	return S_FALSE;
    }

    m_pApplication->PrintToOutputWindow( CComBSTR("Running qmake...") );
    if ( system( "qmake "+file+" -t "+tFile ) )
	m_pApplication->PrintToOutputWindow( CComBSTR("FAILED TO RUN QMAKE!") );
    else
	::MessageBox(NULL, "Created Developer Studio Project for Qt Project "+file+"\n"
			   "Add the new project file to your current workspace,\n"
			   "or open it in an empty workspace.", 
			   "Open Qt Project", MB_OK | MB_ICONINFORMATION );

    VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    return S_OK;
}

STDMETHODIMP CCommands::QMsDevAddUICStep()
{
    return S_OK;
}

STDMETHODIMP CCommands::QMsDevStartLinguist()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())
	
    CString file;
    CString filepath;
    CString filename;
    CString fileext;
    
    // Get the active file
    file = getActiveFileName();
    splitFileName( file, filepath, filename, fileext );
    
    // Check if we can use the file
    if ( file.IsEmpty() || fileext != "ts" )
	return S_FALSE;
    
    runDesigner( filepath + file );
    
    return S_OK;
}

STDMETHODIMP CCommands::QMsDevStartAssistant()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())

    CString path;
    CString command;

    path = getenv("QTDIR");
    if ( path.IsEmpty() ) {
	// Get the location from the registry
	CRegKey key;
	char* value = new char[256];
	unsigned long length;
	if (key.Open(HKEY_CURRENT_USER, "Software\\Trolltech\\Qt Assistant") == ERROR_SUCCESS) {
	    length = 255;
	    key.QueryValue( value, "PathToExe", &length );
	    path = value;
	    length = 255;
	    key.QueryValue( value, "NameOfExe", &length );
	    command = value;
	    key.Close();
	} else {
	    ::MessageBox(NULL, "Can't locate Qt Assistant", 
			       "Error", MB_OK | MB_ICONINFORMATION);
	    return S_FALSE;
	}
	delete[] value;
    } else {
	command = "assistant.exe";
	path+="\\bin";
    }

    // Run the assistant

    if ( spawnl(_P_NOWAIT, path+"\\"+command, command, 0 ) == -1 ) {
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
	::MessageBox(NULL, "Failed to run Qt Assistant: "+command, 
			   "Start Designer", MB_OK | MB_ICONINFORMATION);
	VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
    }

    return S_OK;
}
