/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003  Yiannis An. Mandravellos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL   : http://www.codeblocks.org
*
* $Id: compilergcc.cpp,v 1.104.2.1 2005/10/25 07:59:01 mandrav Exp $
* $Date: 2005/10/25 07:59:01 $
*/

#include <sdk.h>
#include "compilergcc.h"
#include <manager.h>
#include <sdk_events.h>
#include <pipedprocess.h>
#include <configmanager.h>
#include <messagemanager.h>
#include <macrosmanager.h>
#include <projectmanager.h>
#include <editormanager.h>
#include <customvars.h>
#include <wx/xrc/xmlres.h>
#include "makefilegenerator.h"
#include "compileroptionsdlg.h"
#include "directcommands.h"

#include "compilerMINGW.h"
// TODO (mandrav#1#): Find out which compilers exist for linux and adapt this
#ifdef __WXMSW__
    #include "compilerMSVC.h"
    #include "compilerBCC.h"
    #include "compilerDMC.h"
    #include "compilerOW.h"
#endif
#include "compilerSDCC.h"

#define COLOUR_MAROON wxColour(0xa0, 0x00, 0x00)
#define COLOUR_NAVY   wxColour(0x00, 0x00, 0xa0)

CB_IMPLEMENT_PLUGIN(CompilerGCC);

// menu IDS
// just because we don't know other plugins' used identifiers,
// we use wxNewId() to generate a guaranteed unique ID ;), instead of enum
// (don't forget that, especially in a plugin)
int idTimerPollCompiler = XRCID("idTimerPollCompiler");
int idMenuCompile = XRCID("idCompilerMenuCompile");
int idMenuCompileTarget = XRCID("idCompilerMenuCompileTarget");
int idMenuCompileFromProjectManager = XRCID("idCompilerMenuCompileFromProjectManager");
int idMenuProjectCompilerOptions = XRCID("idCompilerMenuProjectCompilerOptions");
int idMenuTargetCompilerOptions = XRCID("idCompilerMenuTargetCompilerOptions");
int idMenuTargetCompilerOptionsSub = XRCID("idCompilerMenuTargetCompilerOptionsSub");
int idMenuCompileTargetFromProjectManager = XRCID("idCompilerMenuCompileTargetFromProjectManager");
int idMenuCompileFile = XRCID("idCompilerMenuCompileFile");
int idMenuCompileFileFromProjectManager = XRCID("idCompilerMenuCompileFileFromProjectManager");
int idMenuRebuild = XRCID("idCompilerMenuRebuild");
int idMenuRebuildTarget = XRCID("idCompilerMenuRebuildTarget");
int idMenuRebuildFromProjectManager = XRCID("idCompilerMenuRebuildFromProjectManager");
int idMenuRebuildTargetFromProjectManager = XRCID("idCompilerMenuRebuildTargetFromProjectManager");
int idMenuCompileAll = XRCID("idCompilerMenuCompileAll");
int idMenuRebuildAll = XRCID("idCompilerMenuRebuildAll");
int idMenuClean = XRCID("idCompilerMenuClean");
int idMenuDistClean = XRCID("idCompilerMenuDistClean");
int idMenuCleanTarget = XRCID("idCompilerMenuCleanTarget");
int idMenuDistCleanTarget = XRCID("idCompilerMenuDistCleanTarget");
int idMenuCleanFromProjectManager = XRCID("idCompilerMenuCleanFromProjectManager");
int idMenuDistCleanFromProjectManager = XRCID("idCompilerMenuDistCleanFromProjectManager");
int idMenuCleanTargetFromProjectManager = XRCID("idCompilerMenuCleanTargetFromProjectManager");
int idMenuDistCleanTargetFromProjectManager = XRCID("idCompilerMenuDistCleanTargetFromProjectManager");
int idMenuCompileAndRun = XRCID("idCompilerMenuCompileAndRun");
int idMenuRun = XRCID("idCompilerMenuRun");
int idMenuKillProcess = XRCID("idCompilerMenuKillProcess");
int idMenuSelectTarget = XRCID("idCompilerMenuSelectTarget");
int idMenuSelectTargetAll = XRCID("idCompilerMenuSelectTargetAll");
int idMenuSelectTargetOther[MAX_TARGETS]; // initialized in ctor
int idMenuNextError = XRCID("idCompilerMenuNextError");
int idMenuPreviousError = XRCID("idCompilerMenuPreviousError");
int idMenuClearErrors = XRCID("idCompilerMenuClearErrors");
int idMenuCreateDist = XRCID("idCompilerMenuCreateDist");
int idMenuExportMakefile = XRCID("idCompilerMenuExportMakefile");
int idMenuSettings = XRCID("idCompilerMenuSettings");

int idToolTarget = XRCID("idToolTarget");
int idToolTargetLabel = XRCID("idToolTargetLabel");

int idGCCProcess = wxNewId();

BEGIN_EVENT_TABLE(CompilerGCC, cbCompilerPlugin)
    EVT_UPDATE_UI_RANGE(idMenuCompile, idToolTargetLabel, CompilerGCC::OnUpdateUI)

    // these are loaded from the XRC
    EVT_UPDATE_UI(XRCID("idCompilerMenuCompile"), CompilerGCC::OnUpdateUI)
    EVT_UPDATE_UI(XRCID("idCompilerMenuRebuild"), CompilerGCC::OnUpdateUI)
    EVT_UPDATE_UI(XRCID("idCompilerMenuCompileAndRun"), CompilerGCC::OnUpdateUI)
    EVT_UPDATE_UI(XRCID("idCompilerMenuRun"), CompilerGCC::OnUpdateUI)

    EVT_IDLE(										CompilerGCC::OnIdle)
	EVT_TIMER(idTimerPollCompiler,                  CompilerGCC::OnTimer)

    EVT_MENU(idMenuRun,                             CompilerGCC::OnRun)
    EVT_MENU(idMenuCompileAndRun,                   CompilerGCC::OnCompileAndRun)
    EVT_MENU(idMenuCompile,                         CompilerGCC::OnCompile)
    EVT_MENU(idMenuCompileFromProjectManager,       CompilerGCC::OnCompile)
    EVT_MENU(idMenuCompileTargetFromProjectManager, CompilerGCC::OnCompile)
    EVT_MENU(idMenuCompileFile,                     CompilerGCC::OnCompileFile)
    EVT_MENU(idMenuCompileFileFromProjectManager,   CompilerGCC::OnCompileFile)
    EVT_MENU(idMenuRebuild,                         CompilerGCC::OnRebuild)
    EVT_MENU(idMenuRebuildFromProjectManager,       CompilerGCC::OnRebuild)
    EVT_MENU(idMenuRebuildTargetFromProjectManager, CompilerGCC::OnRebuild)
    EVT_MENU(idMenuCompileAll,                      CompilerGCC::OnCompileAll)
    EVT_MENU(idMenuRebuildAll,                      CompilerGCC::OnRebuildAll)
	EVT_MENU(idMenuProjectCompilerOptions,			CompilerGCC::OnProjectCompilerOptions)
	EVT_MENU(idMenuTargetCompilerOptions,			CompilerGCC::OnTargetCompilerOptions)
    EVT_MENU(idMenuClean,                           CompilerGCC::OnClean)
    EVT_MENU(idMenuDistClean,                       CompilerGCC::OnDistClean)
    EVT_MENU(idMenuCleanFromProjectManager,         CompilerGCC::OnClean)
    EVT_MENU(idMenuDistCleanFromProjectManager,     CompilerGCC::OnDistClean)
    EVT_MENU(idMenuCleanTargetFromProjectManager,   CompilerGCC::OnClean)
    EVT_MENU(idMenuDistCleanTargetFromProjectManager, CompilerGCC::OnDistClean)
    EVT_MENU(idMenuKillProcess,                     CompilerGCC::OnKillProcess)
	EVT_MENU(idMenuSelectTargetAll,					CompilerGCC::OnSelectTarget)
	EVT_MENU(idMenuNextError,						CompilerGCC::OnNextError)
	EVT_MENU(idMenuPreviousError,					CompilerGCC::OnPreviousError)
	EVT_MENU(idMenuClearErrors,						CompilerGCC::OnClearErrors)
    EVT_MENU(idMenuCreateDist,                      CompilerGCC::OnCreateDist)
    EVT_MENU(idMenuExportMakefile,                  CompilerGCC::OnExportMakefile)
    EVT_MENU(idMenuSettings,                        CompilerGCC::OnConfig)

	EVT_COMBOBOX(idToolTarget,						CompilerGCC::OnSelectTarget)

	EVT_PROJECT_ACTIVATE(CompilerGCC::OnProjectActivated)
	//EVT_PROJECT_POPUP_MENU(CompilerGCC::OnProjectPopupMenu)

	EVT_PIPEDPROCESS_STDOUT(idGCCProcess, CompilerGCC::OnGCCOutput)
	EVT_PIPEDPROCESS_STDERR(idGCCProcess, CompilerGCC::OnGCCError)
	EVT_PIPEDPROCESS_TERMINATED(idGCCProcess, CompilerGCC::OnGCCTerminated)
END_EVENT_TABLE()

