/////////////////////////////////////////////////////////////////////////////
// Name:        compilerpanel.cpp
// Purpose:     wxCompilerSettingsPanel
// Author:      Francesco Montorsi
// Modified by:
// Created:     08/07/2006 14:41:18
// RCS-ID:      $Id: compilerpanel.cpp,v 1.5 2007/02/01 11:33:28 frm Exp $
// Copyright:   (c) 2006 Francesco Montorsi
// Licence:     wxWidgets license
/////////////////////////////////////////////////////////////////////////////


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

#ifdef __BORLANDC__
#pragma hdrstop
#endif

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

#include "guipm/compilerpanel.h"
#include "guipm/opteditctrl.h"
#include "wxp/package.h"
#include "wxp/wxp.h"
#include "wx/config.h"
#include "wx/dir.h"

#ifdef __WXMSW__
    #include "shlobj.h"
#endif

// definition

wxString wxPackageCompilerNotes[wxPCF_MAX] =
{
    // borland
    _("The 'Autodetect' button will be able to autodetect the BCC 5.5 folders"),

    // msvc
    _("The Microsoft VisualC++ compiler requires a number of different folders which are different from version to version. The 'Autodetect' button should be able to locate all required folders for MSVC 6, 7.1 and 8.0"),

    // watcom
    _("Autodetect feature not tested yet (FIXME)"),

    // mingw
    _("All MinGW versions are supported by the Autodetect feature"),

    // msys
    _("TOWRITE"),

    // gnu makefile
    _("On a Unix system usually there's no need to add additional paths to those built-in in the compiler: the GNU make is usually already in PATH and should run out-of-the-box when you have installed the 'gcc' (or similar) package of your distribution."),

    // autoconf
    _("On a Unix system usually there's no need to add additional paths to those built-in in the compiler: the GNU make is usually already in PATH and should run out-of-the-box when you have installed the 'gcc' (or similar) package of your distribution.")
};


// ----------------------------------------------------------------------------
// wxCompilerSettingsPanel
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS( wxCompilerSettingsPanel, wxPanel )
BEGIN_EVENT_TABLE( wxCompilerSettingsPanel, wxPanel )
    EVT_CHOICE( ID_COMPILERSETTINGS_DEFAULTCOMPILER,
                wxCompilerSettingsPanel::OnCompilerChanged)
    EVT_BUTTON( ID_COMPILERSETTINGS_AUTODETECT,
                wxCompilerSettingsPanel::OnAutodetect)
    EVT_BUTTON( ID_COMPILERSETTINGS_ADDPATH,
                wxCompilerSettingsPanel::OnAddNewPath)
    EVT_BUTTON( ID_COMPILERSETTINGS_EDITPATH,
                wxCompilerSettingsPanel::OnEditPath)
    EVT_BUTTON( ID_COMPILERSETTINGS_OPENPATH,
                wxCompilerSettingsPanel::OnOpenPath)
    EVT_BUTTON( ID_COMPILERSETTINGS_DELETEPATH,
                wxCompilerSettingsPanel::OnRemovePath)

    EVT_LISTBOX_DCLICK( ID_COMPILERSETTINGS_PATHS,
                wxCompilerSettingsPanel::OnEditPath )
    EVT_UPDATE_UI( wxID_ANY, wxCompilerSettingsPanel::OnUpdateUI )
END_EVENT_TABLE()

wxCompilerSettingsPanel::wxCompilerSettingsPanel( )
{
}