CompilerGCC::CompilerGCC()
    : m_CompilerIdx(-1),
    m_PageIndex(-1),
	m_ListPageIndex(-1),
    m_Menu(0L),
    m_TargetMenu(0L),
	m_pToolbar(0L),
	m_TargetIndex(-1),
	m_ErrorsMenu(0L),
    m_Project(0L),
    m_Process(0L),
    m_pTbar(0L),
    m_Pid(0),
    m_Log(0L),
	m_pListLog(0L),
	m_ToolTarget(0L),
	m_ToolTargetLabel(0L),
	m_IsRun(false),
	m_RunAfterCompile(false),
	m_DoAllProjects(mpjNone),
	m_BackupActiveProject(0L),
	m_ProjectIndex(0),
	m_LastExitCode(0),
	m_HasTargetAll(false),
	m_QueueIndex(0),
	m_DeleteTempMakefile(true)
{
    Manager::Get()->Loadxrc(_T("/compiler_gcc.zip#zip:*.xrc"));

    m_Type = ptCompiler;
    m_PluginInfo.name = _T("Compiler");
    m_PluginInfo.title = _T("Compiler");
    m_PluginInfo.version = _T("1.0");
    m_PluginInfo.description = _("This plugin is an interface to various compilers:\n\n"
                               "\tGNU GCC compiler\n"
                               "\tMicrosoft Visual C++ Free Toolkit 2003\n"
                               "\tBorland C++ Compiler 5.5");
    m_PluginInfo.author = _T("Yiannis An. Mandravellos");
    m_PluginInfo.authorEmail = _T("info@codeblocks.org");
    m_PluginInfo.authorWebsite = _T("www.codeblocks.org");
    m_PluginInfo.thanksTo = _("All the free (and not) compilers out there");
	m_PluginInfo.hasConfigure = false;

    m_timerIdleWakeUp.SetOwner(this, idTimerPollCompiler);

	for (int i = 0; i < MAX_TARGETS; ++i)
		idMenuSelectTargetOther[i] = wxNewId();
#ifndef __WXMSW__
	m_ConsoleShell = ConfigManager::Get()->Read(_T("/compiler_gcc/console_shell"), DEFAULT_CONSOLE_SHELL);
#endif

	// register built-in compilers
	CompilerFactory::RegisterCompiler(new CompilerMINGW);
#ifdef __WXMSW__
	CompilerFactory::RegisterCompiler(new CompilerMSVC);
	CompilerFactory::RegisterCompiler(new CompilerBCC);
	CompilerFactory::RegisterCompiler(new CompilerDMC);
	CompilerFactory::RegisterCompiler(new CompilerOW);
#endif
	CompilerFactory::RegisterCompiler(new CompilerSDCC);

	// register (if any) user-copies of built-in compilers
	CompilerFactory::RegisterUserCompilers();

	ConfigManager::AddConfiguration(m_PluginInfo.title, _T("/compiler_gcc"));
}

CompilerGCC::~CompilerGCC()
{
    DoDeleteTempMakefile();
	if (m_ToolTarget)
		delete m_ToolTarget;
	CompilerFactory::UnregisterCompilers();
}

void CompilerGCC::OnAttach()
{
    wxFont font(8, wxMODERN, wxNORMAL, wxNORMAL);
    MessageManager* msgMan = Manager::Get()->GetMessageManager();

	// create compiler's log
    m_Log = new SimpleTextLog(msgMan, _("Build log"));
    m_Log->GetTextControl()->SetFont(font);
    m_PageIndex = msgMan->AddLog(m_Log);

    // set log image
	wxBitmap bmp;
	wxString prefix = ConfigManager::Get()->Read(_T("data_path")) + _T("/images/");
    bmp.LoadFile(prefix + _T("misc_16x16.png"), wxBITMAP_TYPE_PNG);
    Manager::Get()->GetMessageManager()->SetLogImage(m_Log, bmp);

	// create warnings/errors log
	wxArrayString titles;
	int widths[3] = {128, 48, 640};
	titles.Add(_("File"));
	titles.Add(_("Line"));
	titles.Add(_("Message"));

	m_pListLog = new CompilerMessages(msgMan, _("Build messages"), 3, widths, titles);
	m_pListLog->SetCompilerErrors(&m_Errors);
    m_pListLog->GetListControl()->SetFont(font);
	m_ListPageIndex = msgMan->AddLog(m_pListLog);

    // set log image
    bmp.LoadFile(prefix + _T("flag_16x16.png"), wxBITMAP_TYPE_PNG);
    Manager::Get()->GetMessageManager()->SetLogImage(m_pListLog, bmp);

    // set default compiler for new projects
    CompilerFactory::SetDefaultCompilerIndex(ConfigManager::Get()->Read(_T("/compiler_gcc/default_compiler"), (long int)0));
	LoadOptions();
	SetupEnvironment();
}

void CompilerGCC::OnRelease(bool appShutDown)
{
    DoDeleteTempMakefile();
	SaveOptions();
    ConfigManager::Get()->Write(_T("/compiler_gcc/default_compiler"), CompilerFactory::GetDefaultCompilerIndex());
	if (Manager::Get()->GetMessageManager())
	{
        Manager::Get()->GetMessageManager()->DeletePage(m_ListPageIndex);
        Manager::Get()->GetMessageManager()->DeletePage(m_PageIndex);
    }

	if (appShutDown)
		return; // no need to continue if app is shutting down

	DoClearTargetMenu();

//	if (m_Menu)
//	{
//		wxMenuBar* mBar = Manager::Get()->GetAppWindow()->GetMenuBar();
//		int pos = mBar->FindMenu(_("&Compile"));
//		if (pos != wxNOT_FOUND)
//			mBar->Remove(pos);
//		delete m_Menu;
//		m_Menu = 0L;
//	}

	if (m_pToolbar)
	{
		m_pToolbar->DeleteTool(idMenuCompile);
		m_pToolbar->DeleteTool(idMenuRun);
		m_pToolbar->DeleteTool(idMenuCompileAndRun);
		m_pToolbar->DeleteTool(idMenuRebuild);

		m_pToolbar->DeleteTool(idToolTarget);
		delete m_ToolTarget;
		m_ToolTarget = 0L;

		m_pToolbar->DeleteTool(idToolTargetLabel);
		delete m_ToolTargetLabel;
		m_ToolTargetLabel = 0L;
	}
}

int CompilerGCC::Configure(cbProject* project, ProjectBuildTarget* target)
{
    CompilerOptionsDlg dlg(Manager::Get()->GetAppWindow(), this, project, target);
    if(dlg.ShowModal()==wxID_OK)
    {
      m_ConsoleShell = ConfigManager::Get()->Read(_T("/compiler_gcc/console_shell"), DEFAULT_CONSOLE_SHELL);
      SaveOptions();
      SetupEnvironment();
    }
    return 0;
}

void CompilerGCC::OnConfig(wxCommandEvent& event)
{
    Configure(NULL);
}

void CompilerGCC::BuildMenu(wxMenuBar* menuBar)
{
	if (!m_IsAttached)
		return;
	if (m_Menu)
		return;

    m_Menu=Manager::Get()->LoadMenu(_T("compiler_menu"),true);

	// target selection menu
	wxMenuItem *tmpitem=m_Menu->FindItem(idMenuSelectTarget,NULL);
    m_TargetMenu = tmpitem ? tmpitem->GetSubMenu() : new wxMenu(_T(""));
    DoRecreateTargetMenu();
	//m_Menu->Append(idMenuSelectTarget, _("Select target..."), m_TargetMenu);

	// ok, now, where do we insert?
	// three possibilities here:
	// a) locate "Debug" menu and insert before it
	// b) locate "Project" menu and insert after it
	// c) if not found (?), insert at pos 5
	int finalPos = 5;
	int projMenuPos = menuBar->FindMenu(_("&Debug"));
	if (projMenuPos != wxNOT_FOUND)
		finalPos = projMenuPos;
	else
	{
		projMenuPos = menuBar->FindMenu(_("&Project"));
		if (projMenuPos != wxNOT_FOUND)
			finalPos = projMenuPos + 1;
	}
    menuBar->Insert(finalPos, m_Menu, _("&Build"));

    // now add some entries in Project menu
	projMenuPos = menuBar->FindMenu(_("&Project"));
	if (projMenuPos != wxNOT_FOUND)
	{
        wxMenu* prj = menuBar->GetMenu(projMenuPos);
        // look if we have a "Properties" item. If yes, we 'll insert
        // before it, else we 'll just append...
        size_t propsPos = prj->GetMenuItemCount(); // append
        int propsID = prj->FindItem(_("Properties"));
        if (propsID != wxNOT_FOUND)
            prj->FindChildItem(propsID, &propsPos);
        prj->Insert(propsPos, idMenuProjectCompilerOptions, _("Build options"), _("Set the project's build options"));
        prj->InsertSeparator(propsPos);
    }
    // Add entry in settings menu (outside "plugins")
    int settingsMenuPos = menuBar->FindMenu(_("&Settings"));
    if (settingsMenuPos != wxNOT_FOUND)
    {
        wxMenu* settingsmenu = menuBar->GetMenu(settingsMenuPos);
        settingsmenu->Insert(2,idMenuSettings,_("&Compiler"),_("Global Compiler Options"));
    }
}

void CompilerGCC::BuildModuleMenu(const ModuleType type, wxMenu* menu, const wxString& arg)
{
	if (!m_IsAttached)
		return;
    // we 're only interested in project manager's menus
    if (type != mtProjectManager || !menu || m_Process)
        return;

	if (!CheckProject())
		return;

    FileType ft = FileTypeOf(arg);

    if (arg.IsEmpty())
    {
        // popup menu in empty space in ProjectManager
        menu->Append(idMenuCompileAll, _("Build all projects"));
        menu->Append(idMenuRebuildAll, _("Rebuild all projects"));
    }
    else
    {
        // see if the arg is a project name
        bool found = false;
        ProjectsArray* array = Manager::Get()->GetProjectManager()->GetProjects();
        if (array)
        {
            for (size_t i = 0; i < array->GetCount(); ++i)
            {
                cbProject* cur = array->Item(i);
                if (cur && cur->GetTitle() == arg)
                {
                    found = true;
                    break;
                }
            }
        }

        if (found)
        {
            // popup menu on a project
            menu->AppendSeparator();
            menu->Append(idMenuCompileFromProjectManager, _("Build\tCtrl-F9"));
            menu->Append(idMenuRebuildFromProjectManager, _("Rebuild\tCtrl-F11"));
            menu->Append(idMenuCleanFromProjectManager, _("Clean"));
            menu->Append(idMenuDistCleanFromProjectManager, _("Dist-clean"));
            wxMenu* subMenu = new wxMenu();
            subMenu->Append(idMenuCompileTargetFromProjectManager, _("Build"));
            subMenu->Append(idMenuRebuildTargetFromProjectManager, _("Rebuild"));
            subMenu->Append(idMenuCleanTargetFromProjectManager, _("Clean"));
            subMenu->Append(idMenuDistCleanTargetFromProjectManager, _("Dist-clean"));
            subMenu->AppendSeparator();
            subMenu->Append(idMenuTargetCompilerOptions, _("Build options"));
            menu->Append(idMenuTargetCompilerOptionsSub, _("Specific build target..."), subMenu);
            menu->AppendSeparator();
            menu->Append(idMenuProjectCompilerOptions, _("Build options"));
        }
        else if (ft == ftSource || ft == ftHeader)
        {
            // popup menu on a compilable file
            menu->AppendSeparator();
            menu->Append(idMenuCompileFileFromProjectManager, _("Compile file"));
        }
    }
}

bool CompilerGCC::BuildToolBar(wxToolBar* toolBar)
{
	if (!m_IsAttached || !toolBar)
		return false;
    m_pTbar = toolBar;
    wxString my_16x16=Manager::isToolBar16x16(toolBar) ? _T("_16x16") : _T("");
    Manager::Get()->AddonToolBar(toolBar,_T("compiler_toolbar")+my_16x16);

    // neither the generic nor Motif native toolbars really support this
    #if (wxUSE_TOOLBAR_NATIVE && !USE_GENERIC_TBAR) && !defined(__WXMOTIF__) && !defined(__WXX11__) && !defined(__WXMAC__)
    m_ToolTarget = XRCCTRL(*toolBar, "idToolTarget", wxComboBox);
    #endif
    toolBar->Realize();
    DoRecreateTargetMenu(); // make sure the tool target combo is up-to-date
    return true;
}

void CompilerGCC::SetupEnvironment()
{
    if (!CompilerFactory::CompilerIndexOK(m_CompilerIdx))
        return;

    m_EnvironmentMsg.Clear();

	wxString path;
	Manager::Get()->GetMessageManager()->DebugLog(_("Setting up compiler environment..."));

    // reset PATH to original value
    if (!m_OriginalPath.IsEmpty())
        wxSetEnv(_T("PATH"), m_OriginalPath);

    // look for valid compiler in path
	if (wxGetEnv(_T("PATH"), &path))
	{
        if (m_OriginalPath.IsEmpty())
            m_OriginalPath = path;

        wxArrayInt compilers;
        if(m_Project)
        {
            for (int x = 0; x < m_Project->GetBuildTargetsCount(); ++x)
            {
                ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
                int idx = target->GetCompilerIndex();

                // one time per compiler
                if (compilers.Index(idx) != wxNOT_FOUND || !CompilerFactory::CompilerIndexOK(idx))
                    continue;
                compilers.Add(idx);
                SetEnvironmentForCompilerIndex(idx, path);
            }
        }
        else
            SetEnvironmentForCompilerIndex(CompilerFactory::GetDefaultCompilerIndex(), path);
	}
	else
		m_EnvironmentMsg = _("Could not read the PATH environment variable!\n"
					"This can't be good. There may be problems running "
					"system commands and the application might not behave "
					"the way it was designed to...");
//    wxGetEnv("PATH", &path);
//    Manager::Get()->GetMessageManager()->Log(m_PageIndex, "PATH set to: %s", path.c_str());
}

void CompilerGCC::SetEnvironmentForCompilerIndex(int idx, wxString& envPath)
{
    if (!CompilerFactory::CompilerIndexOK(idx))
        return;

    Compiler* compiler = CompilerFactory::Compilers[idx];
    wxString sep = wxFileName::GetPathSeparator();

    wxString masterPath = compiler->GetMasterPath();
    while (masterPath.Last() == '\\' || masterPath.Last() == '/')
        masterPath.RemoveLast();
    wxString gcc = compiler->GetPrograms().C;
    const wxArrayString& extraPaths = compiler->GetExtraPaths();

    wxPathList pathList;
    pathList.Add(masterPath + sep + _T("bin"));
    for (unsigned int i = 0; i < extraPaths.GetCount(); ++i)
    {
        if (!extraPaths[i].IsEmpty())
            pathList.Add(extraPaths[i]);
    }
    pathList.AddEnvList(_T("PATH"));
    wxString binPath = pathList.FindAbsoluteValidPath(gcc);
    // it seems, under Win32, the above command doesn't search in paths with spaces...
    // look directly for the file in question in masterPath
    if (binPath.IsEmpty() || !pathList.Member(wxPathOnly(binPath)))
    {
        if (wxFileExists(masterPath + sep + _T("bin") + sep + gcc))
            binPath = masterPath + sep + _T("bin");
        else if (wxFileExists(masterPath + sep + gcc))
            binPath = masterPath;
        else
        {
            for (unsigned int i = 0; i < extraPaths.GetCount(); ++i)
            {
                if (!extraPaths[i].IsEmpty())
                {
                    if (wxFileExists(extraPaths[i] + sep + gcc))
                    {
                        binPath = extraPaths[i];
                        break;
                    }
                }
            }
        }
    }

    if (binPath.IsEmpty() || !pathList.Member(wxPathOnly(binPath)))
    {
        m_EnvironmentMsg << _("Can't find compiler executable in your search path for ") << compiler->GetName() << _T('\n');
        Manager::Get()->GetMessageManager()->DebugLog(_("Can't find compiler executable in your search path (%s)..."), compiler->GetName().c_str());
    }
    else
    {
        m_EnvironmentMsg.Clear();
#ifdef __WXMSW__
#define PATH_SEP _T(";")
#else
#define PATH_SEP _T(":")
#endif
        // add extra compiler paths in PATH
        wxString oldpath = envPath;
        envPath.Clear();
        for (unsigned int i = 0; i < extraPaths.GetCount(); ++i)
        {
            if (!extraPaths[i].IsEmpty())
            {
                envPath += extraPaths[i] + PATH_SEP;
            }
        }
        envPath = envPath + oldpath;

        // add bin path to PATH env. var.
        if (wxFileExists(masterPath + sep + _T("bin") + sep + gcc))
            envPath = masterPath + sep + _T("bin") + PATH_SEP + envPath;
        else if (wxFileExists(masterPath + sep + gcc))
            envPath = masterPath + PATH_SEP + envPath;
        wxSetEnv(_T("PATH"), envPath);
#undef PATH_SEP
    }
}

void CompilerGCC::SaveOptions()
{
	// save compiler sets
    CompilerFactory::SaveSettings();
}

void CompilerGCC::LoadOptions()
{
    // load compiler sets
    CompilerFactory::LoadSettings();
}

int CompilerGCC::GetCurrentCompilerIndex()
{
    return CompilerFactory::CompilerIndexOK(m_CompilerIdx) ? m_CompilerIdx : 0;
}

void CompilerGCC::SwitchCompiler(int compilerIdx)
{
    if (!CompilerFactory::CompilerIndexOK(compilerIdx))
        return;
    m_CompilerIdx = compilerIdx;
    SetupEnvironment();
}

void CompilerGCC::AskForActiveProject()
{
    m_Project = Manager::Get()->GetProjectManager()->GetActiveProject();
}

bool CompilerGCC::CheckProject()
{
    AskForActiveProject();
    if (m_Project && m_Project->GetCompilerIndex() != m_CompilerIdx)
        SwitchCompiler(m_Project->GetCompilerIndex());
    return m_Project;
}

wxString CompilerGCC::ProjectMakefile()
{
    AskForActiveProject();
    if (!m_Project)
        return wxEmptyString;

    return m_Project->GetMakefile();
}

void CompilerGCC::ClearLog()
{
    if (m_Log)
        m_Log->GetTextControl()->Clear();
}

FileTreeData* CompilerGCC::DoSwitchProjectTemporarily()
{
	wxTreeCtrl* tree = Manager::Get()->GetProjectManager()->GetTree();
	wxTreeItemId sel = tree->GetSelection();
    FileTreeData* ftd = (FileTreeData*)tree->GetItemData(sel);
    if (!ftd)
        return 0L;
    // copy ftd to a new instance, because after the SetProject() call
    // that follows, ftd will no longer be valid...
    FileTreeData* newFtd = new FileTreeData(ftd->GetProject(), ftd->GetFileIndex());
    Manager::Get()->GetProjectManager()->SetProject(ftd->GetProject(), false);
    AskForActiveProject();

    return newFtd;
}