wxCompilerSettingsPanel::wxCompilerSettingsPanel( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
{
    Create(parent, id, pos, size, style);
}

bool wxCompilerSettingsPanel::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
{
////@begin wxCompilerSettingsPanel member initialisation
    m_pCompilerChoice = NULL;
    m_pNotes = NULL;
    m_pPathList = NULL;
////@end wxCompilerSettingsPanel member initialisation

////@begin wxCompilerSettingsPanel creation
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
    wxPanel::Create( parent, id, pos, size, style );

    CreateControls();
    if (GetSizer())
    {
        GetSizer()->SetSizeHints(this);
    }
    Centre();
////@end wxCompilerSettingsPanel creation
    return true;
}

void wxCompilerSettingsPanel::CreateControls()
{
////@begin wxCompilerSettingsPanel content construction
    wxCompilerSettingsPanel* itemPanel1 = this;

    wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
    itemPanel1->SetSizer(itemBoxSizer2);

    wxStaticBox* itemStaticBoxSizer3Static = new wxStaticBox(itemPanel1, wxID_ANY, _("Compiler"));
    wxStaticBoxSizer* itemStaticBoxSizer3 = new wxStaticBoxSizer(itemStaticBoxSizer3Static, wxVERTICAL);
    itemBoxSizer2->Add(itemStaticBoxSizer3, 1, wxGROW|wxALL, 5);

    wxFlexGridSizer* itemFlexGridSizer4 = new wxFlexGridSizer(2, 2, 0, 0);
    itemFlexGridSizer4->AddGrowableRow(0);
    itemFlexGridSizer4->AddGrowableRow(1);
    itemFlexGridSizer4->AddGrowableCol(1);
    itemStaticBoxSizer3->Add(itemFlexGridSizer4, 0, wxGROW, 5);

    wxStaticText* itemStaticText5 = new wxStaticText( itemPanel1, wxID_STATIC, _("Currently selected compiler:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemFlexGridSizer4->Add(itemStaticText5, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);

    wxString* m_pCompilerChoiceStrings = NULL;
    m_pCompilerChoice = new wxChoice( itemPanel1, ID_COMPILERSETTINGS_DEFAULTCOMPILER, wxDefaultPosition, wxDefaultSize, 0, m_pCompilerChoiceStrings, 0 );
    itemFlexGridSizer4->Add(m_pCompilerChoice, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxStaticText* itemStaticText7 = new wxStaticText( itemPanel1, wxID_STATIC, _("Notes about selected compiler:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticBoxSizer3->Add(itemStaticText7, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5);

    m_pNotes = new wxTextCtrl( itemPanel1, ID_COMPILERSETTINGS_NOTES, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY );
    itemStaticBoxSizer3->Add(m_pNotes, 1, wxGROW|wxALL, 5);

    wxStaticText* itemStaticText9 = new wxStaticText( itemPanel1, wxID_STATIC, _("Compiler/tools paths:"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticBoxSizer3->Add(itemStaticText9, 0, wxALIGN_LEFT|wxLEFT|wxRIGHT|wxTOP|wxADJUST_MINSIZE, 5);

    wxBoxSizer* itemBoxSizer10 = new wxBoxSizer(wxHORIZONTAL);
    itemStaticBoxSizer3->Add(itemBoxSizer10, 2, wxGROW, 5);

    wxString* m_pPathListStrings = NULL;
    m_pPathList = new wxListBox( itemPanel1, ID_COMPILERSETTINGS_PATHS, wxDefaultPosition, wxSize(-1, 100), 0, m_pPathListStrings, wxLB_SINGLE|wxLB_HSCROLL );
    itemBoxSizer10->Add(m_pPathList, 1, wxGROW|wxALL|wxFIXED_MINSIZE, 5);

    wxBoxSizer* itemBoxSizer12 = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer10->Add(itemBoxSizer12, 0, wxALIGN_BOTTOM, 5);

    wxButton* itemButton13 = new wxButton( itemPanel1, ID_COMPILERSETTINGS_ADDPATH, _("Add new..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer12->Add(itemButton13, 0, wxGROW|wxALL, 5);

    wxButton* itemButton14 = new wxButton( itemPanel1, ID_COMPILERSETTINGS_EDITPATH, _("Edit..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer12->Add(itemButton14, 0, wxGROW|wxALL, 5);

    wxButton* itemButton15 = new wxButton( itemPanel1, ID_COMPILERSETTINGS_OPENPATH, _("Open..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer12->Add(itemButton15, 0, wxGROW|wxALL, 5);

    wxButton* itemButton16 = new wxButton( itemPanel1, ID_COMPILERSETTINGS_DELETEPATH, _("Delete"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer12->Add(itemButton16, 0, wxGROW|wxALL, 5);

    wxButton* itemButton17 = new wxButton( itemPanel1, ID_COMPILERSETTINGS_AUTODETECT, _("Autodetect..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer12->Add(itemButton17, 0, wxGROW|wxALL, 5);

////@end wxCompilerSettingsPanel content construction
}

wxString wxCompilerSettingsPanel::GetCompilerUserFriendlyName(wxPackageCompilerFormat f)
{
    wxString str = wxPackageCompilerFormat2String(f);

    // make uppercase the first letter
    str = wxString(str[0]).MakeUpper() + str.Mid(1);

    if (f != wxPCF_AUTOCONF)
        return str + wxT(" makefile");
    return str;
}

void wxCompilerSettingsPanel::InitAsGlobal()
{
    wxPackageCompilerFormat def = wxCompilerSettings::GetDefaultFormat();
    wxASSERT(def != wxPCF_INVALID);

    // init the compiler list
    for (size_t i=0; i < wxPCF_MAX; i++)
    {
        wxPackageCompilerFormat fmt = wxIdx2PackageCompilerFormat(i);
        wxString str = GetCompilerUserFriendlyName(fmt) + wxT(" [");

        // inform the user that the compiler settings associated with
        // this compiler are shared among the build systems supported.
        long buildsyslist = wxGetBuildSystemsSupportingCompilerFormat(fmt);
        str += wxPackageBuildSystemTypeList2String(buildsyslist) + wxT("]");

        // use as untyped data the compiler format index
        int lastitem = m_pCompilerChoice->Append(str, (void*)fmt);
        if (fmt == def)
            m_pCompilerChoice->SetSelection(lastitem);
    }

    UpdatePathList();
    UpdateNotes();
}

void wxCompilerSettingsPanel::SetPackage(const wxPackage &p)
{
    // this function can be called more than once !
    m_pCompilerChoice->Clear();
    m_pPathList->Clear();

    m_pkg = p;
    wxPackageCompilerFormat def = m_pkg.GetCompilerSettings().GetSelFormat();
    wxASSERT(def != wxPCF_INVALID);

    // init the compiler list
    for (size_t i=0; i < wxPCF_MAX; i++)
    {
        wxPackageCompilerFormat fmt = wxIdx2PackageCompilerFormat(i);
        if (m_pkg.SupportsBuildSysFormat(fmt))
        {
            // use as untyped data the compiler format index
            int lastitem =
                m_pCompilerChoice->Append(GetCompilerUserFriendlyName(fmt), (void*)fmt);

            // if this is the default compiler for this package, select it.
            // NOTE: this cannot be done out of the loop because of the different
            //       mapping between the listbox' item indexes and the
            //       wxPackageCompilerFormat enum values.
            if (fmt == def)
                m_pCompilerChoice->SetSelection(lastitem);
        }
    }

    wxASSERT(m_pCompilerChoice->GetCount() > 0);
    if (m_pCompilerChoice->GetSelection() == wxNOT_FOUND)
        m_pCompilerChoice->SetSelection(0);

    UpdatePathList();
    UpdateNotes();
}

bool wxCompilerSettingsPanel::ShowToolTips()
{
    return true;
}
/*
bool wxCompilerSettingsPanel::Load(wxConfigBase *p, const wxString &path)
{
    return wxCompilerSettings::Load(p, path);
}

void wxCompilerSettingsPanel::Save(wxConfigBase *p, const wxString &path) const
{
    wxCompilerSettings::Save(p, path);
}*/

wxPackageCompilerFormat wxCompilerSettingsPanel::GetSelCompilerFormat() const
{
    int n = m_pCompilerChoice->GetSelection();
    wxASSERT(n != wxNOT_FOUND);
    return (wxPackageCompilerFormat)(int)
             m_pCompilerChoice->GetClientData(n);
}

void wxCompilerSettingsPanel::UpdatePathList()
{
    wxPackageCompilerFormat def = GetSelCompilerFormat();
    m_pPathList->Clear();

    for (size_t j=0; j<wxPCPT_MAX; j++)
    {
        wxPackageCompilerPathType t = (wxPackageCompilerPathType)j;
        wxString prefix = wxT("[") + wxPackageCompilerPathType2String(t) + wxT("] ");

        wxArrayString arr = wxCompilerSettings::GetCompilerPaths(def, t);
        for (size_t i=0; i<arr.GetCount(); i++)
            m_pPathList->Append(prefix + arr[i], (void *)t);
    }
}

void wxCompilerSettingsPanel::UpdatePackageCompiler()
{
    // update the selected format for our package
    m_pkg.GetCompilerSettings().SetSelFormat(GetSelCompilerFormat());
}

void wxCompilerSettingsPanel::UpdateCompilerSettingsPaths()
{
    wxPathList pl[wxPCPT_MAX];

    for (size_t i=0; i < m_pPathList->GetCount(); i++)
    {
        wxPackageCompilerPathType t = 
            (wxPackageCompilerPathType)(int)m_pPathList->GetClientData(i);

        pl[t].Add(m_pPathList->GetString(i).AfterFirst(wxT(' ')));
    }

    // update compiler paths for selected format
    for (size_t j=0; j < wxPCPT_MAX; j++)
        wxCompilerSettings::SetCompilerPaths(GetSelCompilerFormat(),
                                             (wxPackageCompilerPathType)j,
                                             pl[j]);
}

void wxCompilerSettingsPanel::UpdateNotes()
{
    size_t n = wxPackageCompilerFormat2Idx(GetSelCompilerFormat());
    m_pNotes->SetValue(wxPackageCompilerNotes[n]);
}


// ----------------------------------------------------------------------------
// wxCompilerSettingsPanel - event handlers
// ----------------------------------------------------------------------------

void wxCompilerSettingsPanel::OnCompilerChanged(wxCommandEvent &WXUNUSED(ev))
{
    // update compiler selected in the package
    UpdatePackageCompiler();

    // update path list
    UpdatePathList();

    // update the compiler notes
    UpdateNotes();
}

void wxCompilerSettingsPanel::OnAutodetect(wxCommandEvent &)
{
    wxPackageCompilerFormat selected = GetSelCompilerFormat();
    
    // autodetect selected compiler
    InteractiveAutodetectPathsFor(selected);
    
    // the path list in wxCompilerSettings::s_paths has been updated;
    // update also our control
    UpdatePathList();
}

void wxCompilerSettingsPanel::OnAddNewPath(wxCommandEvent &)
{
    wxPackageCompilerPathType idx =
        (wxPackageCompilerPathType)wxGetSingleChoiceIndex(
            _("Please choose the type of path you want to add:"),
            _("Choose path type"),
            wxPCPT_MAX, wxPackageCompilerPathTypeName,
            this);
    if (idx == wxPCPT_INVALID)
        return;

    wxDirDialog dlg(this);
    if (dlg.ShowModal() == wxID_OK)
    {
        wxString prefix = wxT("[") + wxPackageCompilerPathType2String(idx) + wxT("] ");
        m_pPathList->Append(prefix + dlg.GetPath(), (void*)idx);
        UpdateCompilerSettingsPaths();
    }
}

void wxCompilerSettingsPanel::OnEditPath(wxCommandEvent &)
{
    wxString path = m_pPathList->GetStringSelection().AfterFirst(wxT(' '));

    wxDirDialog dlg(this);
    dlg.SetPath(path);

    int sel = m_pPathList->GetSelection();
    wxASSERT(sel != wxNOT_FOUND);

    wxPackageCompilerPathType idx = 
        (wxPackageCompilerPathType)(int)m_pPathList->GetClientData(sel);
    if (dlg.ShowModal() == wxID_OK)
    {
        wxString prefix = wxT("[") + wxPackageCompilerPathType2String(idx) + wxT("] ");
        m_pPathList->SetString(sel, prefix + dlg.GetPath());
        UpdateCompilerSettingsPaths();
    }
}

void wxCompilerSettingsPanel::OnOpenPath(wxCommandEvent &)
{
    wxString path = m_pPathList->GetStringSelection().AfterFirst(wxT(' '));

#ifdef __WXMSW__
    wxExecute(wxT("explorer.exe ") + path);
#elif defined(__WXGTK__)
    wxExecute(wxT("gnome-open ") + path);
#endif
}

void wxCompilerSettingsPanel::OnRemovePath(wxCommandEvent &)
{
    m_pPathList->Delete(m_pPathList->GetSelection());
    UpdateCompilerSettingsPaths();
}

void wxCompilerSettingsPanel::OnUpdateUI(wxUpdateUIEvent &)
{
    bool toenable = m_pPathList->GetSelection() != wxNOT_FOUND;

    FindWindowById(ID_COMPILERSETTINGS_EDITPATH, this)->Enable(toenable);
    FindWindowById(ID_COMPILERSETTINGS_OPENPATH, this)->Enable(toenable);
    FindWindowById(ID_COMPILERSETTINGS_DELETEPATH, this)->Enable(toenable);
}



// ----------------------------------------------------------------------------
// wxCompilerSettingsPanel - autodetect
// ----------------------------------------------------------------------------

/* static */
void wxCompilerSettingsPanel::InteractiveAutodetectPathsFor(wxPackageCompilerFormat f)
{
    wxPathList pl;

    wxArrayString tool = wxCompilerSettings::GetRequiredToolsList(f);
    wxString toolstr;
    for (size_t i=0; i<tool.GetCount(); i++)
        toolstr += tool[i] + wxT("\n");

    // first, look for required tools in the PATH
    pl.AddEnvList(wxT("PATH"));
    if (wxCompilerSettings::IsValidPathList(f, pl))
    {
        // all tools are in PATH...
        wxLogMessage(_("It looks like all the following tools:\n\n%s\nare already in the PATH environment variable... so you don't need any additional path!"),
                     toolstr.c_str());
        return;
    }

    // now, try some compiler-specific heuristic
    switch (f)
    {
    case wxPCF_BORLAND:
        if (AutodetectBCC())
            return;
        break;

    case wxPCF_MSVC:
        if (AutodetectMSVC())
            return;
        break;

    case wxPCF_MINGW:
        if (AutodetectMinGW())
            return;
        break;

    case wxPCF_WATCOM:
        if (AutodetectWatcom())
            return;
        break;

    default:
        break;
    }

    // fallback to some generic code:
    wxString path;
#if defined( __WXMSW__ )
    wxChar pathbuf[MAX_PATH];
    if (!SHGetSpecialFolderPath(NULL, pathbuf, CSIDL_PROGRAM_FILES, false))
        return;
    path = pathbuf;
#elif defined( __UNIX__ )
    path = wxT("/usr");
#else
    #error Please add some logic for this platform!
#endif

    int reply = wxMessageBox(wxString::Format(
        _("The required compiler programs:\n\n%s\nare not in the PATH; should I search them in the '%s' folder?\nNote that this search could take few minutes..."), 
            toolstr.c_str(), path.c_str()),
            wxT("Question"), wxYES_NO|wxICON_INFORMATION);

    if (reply == wxYES)
    {
        wxBusyCursor wait;

        for (size_t i=0; i<tool.GetCount(); i++)
        {
            wxFileName fn(wxDir::FindFirst(path, tool[i]));
            if (fn.IsOk())
                wxCompilerSettings::AddPath(f, wxPCPT_BIN, fn.GetPath());
        }
    }
}

// mini helper
void AddIfExists(wxPathList &pl, const wxString &path)
{
    if (wxFileName::DirExists(path))
        pl.Add(path);
}

/* static */
bool wxCompilerSettingsPanel::AutodetectMSVC()
{
    wxPathList &binDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MSVC, wxPCPT_BIN);
    wxPathList &incDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MSVC, wxPCPT_INCLUDE);
    wxPathList &libDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MSVC, wxPCPT_LIB);

    // look for a VS71COMNTOOLS env var
    wxString maindir;
    if (!wxGetEnv(wxT("VS71COMNTOOLS"), &maindir))
        return false;

    wxFileName fn(maindir);
    if (!fn.IsOk() || !fn.DirExists())
    {
        wxDirDialog dlg(NULL, wxT("Choose MSVC main directory"),
                        wxEmptyString, wxDD_DIR_MUST_EXIST|wxDD_DEFAULT_STYLE);
        if (dlg.ShowModal() == wxID_OK)
        {
            fn.AssignDir(dlg.GetPath());
            if (!fn.IsOk() || !fn.DirExists())
                return false;
        }
        else
            return false;
    }
    else
    {
        // VS71COMNTOOLS should end with \Common7\Tools
        // get the path normalized and with trailing separator
        if (fn.GetDirs().Last() == wxT("Tools"))
            fn.RemoveLastDir();
        if (fn.GetDirs().Last() == wxT("Common7"))
            fn.RemoveLastDir();
    }
    maindir = fn.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);

    // Populate all possible bin directories under the main directory.

    // VC++ 6
    AddIfExists(binDirs, maindir + wxT("vc98\\bin"));
    AddIfExists(binDirs, maindir + wxT("common\\msdev98\\bin"));

    AddIfExists(incDirs, maindir + wxT("vc98\\include"));

    AddIfExists(libDirs, maindir + wxT("vc98\\lib"));

    // VC++ 7
    AddIfExists(binDirs, maindir + wxT("vc7\\bin"));
    AddIfExists(binDirs, maindir + wxT("common7\\ide"));

    AddIfExists(incDirs, maindir + wxT("vc7\\include"));
    AddIfExists(incDirs, maindir + wxT("vc7\\PlatformSDK\\include"));

    AddIfExists(libDirs, maindir + wxT("vc7\\lib"));
    AddIfExists(libDirs, maindir + wxT("vc7\\PlatformSDK\\lib"));

    // VC++ 8
    AddIfExists(binDirs, maindir + wxT("vc\\bin"));
    AddIfExists(binDirs, maindir + wxT("vc\\vcpackages")); // contains vcbuild.exe
    AddIfExists(incDirs, maindir + wxT("vc\\include"));
    AddIfExists(incDirs, maindir + wxT("vc\\PlatformSDK\\include"));
    AddIfExists(libDirs, maindir + wxT("vc\\lib"));
    AddIfExists(libDirs, maindir + wxT("vc\\PlatformSDK\\lib"));

    // Platform SDK
    AddIfExists(binDirs, maindir + wxT("bin"));
    AddIfExists(binDirs, maindir + wxT("bin\\win64"));
    AddIfExists(incDirs, maindir + wxT("include"));
    AddIfExists(libDirs, maindir + wxT("lib"));

    return true;
}

/* static */
bool wxCompilerSettingsPanel::AutodetectBCC()
{
    wxPathList &binDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_BORLAND, wxPCPT_BIN);
    wxPathList &incDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_BORLAND, wxPCPT_INCLUDE);
    wxPathList &libDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_BORLAND, wxPCPT_LIB);

    wxFileName fn;
    wxDirDialog dlg(NULL, wxT("Choose Borland main directory"),
                    wxEmptyString, wxDD_DIR_MUST_EXIST|wxDD_DEFAULT_STYLE);
    if (dlg.ShowModal() == wxID_OK)
    {
        fn.AssignDir(dlg.GetPath());
        if (!fn.IsOk() || !fn.DirExists())
            return false;
    }
    else
        return false;

    wxString maindir = fn.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);
    if (!wxFileName::DirExists(maindir + wxT("Bin")))
    {
        // try to add the "BCC55" string in case user selected one level higher...
        maindir += wxT("BCC55");
        maindir += wxFileName::GetPathSeparator();
        if (!wxFileName::DirExists(maindir + wxT("Bin")))
            return false;
    }

    // BCC 5.5 (free command line tools edition)
    AddIfExists(binDirs, maindir + wxT("Bin"));
    AddIfExists(incDirs, maindir + wxT("Include"));
    AddIfExists(libDirs, maindir + wxT("Lib"));

    return true;
}

/* static */
bool wxCompilerSettingsPanel::AutodetectMinGW()
{
    wxPathList &binDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MINGW, wxPCPT_BIN);
    wxPathList &incDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MINGW, wxPCPT_INCLUDE);
    wxPathList &libDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_MINGW, wxPCPT_LIB);

    wxFileName fn;
    wxDirDialog dlg(NULL, wxT("Choose MinGW main directory"),
                    wxEmptyString, wxDD_DIR_MUST_EXIST|wxDD_DEFAULT_STYLE);
    if (dlg.ShowModal() == wxID_OK)
    {
        fn.AssignDir(dlg.GetPath());
        if (!fn.IsOk() || !fn.DirExists())
            return false;
    }
    else
        return false;

    wxString maindir = fn.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);
    AddIfExists(binDirs, maindir + wxT("bin"));
    AddIfExists(incDirs, maindir + wxT("include"));
    AddIfExists(libDirs, maindir + wxT("lib"));

    return true;
}

/* static */
bool wxCompilerSettingsPanel::AutodetectWatcom()
{
    wxPathList &binDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_WATCOM, wxPCPT_BIN);
    wxPathList &incDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_WATCOM, wxPCPT_INCLUDE);
    wxPathList &libDirs = wxCompilerSettings::GetCompilerPaths(wxPCF_WATCOM, wxPCPT_LIB);

    wxFileName fn;
    wxDirDialog dlg(NULL, wxT("Choose Watcom main directory"),
                    wxEmptyString, wxDD_DIR_MUST_EXIST|wxDD_DEFAULT_STYLE);
    if (dlg.ShowModal() == wxID_OK)
    {
        fn.AssignDir(dlg.GetPath());
        if (!fn.IsOk() || !fn.DirExists())
            return false;
    }
    else
        return false;

    wxString maindir = fn.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);
    AddIfExists(binDirs, maindir + wxT("binnt"));
    AddIfExists(incDirs, maindir + wxT("h"));
    AddIfExists(incDirs, maindir + wxT("h\\nt"));
    AddIfExists(incDirs, maindir + wxT("h\\sys"));
    AddIfExists(libDirs, maindir + wxT("lib386"));
    AddIfExists(libDirs, maindir + wxT("lib386\\nt"));

    return true;
}