int CompilerGCC::DoRunQueue()
{
    wxLogNull ln;

	// leave if already running
	if (m_Process)
		return -2;

    MessageManager* msgMan = Manager::Get()->GetMessageManager();
    msgMan->SwitchTo(m_PageIndex);

	// leave if no active project
    AskForActiveProject();

    // make sure all project files are saved
    if (m_Project && !m_Project->SaveAllFiles())
        msgMan->Log(_("Could not save all files..."));

    if (m_Queue.GetCount() == 0)
	{
        m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(*wxBLUE, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
        msgMan->Log(m_PageIndex, _("Nothing to be done."));
        m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
        m_LastExitCode = 0;
        OnJobEnd();
        return 0;
	}

	// leave if no commands in queue
    if (m_QueueIndex >= m_Queue.GetCount())
	{
        msgMan->DebugLog(_("Queue has been emptied! (count=%d, index=%d)"), m_Queue.GetCount(), m_QueueIndex);
        return -3;
	}

	m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
    wxString dir;// = m_Project->GetBasePath();
    wxString cmd;

    // loop added for compiler log when not working with Makefiles
    wxString mySimpleLog = wxString(COMPILER_SIMPLE_LOG);
    wxString myTargetChange = wxString(COMPILER_TARGET_CHANGE);
    while (true)
    {
        cmd = m_Queue[m_QueueIndex];
//	    msgMan->Log(m_PageIndex, "cmd='%s' in '%s'", cmd.c_str(), m_CdRun.c_str());

        // logging
        if (cmd.StartsWith(mySimpleLog))
        {
            cmd.Remove(0, mySimpleLog.Length());
            msgMan->Log(m_PageIndex, cmd);
        }
        // compiler change
        else if (cmd.StartsWith(myTargetChange))
        {
            cmd.Remove(0, myTargetChange.Length());
            // using other compiler now: find it and set it
            ProjectBuildTarget* bt = m_Project->GetBuildTarget(cmd);
            if (bt)
            {
                SwitchCompiler(bt->GetCompilerIndex());
                // re-apply the env vars for this target
                if (CompilerFactory::CompilerIndexOK(m_CompilerIdx))
                    CompilerFactory::Compilers[m_CompilerIdx]->GetCustomVars().ApplyVarsToEnvironment();
                m_Project->GetCustomVars().ApplyVarsToEnvironment();
                bt->GetCustomVars().ApplyVarsToEnvironment();
            }
            else
                msgMan->Log(m_PageIndex, _("Can't locate target '%s'!"), cmd.c_str());
        }
        else
        {
        	// compile command; apply custom vars
        	Manager::Get()->GetMacrosManager()->ReplaceEnvVars(cmd);
            break;
        }

        ++m_QueueIndex;
        if (m_QueueIndex >= m_Queue.GetCount())
        {
            msgMan->Log(m_PageIndex, _("Nothing to be done."));
            m_LastExitCode = 0;
            OnJobEnd();
            return 0;
        }
    }

    // if message manager is auto-hiding, this will lock it open
    Manager::Get()->GetMessageManager()->LockOpen();

	bool pipe = true;
	int flags = wxEXEC_ASYNC;
	if (m_RunAfterCompile && m_IsRun && m_QueueIndex == m_Queue.GetCount() - 1)
	{
		pipe = false; // no need to pipe output channels...
		flags |= wxEXEC_NOHIDE;
		m_IsRun = false;
		dir = m_CdRun;
#ifndef __WXMSW__
		wxSetEnv(_T("LD_LIBRARY_PATH"), _T("."));
#endif
	}

    m_Process = new PipedProcess((void**)&m_Process, this, idGCCProcess, pipe, dir);
    m_Pid = wxExecute(cmd, flags, m_Process);
    if ( !m_Pid )
    {
        m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(*wxRED, *wxWHITE));
        msgMan->Log(m_PageIndex, _("Execution of '%s' in '%s' failed."), m_Queue[m_QueueIndex].c_str(), wxGetCwd().c_str());
		m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
        delete m_Process;
        m_Process = NULL;
        m_Queue.Clear();
    }
    else
        m_timerIdleWakeUp.Start(100);

    return 0;
}

void CompilerGCC::DoClearTargetMenu()
{
    if (m_TargetMenu)
	{
		wxMenuItemList& items = m_TargetMenu->GetMenuItems();
		while (wxMenuItemList::Node* node = items.GetFirst())
		{
            if (node->GetData())
                m_TargetMenu->Delete(node->GetData());
        }
// mandrav: The following lines DO NOT clear the menu!
//		wxMenuItemList& items = m_TargetMenu->GetMenuItems();
//		bool olddelete=items.GetDeleteContents();
//		items.DeleteContents(true);
//		items.Clear();
//		items.DeleteContents(olddelete);
	}
	m_HasTargetAll = false;
}

void CompilerGCC::DoRecreateTargetMenu()
{
	if (!m_IsAttached)
		return;

	DoClearTargetMenu();
	if (m_ToolTarget)
		m_ToolTarget->Clear();
	if (!CheckProject())
		return;

    if (m_Project->GetBuildTargetsCount() == 0)
        return;

    // find out if at least one target is included in "all"
    // (if not, no need to add "all" in menus and target combo)
    bool atLeastOneBuildableTarget = false;
    for (int i = 0; i < m_Project->GetBuildTargetsCount(); ++i)
    {
        ProjectBuildTarget* bt = m_Project->GetBuildTarget(i);
        if (bt->GetIncludeInTargetAll())
        {
            atLeastOneBuildableTarget = true;
            break;
        }
    }

    m_TargetIndex = m_Project->GetActiveBuildTarget();
    if (atLeastOneBuildableTarget)
    {
        if (m_TargetMenu)
            m_TargetMenu->AppendCheckItem(idMenuSelectTargetAll, _("All"), _("Compile target 'all' in current project"));
        if (m_ToolTarget)
            m_ToolTarget->Append(_("All"));
    }
    else
    {
        if (m_TargetIndex == -1)
            m_TargetIndex = 0;
    }
    m_HasTargetAll = atLeastOneBuildableTarget;

    int targetsCount = m_Project->GetBuildTargetsCount();
    for (int x = 0; x < targetsCount; ++x)
    {
        ProjectBuildTarget* target = m_Project->GetBuildTarget(x);
        if (!target)
            break;

		wxString caption;
		caption.Printf(_("Compile target '%s' in current project"), target->GetTitle().c_str());
		if (m_TargetMenu)
            m_TargetMenu->AppendCheckItem(idMenuSelectTargetOther[x], target->GetTitle(), caption);
		if (m_ToolTarget)
			m_ToolTarget->Append(target->GetTitle());
	}
	Connect( idMenuSelectTargetOther[0],  idMenuSelectTargetOther[MAX_TARGETS - 1],
			wxEVT_COMMAND_MENU_SELECTED,
			(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
			&CompilerGCC::OnSelectTarget );
	DoUpdateTargetMenu();

    SwitchCompiler(m_Project->GetCompilerIndex());
}

void CompilerGCC::DoUpdateTargetMenu()
{
	if (!m_TargetMenu)
		return;

    if (!m_HasTargetAll && m_TargetIndex == -1)
        m_TargetIndex = 0;

    if (m_Project)
        m_Project->SetActiveBuildTarget(m_TargetIndex);

	m_TargetMenu->Check(idMenuSelectTargetAll, m_TargetIndex == -1);
	for (int i = 0; i < MAX_TARGETS; ++i)
	{
		m_TargetMenu->Check(idMenuSelectTargetOther[i], i == m_TargetIndex);
	}
	if (m_ToolTarget)
		m_ToolTarget->SetSelection(m_TargetIndex + (m_HasTargetAll ? 1 : 0));
}

bool CompilerGCC::DoPrepareMultiProjectCommand(MultiProjectJob job)
{
    ProjectManager* prjMan = Manager::Get()->GetProjectManager();
    ProjectsArray* projects = prjMan->GetProjects();

    if (projects->GetCount() <= 1)
        return false;

    m_Queue.Clear();
	AskForActiveProject();
	m_BackupActiveProject = m_Project;
	m_ProjectIndex = 0;
	m_DoAllProjects = job;
	prjMan->SetProject(projects->Item(0), false);
	AskForActiveProject();

	return true;
}

void CompilerGCC::DoPrepareQueue()
{
	if (m_LastTempMakefile.IsEmpty() || m_Queue.GetCount() == 0)
	{
		m_QueueIndex = 0;
		if (m_DoAllProjects == mpjNone)
		{
            ClearLog();
            DoClearErrors();
        }
		DoCreateMakefile();
		wxStartTimer();
	}
}

ProjectBuildTarget* CompilerGCC::DoAskForTarget()
{
    if (!CheckProject())
        return 0L;

	return m_Project->GetBuildTarget(m_TargetIndex);
}

int CompilerGCC::DoGUIAskForTarget()
{
    if (!CheckProject())
        return -1;

	return m_Project->SelectTarget(m_TargetIndex);
}

void CompilerGCC::DoDeleteTempMakefile()
{
    // delete temp Makefile
    if (m_DeleteTempMakefile && !m_LastTempMakefile.IsEmpty())
        wxRemoveFile(m_LastTempMakefile);
    m_LastTempMakefile = _T("");
}

bool CompilerGCC::UseMake(ProjectBuildTarget* target)
{
    int idx = m_CompilerIdx;
    if (target)
        idx = target->GetCompilerIndex();
    else if (m_Project)
        idx = m_Project->GetCompilerIndex();
    if (CompilerFactory::CompilerIndexOK(idx))
        return CompilerFactory::Compilers[idx]->GetSwitches().buildMethod == cbmUseMake;
    return false;
}

bool CompilerGCC::CompilerValid(ProjectBuildTarget* target)
{
	int idx = target ? target->GetCompilerIndex() : (m_Project ? m_Project->GetCompilerIndex() : CompilerFactory::GetDefaultCompilerIndex());
	bool ret = CompilerFactory::CompilerIndexOK(idx);
	if (!ret)
	{
		wxString msg;
		msg.Printf(_("This %s is configured to use an invalid compiler.\nThe operation failed..."), target ? _("target") : _("project"));
		wxMessageBox(msg, _("Error"), wxICON_ERROR);
	}
	return ret;
}

bool CompilerGCC::DoCreateMakefile(bool temporary, const wxString& makefile)
{
    DoDeleteTempMakefile();

    // display error about incorrect compile environment
	if (!m_EnvironmentMsg.IsEmpty())
	{
		wxMessageBox(m_EnvironmentMsg, _("Error"), wxICON_ERROR);
		m_EnvironmentMsg.Clear(); // once is enough, per session...
	}

	// verify current project
    AskForActiveProject();
    if (!m_Project)
        return false;

    if (UseMake())
    {
        // if the project has a custom makefile, use that (i.e. don't create makefile)
        if (temporary && m_Project->IsMakefileCustom())
        {
            m_LastTempMakefile = m_Project->GetMakefile();
            m_DeleteTempMakefile = false;
            return true;
        }

        // invoke Makefile generation
        if (temporary)
            m_LastTempMakefile = wxFileName::CreateTempFileName(_T("cbmk"), 0L);
        else
        {
            m_LastTempMakefile = makefile;
            if (m_LastTempMakefile.IsEmpty())
            {
                m_LastTempMakefile = ProjectMakefile();
                if (m_LastTempMakefile.IsEmpty())
                    m_LastTempMakefile = _T("Makefile");
            }
        }
    }

    PrintBanner();
	wxSetWorkingDirectory(m_Project->GetBasePath());

    if (UseMake())
    {
        MakefileGenerator generator(this, m_Project, m_LastTempMakefile, m_PageIndex);
        bool ret = generator.CreateMakefile();

        // if exporting Makefile, reset variable so that it's not deleted on
        // next Makefile generation :)
        if (!temporary)
            m_LastTempMakefile = _T("");
        m_DeleteTempMakefile = temporary;

        return ret;
    }
    return true;
}

void CompilerGCC::PrintBanner()
{
	if (!CompilerValid())
		return;
    if (!m_Project)
        return;
    Manager::Get()->GetMessageManager()->SwitchTo(m_PageIndex);
    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Project   : %s"), m_Project->GetTitle().c_str());
    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Compiler  : %s (%s)"), CompilerFactory::Compilers[m_Project->GetCompilerIndex()]->GetName().c_str(),
                                                                                    CompilerFactory::Compilers[m_Project->GetCompilerIndex()]->GetSwitches().buildMethod == cbmUseMake ? _("using GNU \"make\"") : _("called directly"));
    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Directory : %s"), m_Project->GetBasePath().c_str());
    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _T("--------------------------------------------------------------------------------"));
}

void CompilerGCC::DoGotoNextError()
{
	m_Errors.Next();
    m_pListLog->FocusError(m_Errors.GetFocusedError());
}

void CompilerGCC::DoGotoPreviousError()
{
	m_Errors.Previous();
    m_pListLog->FocusError(m_Errors.GetFocusedError());
}

void CompilerGCC::DoClearErrors()
{
	m_Errors.Clear();
	m_pListLog->Clear();
}

int CompilerGCC::Run(ProjectBuildTarget* target)
{
    if (!CheckProject())
        return -1;
	DoPrepareQueue();
	if (!CompilerValid(target))
		return -1;

    Manager::Get()->GetMessageManager()->Open();

	if (!target)
	{
		if (m_TargetIndex == -1) // only ask for target if target 'all' is selected
		{
			int idx = -1;
			int bak = m_TargetIndex;
			if (m_Project->GetBuildTargetsCount() == 1)
				idx = 0;
			else
				idx = DoGUIAskForTarget();

			m_TargetIndex = idx;
			target = DoAskForTarget();
			m_TargetIndex = bak;
		}
		else
			target = DoAskForTarget();
	}

    if (!target)
		return -1;

    wxString out = UnixFilename(target->GetOutputFilename());
    Manager::Get()->GetMacrosManager()->ReplaceEnvVars(out);

    wxString cmd;
    wxFileName f(out);
    f.MakeAbsolute(m_Project->GetBasePath());
//    m_CdRun = f.GetPath(wxPATH_GET_VOLUME);
    m_CdRun = target->GetWorkingDir();

    // for console projects, use helper app to wait for a key after
    // execution ends...
	if (target->GetTargetType() == ttConsoleOnly)
	{
#ifndef __WXMSW__
        // for non-win platforms, use m_ConsoleShell to run the console app
        wxString shell = m_ConsoleShell;
        shell.Replace(_T("$TITLE"), _T("'") + m_Project->GetTitle() + _T("'"));
        cmd << shell << _T(" ");
#endif
        // should console runner be used?
        if (target->GetUseConsoleRunner())
        {
            wxString baseDir = ConfigManager::Get()->Read(_T("/app_path"));
#ifdef __WXMSW__
	#define CONSOLE_RUNNER "console_runner.exe"
#else
	#define CONSOLE_RUNNER "console_runner"
#endif
            if (wxFileExists(baseDir + wxT("/" CONSOLE_RUNNER)))
                cmd << baseDir << wxT("/" CONSOLE_RUNNER " ");
        }
    }

	if (target->GetTargetType() == ttDynamicLib ||
		target->GetTargetType() == ttStaticLib)
	{
		// check for hostapp
		if (target->GetHostApplication().IsEmpty())
		{
			wxMessageBox(_("You must select a host application to \"run\" a library..."));
			return -1;
		}
		wxString tmp = target->GetHostApplication();
        Manager::Get()->GetMacrosManager()->ReplaceEnvVars(tmp);
		cmd << _T("\"") << tmp << _T("\" ") << target->GetExecutionParameters();
	}
	else if (target->GetTargetType() != ttCommandsOnly)
    {
        cmd << _T("\"");
		cmd << f.GetFullPath();
		cmd << _T("\" ");
		cmd << target->GetExecutionParameters();
    }
    else
    {
        // commands-only target?
        wxMessageBox(_("You can't \"run\" a commands-only target..."));
        return -1;
    }

    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Checking for existence: %s"), out.c_str());
    if (!wxFileExists(out))
    {
    	int ret = wxMessageBox(_("It seems that this project has not been built yet.\n"
                                "Do you want to build it now?"),
                                _("Information"),
                                wxYES | wxNO | wxCANCEL | wxICON_QUESTION);
        switch (ret)
        {
        	case wxYES:
        	{
        		Compile(target);
        		return -1;
        	}
            case wxNO:
                break;
            default:
                return -1;
        }
    }

    Manager::Get()->GetMacrosManager()->ReplaceEnvVars(m_CdRun);
    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Executing: %s (in %s)"), cmd.c_str(), m_CdRun.c_str());
	m_Queue.Add(cmd);

	m_IsRun = true;

	return 0;
}

int CompilerGCC::Clean(ProjectBuildTarget* target)
{
	DoPrepareQueue();
	if (!CompilerValid(target))
		return -1;

    if (CompilerFactory::CompilerIndexOK(m_CompilerIdx))
        CompilerFactory::Compilers[m_CompilerIdx]->GetCustomVars().ApplyVarsToEnvironment();
    m_Project->GetCustomVars().ApplyVarsToEnvironment();

    Manager::Get()->GetMessageManager()->Open();

    wxSetWorkingDirectory(m_Project->GetBasePath());
    if (UseMake(target))
    {
        wxString cmd;
        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        if (target)
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" clean_") << target->GetTitle();
        else
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" clean");
        m_Queue.Add(cmd);
        return DoRunQueue();
    }
    else
    {
        DirectCommands dc(this, CompilerFactory::Compilers[m_CompilerIdx], m_Project, m_PageIndex);
        wxArrayString clean = dc.GetCleanCommands(target, false);
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Cleaning %s..."), target ? target->GetTitle().c_str() : m_Project->GetTitle().c_str());
        for (unsigned int i = 0; i < clean.GetCount(); ++i)
        {
            wxRemoveFile(clean[i]);
        }
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Done."));
        Manager::Get()->GetMessageManager()->Close();
    }
    return 0;
}

int CompilerGCC::DistClean(ProjectBuildTarget* target)
{
	DoPrepareQueue();
	if (!CompilerValid(target))
		return -1;

    if (CompilerFactory::CompilerIndexOK(m_CompilerIdx))
        CompilerFactory::Compilers[m_CompilerIdx]->GetCustomVars().ApplyVarsToEnvironment();
    m_Project->GetCustomVars().ApplyVarsToEnvironment();

    Manager::Get()->GetMessageManager()->Open();

    wxSetWorkingDirectory(m_Project->GetBasePath());
    if (UseMake(target))
    {
        wxString cmd;
        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        if (target)
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" distclean_") << target->GetTitle();
        else
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" distclean");
        m_Queue.Add(cmd);
        return DoRunQueue();
    }
    else
    {
        DirectCommands dc(this, CompilerFactory::Compilers[m_CompilerIdx], m_Project, m_PageIndex);
        wxArrayString clean = dc.GetCleanCommands(target, true);
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Dist-cleaning %s..."), target ? target->GetTitle().c_str() : m_Project->GetTitle().c_str());
        for (unsigned int i = 0; i < clean.GetCount(); ++i)
        {
            wxRemoveFile(clean[i]);
        }
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Done."));
        Manager::Get()->GetMessageManager()->Close();
    }
    return 0;
}

int CompilerGCC::CreateDist()
{
	DoPrepareQueue();
	if (!CompilerValid())
		return -1;

    Manager::Get()->GetMessageManager()->Open();

    wxString cmd;
    if (UseMake())
    {
        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" dist");
        m_Queue.Add(cmd);
        return DoRunQueue();
    }
    else
        wxMessageBox(_("\"Create distribution\" is only valid when using GNU \"make\"..."));

    return -1;
}

void CompilerGCC::OnExportMakefile(wxCommandEvent& event)
{
	if (!CompilerValid())
		return;
	wxString makefile = wxGetTextFromUser(_("Please enter the \"Makefile\" name:"), _("Export Makefile"), ProjectMakefile());
	if (makefile.IsEmpty())
		return;

    Manager::Get()->GetMessageManager()->Open();

    wxSetWorkingDirectory(m_Project->GetBasePath());
    if (UseMake())
    {
        DoCreateMakefile(false, makefile);
    }
    else
    {
        MakefileGenerator generator(this, m_Project, makefile, m_PageIndex);
        generator.CreateMakefile();
    }
    wxString msg;
    msg.Printf(_("\"%s\" has been exported in the same directory as the project file."), makefile.c_str());
    wxMessageBox(msg);
}

int CompilerGCC::Compile(ProjectBuildTarget* target)
{
    DoClearErrors();
	DoPrepareQueue();
	if (!m_Project || !CompilerValid(target))
        return -2;

    if (CompilerFactory::CompilerIndexOK(m_CompilerIdx))
        CompilerFactory::Compilers[m_CompilerIdx]->GetCustomVars().ApplyVarsToEnvironment();
    m_Project->GetCustomVars().ApplyVarsToEnvironment();

    Manager::Get()->GetMessageManager()->Open();

    wxString cmd;
    wxSetWorkingDirectory(m_Project->GetBasePath());
    if (UseMake(target))
    {
        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        if (target)
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" ") << target->GetTitle();
        else
            cmd << make << _T(" -f ") << m_LastTempMakefile;
        m_Queue.Add(cmd);
    }
    else
    {
        DirectCommands dc(this, CompilerFactory::Compilers[m_CompilerIdx], m_Project, m_PageIndex);
        wxArrayString compile = dc.GetCompileCommands(target);
        dc.AppendArray(compile, m_Queue);
    }
    return DoRunQueue();
}

int CompilerGCC::Rebuild(ProjectBuildTarget* target)
{
	DoPrepareQueue();
	if (!CompilerValid(target))
		return -1;

    if (CompilerFactory::CompilerIndexOK(m_CompilerIdx))
        CompilerFactory::Compilers[m_CompilerIdx]->GetCustomVars().ApplyVarsToEnvironment();
    m_Project->GetCustomVars().ApplyVarsToEnvironment();

    Manager::Get()->GetMessageManager()->Open();

    if (UseMake(target))
    {
        wxString cmd;
        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        if (target)
        {
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" clean_") << target->GetTitle();
            m_Queue.Add(cmd);
            cmd.Clear();
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" ") << target->GetTitle();
            m_Queue.Add(cmd);
        }
        else
        {
            cmd << make << _T(" -f ") << m_LastTempMakefile << _T(" clean");
            m_Queue.Add(cmd);
            cmd.Clear();
            cmd << make << _T(" -f ") << m_LastTempMakefile;
            m_Queue.Add(cmd);
        }
    }
    else
    {
        Clean(target);
        Compile(target);
    }
    return DoRunQueue();
}

int CompilerGCC::CompileAll()
{
    Manager::Get()->GetMessageManager()->Open();
    DoPrepareMultiProjectCommand(mpjCompile);
    DoPrepareQueue();
    ClearLog();
    ProjectBuildTarget* target = DoAskForTarget();
    return Compile(target);
}

int CompilerGCC::RebuildAll()
{
    Manager::Get()->GetMessageManager()->Open();
    DoPrepareMultiProjectCommand(mpjRebuild);
    DoPrepareQueue();
    ClearLog();
    ProjectBuildTarget* target = DoAskForTarget();
    return Rebuild(target);
}

int CompilerGCC::KillProcess()
{
    if (!m_Process || !m_Pid)
        return -1;
    wxKillError ret;
    bool isdirect=(!UseMake());

    m_Queue.Clear();

    // Close input pipe
    m_Process->CloseOutput();
    ret = wxProcess::Kill(m_Pid, wxSIGTERM);
    if(isdirect && ret!=wxKILL_OK)
    {
        // No need to tell the user about the errors - just keep him waiting.
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Aborting..."));
    }
    else switch (ret)
    {
        case wxKILL_ACCESS_DENIED: wxMessageBox(_("Access denied")); break;
        case wxKILL_NO_PROCESS: wxMessageBox(_("No process")); break;
        case wxKILL_BAD_SIGNAL: wxMessageBox(_("Bad signal")); break;
        case wxKILL_ERROR: wxMessageBox(_("Unspecified error")); break;

        case wxKILL_OK:
        default: Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Process killed..."));
    }
    return ret;
}

ProjectBuildTarget* CompilerGCC::GetBuildTargetForFile(ProjectFile* pf)
{
    if (!pf)
        return 0;

    if (!pf->buildTargets.GetCount())
    {
        wxMessageBox(_("That file isn't assigned to any target."),
                    _("Information"), wxICON_INFORMATION);
        return 0;
    }
    else if (pf->buildTargets.GetCount() == 1)
        return m_Project->GetBuildTarget(pf->buildTargets[0]);
    // belongs to two or more build targets
    ProjectBuildTarget* bt = 0;
    // if "All" is selected, ask for build target
    if (m_HasTargetAll && m_TargetIndex == -1)
    {
        int idx = DoGUIAskForTarget();
        if (idx == -1)
            return 0;
        bt = m_Project->GetBuildTarget(idx);
    }
    else // use the currently selected build target
        bt = m_Project->GetBuildTarget(m_TargetIndex); // pick the selected target

    return bt;
}

ProjectBuildTarget* CompilerGCC::GetBuildTargetForFile(const wxString& file)
{
    ProjectFile* pf = m_Project ? m_Project->GetFileByFilename(file, true, false) : 0;
    return GetBuildTargetForFile(pf);
}

int CompilerGCC::CompileFile(const wxString& file)
{
	DoPrepareQueue();
	if (!CompilerValid())
		return -1;

    Manager::Get()->GetMessageManager()->Open();

    if (m_Project)
        wxSetWorkingDirectory(m_Project->GetBasePath());

    ProjectFile* pf = m_Project ? m_Project->GetFileByFilename(file, true, false) : 0;
    ProjectBuildTarget* bt = GetBuildTargetForFile(pf);
    bool useMake = UseMake(bt);

    if (!pf)
    {
        // compile single file not belonging to a project

        // switch to the default compiler
        SwitchCompiler(CompilerFactory::GetDefaultCompilerIndex());

        if (useMake)
        {
            wxMessageBox(_("That file doesn't belong to a project.\n"
                            "If you want to compile it as stand-alone, please use the \"Invoke compiler directly\" build method\n"
                            "(Settings->Compiler->Other->Build method)"),
                        _("Information"), wxICON_INFORMATION);
        }
        else
        {
            // get compile commands for file (always linked as console-executable)
            DirectCommands dc(this, CompilerFactory::GetDefaultCompiler(), 0, m_PageIndex);
            wxArrayString compile = dc.GetCompileSingleFileCommand(file);
            dc.AppendArray(compile, m_Queue);

            // apply global custom vars
            CompilerFactory::GetDefaultCompiler()->GetCustomVars().ApplyVarsToEnvironment();
        }
        return DoRunQueue();
    }

    if (!bt)
        return -2;
    if (useMake)
    {
        wxFileName tmp = pf->GetObjName();
        wxFileName o_file(bt->GetObjectOutput() + wxFILE_SEP_PATH + tmp.GetFullPath());
        wxString fname = UnixFilename(o_file.GetFullPath());
        MakefileGenerator mg(this, 0, _T(""), 0);
        mg.ConvertToMakefileFriendly(fname, true);

        // apply global custom vars
        CompilerFactory::Compilers[bt->GetCompilerIndex()]->GetCustomVars().ApplyVarsToEnvironment();

        wxString make = CompilerFactory::Compilers[m_CompilerIdx]->GetPrograms().MAKE;
        m_Queue.Add(make + _T(" -f ") + m_LastTempMakefile + _T(" depend_") + bt->GetTitle() + _T("_DIRS")); // make the output dir
        m_Queue.Add(make + _T(" -f ") + m_LastTempMakefile + _T(" ") + fname);
    }
    else
    {
        DirectCommands dc(this, CompilerFactory::Compilers[bt->GetCompilerIndex()], m_Project, m_PageIndex);
        wxArrayString compile = dc.CompileFile(bt, pf);
        dc.AppendArray(compile, m_Queue);
    }
    return DoRunQueue();
}

// events

void CompilerGCC::OnIdle(wxIdleEvent& event)
{
    if (m_Process && ((PipedProcess*)m_Process)->HasInput())
		event.RequestMore();
	else
		event.Skip();
}

void CompilerGCC::OnTimer(wxTimerEvent& event)
{
	wxWakeUpIdle();
}

void CompilerGCC::OnRun(wxCommandEvent& event)
{
	m_RunAfterCompile = true;
	if (Run() == 0)
		DoRunQueue();
	m_RunAfterCompile = false;
}

void CompilerGCC::OnCompileAndRun(wxCommandEvent& event)
{
	m_RunAfterCompile = true;
    Compile(DoAskForTarget());
}

void CompilerGCC::OnCompile(wxCommandEvent& event)
{
	int bak = m_TargetIndex;
    if (event.GetId() == idMenuCompileTargetFromProjectManager)
	{
    	// we 're called from a menu in ProjectManager
		int idx = DoGUIAskForTarget();
		if (idx == -1)
			return;
		else
			m_TargetIndex = idx;

    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
	}
    else if (event.GetId() == idMenuCompileFromProjectManager)
    {
    	// we 're called from a menu in ProjectManager
    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
    }
    ProjectBuildTarget* target = DoAskForTarget();
    Compile(target);
	m_TargetIndex = bak;
}

void CompilerGCC::OnCompileFile(wxCommandEvent& event)
{
 	wxFileName file;
    if (event.GetId() == idMenuCompileFileFromProjectManager)
    {
    	// we 're called from a menu in ProjectManager
    	// let's check the selected project...
    	FileTreeData* ftd = DoSwitchProjectTemporarily();
    	ProjectFile* pf = m_Project->GetFile(ftd->GetFileIndex());
    	if (!pf)
    	{
//            wxLogError("File index=%d", ftd->GetFileIndex());
            return;
        }
    	file = pf->file;
    }
    else
    {
        cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
        if (ed)
        {
            // make sure it is saved
            if (ed->Save())
                file.Assign(ed->GetFilename());
        }
    }

    if (m_Project)
        file.MakeRelativeTo(m_Project->GetBasePath());
#ifdef ALWAYS_USE_MAKEFILE
	file.SetExt(OBJECT_EXT);
#endif
    wxString fname = file.GetFullPath();
    if (!fname.IsEmpty())
        CompileFile(UnixFilename(fname));
}

void CompilerGCC::OnRebuild(wxCommandEvent& event)
{
	if (wxMessageBox(_("Rebuilding the project will cause the deletion of all "
                        "object files and building it from scratch.\nThis action "
                        "might take a while, especially if your project contains "
                        "more than a few files.\nAnother factor is your CPU "
                        "and the available system memory.\n\n"
                        "Are you sure you want to rebuild the entire project?"),
					_("Rebuild project"),
					wxYES_NO | wxICON_QUESTION) == wxNO)
    {
        return;
    }

	int bak = m_TargetIndex;
    if (event.GetId() == idMenuRebuildTargetFromProjectManager)
	{
    	// we 're called from a menu in ProjectManager
		int idx = DoGUIAskForTarget();
		if (idx == -1)
			return;
		else
			m_TargetIndex = idx;

    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
	}
    else if (event.GetId() == idMenuRebuildFromProjectManager)
    {
    	// we 're called from a menu in ProjectManager
    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
    }
    ProjectBuildTarget* target = DoAskForTarget();
    Rebuild(target);
	m_TargetIndex = bak;
}

void CompilerGCC::OnCompileAll(wxCommandEvent& event)
{
    CompileAll();
}

void CompilerGCC::OnRebuildAll(wxCommandEvent& event)
{
	if (wxMessageBox(_("Rebuilding ALL the open projects will cause the deletion of all "
                        "object files and building them from scratch.\nThis action "
                        "might take a while, especially if your projects contain "
                        "more than a few files.\nAnother factor is your CPU "
                        "and the available system memory.\n\n"
                        "Are you sure you want to rebuild ALL the projects?"),
					_("Rebuild projects"),
					wxYES_NO | wxICON_QUESTION) == wxNO)
    {
        return;
    }
    RebuildAll();
}

void CompilerGCC::OnClean(wxCommandEvent& event)
{
	if (wxMessageBox(_("Cleaning the target or project will cause the deletion "
                        "of all relevant object files.\nThis means that you will "
                        "have to build your project from scratch next time you "
                        "'ll want to build it.\nThat action "
                        "might take a while, especially if your project contains "
                        "more than a few files.\nAnother factor is your CPU "
                        "and the available system memory.\n\n"
                        "Are you sure you want to proceed to cleaning?"),
					_("Clean target/project"),
					wxYES_NO | wxICON_QUESTION) == wxNO)
    {
        return;
    }

	int bak = m_TargetIndex;
    if (event.GetId() == idMenuCleanTargetFromProjectManager)
	{
    	// we 're called from a menu in ProjectManager
		int idx = DoGUIAskForTarget();
		if (idx == -1)
			return;
		else
			m_TargetIndex = idx;

    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
	}
    else if (event.GetId() == idMenuCleanFromProjectManager)
    {
    	// we 're called from a menu in ProjectManager
    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
    }
    ProjectBuildTarget* target = DoAskForTarget();
    Clean(target);
	m_TargetIndex = bak;
}

void CompilerGCC::OnDistClean(wxCommandEvent& event)
{
	if (wxMessageBox(_("Dist-cleaning the target or project will cause the deletion "
                        "of all relevant object files.\nThis means that you will "
                        "have to build your project from scratch next time you "
                        "'ll want to build it.\nThat action "
                        "might take a while, especially if your project contains "
                        "more than a few files.\nAnother factor is your CPU "
                        "and the available system memory.\n\n"
                        "Are you sure you want to proceed to dist-cleaning?"),
					_("Dist-clean target/project"),
					wxYES_NO | wxICON_QUESTION) == wxNO)
    {
        return;
    }

	int bak = m_TargetIndex;
    if (event.GetId() == idMenuDistCleanTargetFromProjectManager)
	{
    	// we 're called from a menu in ProjectManager
		int idx = DoGUIAskForTarget();
		if (idx == -1)
			return;
		else
			m_TargetIndex = idx;

    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
	}
    else if (event.GetId() == idMenuDistCleanFromProjectManager)
    {
    	// we 're called from a menu in ProjectManager
    	// let's check the selected project...
    	DoSwitchProjectTemporarily();
    }
    ProjectBuildTarget* target = DoAskForTarget();
    DistClean(target);
	m_TargetIndex = bak;
}

void CompilerGCC::OnProjectCompilerOptions(wxCommandEvent& event)
{
	wxTreeCtrl* tree = Manager::Get()->GetProjectManager()->GetTree();
	wxTreeItemId sel = tree->GetSelection();
    FileTreeData* ftd = (FileTreeData*)tree->GetItemData(sel);
    if (ftd)
    {
        // 'configure' selected target, if other than 'All'
        ProjectBuildTarget* target = 0;
        if (ftd->GetProject() == m_Project)
        {
            if (!m_HasTargetAll || m_TargetIndex != -1)
                target = m_Project->GetBuildTarget(m_TargetIndex);
        }
        Configure(ftd->GetProject(), target);
    }
    else
    {
        cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
        if (prj)
            Configure(prj);
    }
}

void CompilerGCC::OnTargetCompilerOptions(wxCommandEvent& event)
{
	int bak = m_TargetIndex;
	// we 're called from a menu in ProjectManager
	int idx = DoGUIAskForTarget();
	if (idx == -1)
		return;
	else
		m_TargetIndex = idx;
   	// let's check the selected project...
   	DoSwitchProjectTemporarily();

    ProjectBuildTarget* target = DoAskForTarget();
	m_TargetIndex = bak;
	Configure(m_Project, target);
}

void CompilerGCC::OnKillProcess(wxCommandEvent& event)
{
    KillProcess();
}

void CompilerGCC::OnSelectTarget(wxCommandEvent& event)
{
 	if (event.GetId() == idMenuSelectTargetAll)
		m_TargetIndex = -1;
	else if (event.GetId() == idToolTarget)
#if wxCHECK_VERSION(2, 6, 2)
		m_TargetIndex = m_ToolTarget->GetCurrentSelection() - (m_HasTargetAll ? 1 : 0);
#else
		m_TargetIndex = m_ToolTarget->GetSelection() - (m_HasTargetAll ? 1 : 0);
#endif
	else
	{
		for (int i = 0; i < MAX_TARGETS; ++i)
		{
			if (event.GetId() == idMenuSelectTargetOther[i])
			{
				m_TargetIndex = i;
				break;
			}
		}
	}
	DoUpdateTargetMenu();
}

void CompilerGCC::OnNextError(wxCommandEvent& event)
{
	DoGotoNextError();
}

void CompilerGCC::OnPreviousError(wxCommandEvent& event)
{
	DoGotoPreviousError();
}

void CompilerGCC::OnClearErrors(wxCommandEvent& event)
{
	DoClearErrors();
}

void CompilerGCC::OnCreateDist(wxCommandEvent& event)
{
    CreateDist();
}

void CompilerGCC::OnUpdateUI(wxUpdateUIEvent& event)
{
	cbProject* prj = Manager::Get()->GetProjectManager()->GetActiveProject();
    cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
    wxMenuBar* mbar = Manager::Get()->GetAppWindow()->GetMenuBar();
    if (mbar)
    {
        mbar->Enable(idMenuCompile, !m_Process && prj);
        mbar->Enable(idMenuCompileAll, !m_Process && prj);
        mbar->Enable(idMenuCompileFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuCompileTargetFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuCompileFile, !m_Process && ed);
        mbar->Enable(idMenuCompileFileFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuRebuild, !m_Process && prj);
        mbar->Enable(idMenuRebuildAll, !m_Process && prj);
        mbar->Enable(idMenuRebuildFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuRebuildTargetFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuClean, !m_Process && prj);
        mbar->Enable(idMenuDistClean, !m_Process && prj);
        mbar->Enable(idMenuCleanFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuDistCleanFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuCleanTargetFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuDistCleanTargetFromProjectManager, !m_Process && prj);
        mbar->Enable(idMenuCompileAndRun, !m_Process && prj);
        mbar->Enable(idMenuRun, !m_Process && prj);
        mbar->Enable(idMenuKillProcess, m_Process);
        mbar->Enable(idMenuSelectTarget, !m_Process && prj);

        mbar->Enable(idMenuNextError, !m_Process && prj && m_Errors.HasNextError());
        mbar->Enable(idMenuPreviousError, !m_Process && prj && m_Errors.HasPreviousError());
//        mbar->Enable(idMenuClearErrors, cnt);

        mbar->Enable(idMenuCreateDist, !m_Process && prj);
        mbar->Enable(idMenuExportMakefile, !m_Process && prj);

        // Project menu
        mbar->Enable(idMenuProjectCompilerOptions, !m_Process && prj);
    }

	// enable/disable compiler toolbar buttons
	wxToolBar* tbar = m_pTbar;//Manager::Get()->GetAppWindow()->GetToolBar();
	if (tbar)
	{
        tbar->EnableTool(idMenuCompile, !m_Process && prj);
        tbar->EnableTool(idMenuRun, !m_Process && prj);
        tbar->EnableTool(idMenuCompileAndRun, !m_Process && prj);
        tbar->EnableTool(idMenuRebuild, !m_Process && prj);
        tbar->EnableTool(idMenuKillProcess, m_Process && prj);

        m_ToolTarget = XRCCTRL(*tbar, "idToolTarget", wxComboBox);
        if (m_ToolTarget)
            m_ToolTarget->Enable(!m_Process && prj);
    }

    // allow other UpdateUI handlers to process this event
    // *very* important! don't forget it...
    event.Skip();
}

void CompilerGCC::OnProjectActivated(CodeBlocksEvent& event)
{
    //Manager::Get()->GetMessageManager()->Log(mltDevDebug, "OnProjectActivated()");
	DoRecreateTargetMenu();
	event.Skip(); // *very* important! don't forget it...
}

/*void CompilerGCC::OnProjectPopupMenu(wxNotifyEvent& event)
{
	BuildModuleMenu(mtProjectManager, (wxMenu*)event.GetClientData(), event.GetString());
	event.Skip();
}*/

void CompilerGCC::OnGCCOutput(CodeBlocksEvent& event)
{
	wxString msg = event.GetString();
	if (!msg.IsEmpty() &&
        !msg.Matches(_T("# ??*")))  // gcc 3.4 started displaying a line like this filter
                                // when calculating dependencies. Until I check out
                                // why this happens (and if there is a switch to
                                // turn it off), I put this condition here to avoid
                                // displaying it...
	{
        AddOutputLine(msg);
	}
}

void CompilerGCC::OnGCCError(CodeBlocksEvent& event)
{
	wxString msg = event.GetString();
	AddOutputLine(msg);
}

void CompilerGCC::AddOutputLine(const wxString& output, bool forceErrorColor)
{
    size_t maxErrors = ConfigManager::Get()->Read(_T("/compiler_gcc/max_reported_errors"), 50);
    if (maxErrors > 0)
    {
        if (m_Errors.GetErrorsCount() > maxErrors)
            return;
        else if (m_Errors.GetErrorsCount() == maxErrors)
        {
            // if we reached the max errors count, notify about it
            m_Errors.AddError(_T(""), 0, _("More errors follow but not being shown."), false);
            m_Errors.AddError(_T(""), 0, _("Edit the max errors limit in compiler options..."), false);
            return;
        }
    }

	Compiler* compiler = CompilerFactory::Compilers[m_CompilerIdx];
	CompilerLineType clt = compiler->CheckForWarningsAndErrors(output);

	switch (clt)
	{
        case cltWarning:
			m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(COLOUR_NAVY));
			break;

        case cltError:
			m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(*wxRED));
			break;

        default:
            if (forceErrorColor)
                m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(COLOUR_MAROON));
            else
                m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
			break;
	}

	if (clt != cltNormal)
	{
        wxArrayString errors;
        errors.Add(compiler->GetLastErrorFilename());
        errors.Add(compiler->GetLastErrorLine());
        errors.Add(compiler->GetLastError());
        m_pListLog->AddLog(errors);
        m_pListLog->GetListControl()->SetColumnWidth(2, wxLIST_AUTOSIZE);

        // colorize the list output
/* NOTE (mandrav#1#): For this to work under win32, one must use -D_WIN32_IE=0x300 when building wxWidgets
                      and probably edit wx/msw/treectrl.cpp and wx/listctrl.cpp (grep for _WIN32_IE) */
        m_pListLog->GetListControl()->SetItemTextColour(m_pListLog->GetListControl()->GetItemCount() - 1,
                                                        clt == cltWarning ? COLOUR_NAVY : *wxRED);

        m_Errors.AddError(compiler->GetLastErrorFilename(),
                          !compiler->GetLastErrorLine().IsEmpty() ? atoi(compiler->GetLastErrorLine().mb_str()) : 0,
                          compiler->GetLastError(),
                          clt == cltWarning);
    }

	if (!output.IsEmpty())
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, output.c_str());
}

void CompilerGCC::OnGCCTerminated(CodeBlocksEvent& event)
{
	m_LastExitCode = event.GetInt();
	OnJobEnd();
}

void CompilerGCC::OnJobEnd()
{
    m_timerIdleWakeUp.Stop();
    m_Pid = 0;

	bool ended = true;
    if (m_Queue.GetCount() != 0 && m_QueueIndex < m_Queue.GetCount() - 1)
    {
        if (m_LastExitCode == 0)
        {
			++m_QueueIndex;
            if (DoRunQueue() != -3) // not end of queue
				ended = false;
		}
    }

//    m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(*wxBLUE));
//    Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("%d commands in queue (at %d)"), m_Queue.GetCount(), m_QueueIndex);
//	m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(*wxBLACK, *wxWHITE));

	if (ended)
    {
        long int elapsed = wxGetElapsedTime() / 1000;
        int mins = elapsed / 60;
        int secs = (elapsed % 60);
        m_Log->GetTextControl()->SetDefaultStyle(m_LastExitCode == 0 ? wxTextAttr(*wxBLUE) : wxTextAttr(*wxRED));
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("Process terminated with status %d (%d minutes, %d seconds)"), m_LastExitCode, mins, secs);
        if (!m_RunAfterCompile)
        {
            m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(COLOUR_NAVY));
            Manager::Get()->GetMessageManager()->Log(m_PageIndex, _("%d errors, %d warnings"), m_Errors.GetErrorsCount(), m_Errors.GetWarningsCount());
        }
        m_Log->GetTextControl()->SetDefaultStyle(wxTextAttr(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
        Manager::Get()->GetMessageManager()->Log(m_PageIndex, _T(" ")); // blank line

        if (m_LastExitCode == 0)
        {
            if (m_RunAfterCompile)
            {
                m_QueueIndex = 0;
                m_Queue.Clear();
                if (Run() == 0)
                    DoRunQueue();
            }
            if (m_DoAllProjects != mpjNone)
            {
                ProjectManager* prjMan = Manager::Get()->GetProjectManager();
                ProjectsArray* projects = prjMan->GetProjects();

                if (m_ProjectIndex < projects->GetCount() - 1)
                {
                    prjMan->SetProject(projects->Item(++m_ProjectIndex), false);
                    CheckProject();
                    m_QueueIndex = 0;
                    if (UseMake())
                    {
                        wxString oldMK = m_LastTempMakefile;
                        DoCreateMakefile();
                        for (unsigned int i = 0; i < m_Queue.GetCount(); ++i)
                            m_Queue[i].Replace(oldMK, m_LastTempMakefile);
                        DoRunQueue();
                    }
                    else
                    {
                        ProjectBuildTarget* target = DoAskForTarget();
                        m_Queue.Clear();
                        switch (m_DoAllProjects)
                        {
                            case mpjCompile: Compile(target); break;
                            case mpjRebuild: Rebuild(target); break;
                            default: break;
                        }
                    }
                }
                else if (m_BackupActiveProject)
                {
                    m_DoAllProjects = mpjNone;
                    m_QueueIndex = 0;
                    m_Queue.Clear();
                    prjMan->SetProject(m_BackupActiveProject, false);
                    AskForActiveProject();
                    DoDeleteTempMakefile();
                    // if message manager is auto-hiding, this will unlock it
                    Manager::Get()->GetMessageManager()->Close(true);
                }
            }
            else
            {
                m_Queue.Clear();
                m_QueueIndex = 0;
                DoDeleteTempMakefile();

                // if message manager is auto-hiding, this will unlock it
                Manager::Get()->GetMessageManager()->Close(true);
            }
        }
        else
        {
            m_DoAllProjects = mpjNone;
            m_Queue.Clear();
            m_QueueIndex = 0;
            if (m_Errors.GetCount())
            {
                Manager::Get()->GetMessageManager()->Open();
                Manager::Get()->GetMessageManager()->SwitchTo(m_ListPageIndex);
                DoGotoNextError();
            }
        }
        m_RunAfterCompile = false;
    }
}


syntax highlighted by Code2HTML, v. 0.9.1