/*=========================================================================

  Program:   WXDialog - wxWidgets X-platform GUI Front-End for CMake
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Author:    Jorgen Bodde

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "CMakeSetupFrame.h"
#endif

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

#ifdef __BORLANDC__
#pragma hdrstop
#endif

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

////@begin includes
////@end includes

#include <wx/dirdlg.h>
#include <wx/msgdlg.h>
#include <wx/filename.h>

#include "CMakeSetupFrame.h"
#include "PropertyList.h"
#include "app_resources.h"
#include "CMakeIcon.xpm"
#include "aboutdlg.h"

// cmake includes
#include "../cmListFileCache.h"
#include "../cmCacheManager.h"
#include "../cmGlobalGenerator.h"
#include "../cmDynamicLoader.h"

////@begin XPM images
////@end XPM images

/*!
 * CMakeSetupFrm type definition
 */

IMPLEMENT_CLASS( CMakeSetupFrm, wxFrame )

/*!
 * CMakeSetupFrm event table definition
 */

BEGIN_EVENT_TABLE( CMakeSetupFrm, wxFrame )

////@begin CMakeSetupFrm event table entries
    EVT_CLOSE( CMakeSetupFrm::OnCloseWindow )

    EVT_SPLITTER_SASH_POS_CHANGING( ID_SPLITTERWINDOW, CMakeSetupFrm::OnSplitterPosChanging )
    EVT_SPLITTER_DCLICK( ID_SPLITTERWINDOW, CMakeSetupFrm::OnSplitterwindowSashDClick )

    EVT_BUTTON( ID_BROWSE_PROJECT, CMakeSetupFrm::OnButtonBrowseProject )

    EVT_TEXT( ID_SOURCE_BUILD_PATH, CMakeSetupFrm::OnSourceBuildPathUpdated )
    EVT_TEXT_ENTER( ID_SOURCE_BUILD_PATH, CMakeSetupFrm::OnSourceBuildPathEnter )

    EVT_BUTTON( ID_BROWSE_BUILD, CMakeSetupFrm::OnButtonBrowseBuild )

    EVT_COMBOBOX( ID_SEARCHQUERY, CMakeSetupFrm::OnSearchquerySelected )
    EVT_TEXT( ID_SEARCHQUERY, CMakeSetupFrm::OnSearchqueryUpdated )

    EVT_CHECKBOX( ID_SHOW_ADVANCED, CMakeSetupFrm::OnShowAdvancedValues )

    EVT_GRID_CELL_CHANGE( CMakeSetupFrm::OnCellChange )
    EVT_GRID_SELECT_CELL( CMakeSetupFrm::OnGridSelectCell )
    EVT_MOTION( CMakeSetupFrm::OnPropertyMotion )

    EVT_BUTTON( ID_DO_CONFIGURE, CMakeSetupFrm::OnButtonConfigure )

    EVT_BUTTON( ID_DO_OK, CMakeSetupFrm::OnButtonOk )

    EVT_BUTTON( ID_DO_CANCEL, CMakeSetupFrm::OnButtonCancel )

    EVT_BUTTON( ID_DO_DELETE_CACHE, CMakeSetupFrm::OnButtonDeleteCache )

    EVT_BUTTON( ID_CLEAR_LOG, CMakeSetupFrm::OnClearLogClick )

    EVT_BUTTON( ID_BROWSE_GRID, CMakeSetupFrm::OnBrowseGridClick )

    EVT_MENU( ID_MENU_RELOAD_CACHE, CMakeSetupFrm::OnMenuReloadCacheClick )

    EVT_MENU( ID_MENU_DELETE_CACHE, CMakeSetupFrm::OnMenuDeleteCacheClick )

    EVT_MENU( ID_MENU_QUIT, CMakeSetupFrm::OnMenuQuitClick )

    EVT_MENU( ID_MENU_CONFIGURE, CMakeSetupFrm::OnMenuConfigureClick )

    EVT_MENU( ID_MENU_EXITGENERATE, CMakeSetupFrm::OnMenuGenerateClick )

    EVT_MENU( ID_MENU_TOGGLE_ADVANCED, CMakeSetupFrm::OnMenuToggleAdvancedClick )

    EVT_MENU( ID_CMAKE_OPTIONS, CMakeSetupFrm::OnOptionsClick )

    EVT_MENU( ID_ABOUTDLG, CMakeSetupFrm::OnAboutClick )

////@end CMakeSetupFrm event table entries

    EVT_MENU_RANGE(CM_RECENT_BUILD_ITEM, CM_RECENT_BUILD_ITEM + CM_MAX_RECENT_PATHS, CMakeSetupFrm::OnRecentFileMenu)   

    EVT_TEXT_ENTER(ID_SEARCHQUERY, CMakeSetupFrm::OnAddQuery )

END_EVENT_TABLE()

/** Callback function for CMake generator, to tell user how
    far the generation actually is */
void updateProgress(const char *msg, float prog, void *cd)
{
    // TODO: Make some kind of progress counter 
    
    CMakeSetupFrm *fm = (CMakeSetupFrm *)cd;

    if(fm)
    {
        if(prog < 0)
            fm->LogMessage(0, msg);
        else
        {
            fm->UpdateProgress(prog);
            fm->IssueUpdate();
        }
    }
}

/** Callback function for CMake generator, to tell user about stuff. This should be
    logged in the m_log window */
void MFCMessageCallback(const char* m, const char* title, bool& nomore, void *clientdata)
{ 
    CMakeSetupFrm *fm = (CMakeSetupFrm *)clientdata;

    if(fm)
    {
        wxString what = m, msg;
        if(what.StartsWith("CMake Error: "))
            fm->LogMessage(-1, m);
        else
            fm->LogMessage(1, m);
    }
}

// Convert to Win32 path (slashes). This calls the system tools one and then
// removes the spaces. It is not in system tools because we don't want any
// generators accidentally use it
std::string ConvertToWindowsPath(const char* path)
{
  // Convert to output path.
  // Remove the "" around it (if any) since it's an output path for
  // the shell. If another shell-oriented feature is not designed 
  // for a GUI use, then we are in trouble.
  // save the value of the force to unix path option
  bool saveForce = cmSystemTools::GetForceUnixPaths();
  // make sure we get windows paths no matter what for the GUI
  cmSystemTools::SetForceUnixPaths(false);
  std::string s = cmSystemTools::ConvertToOutputPath(path);
  // now restore the force unix path to its previous value
  cmSystemTools::SetForceUnixPaths(saveForce);
  if (s.size())
    {
    std::string::iterator i = s.begin();
    if (*i == '\"')
      {
      s.erase(i, i + 1);
      }
    i = s.begin() + s.length() - 1;
    if (*i == '\"')
      {
      s.erase(i, i + 1);
      }
    }
  return s;
}


bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames)
{
    size_t nFiles = filenames.GetCount();

    // only one item allowed
    if(nFiles > 1)
        return false;

    if(nFiles == 1)
    {
        // only one dir allowed
        if(!wxDirExists(filenames[0]))
            return false;

        // strip the seperator
        wxFileName name;
        name.AssignDir(filenames[0]);       
        
        // issue a 'drop' by changing text ctrl
        m_pOwner->SetValue(name.GetFullPath());

        return true;
    }

    return false;
}

/*!
 * CMakeSetupFrm constructors
 */

CMakeSetupFrm::CMakeSetupFrm( )
    : m_cmake(0)
{
}

CMakeSetupFrm::CMakeSetupFrm( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
    : m_cmake(0)
{
    Create( parent, id, caption, pos, size, style );
}

/*!
 * CMakeSetupFrm creator
 */

bool CMakeSetupFrm::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
////@begin CMakeSetupFrm member initialisation
    m_splitter = NULL;
    m_cmProjectPath = NULL;
    m_BrowseProjectPathButton = NULL;
    m_cmBuildPath = NULL;
    m_BrowseSourcePathButton = NULL;
    m_cmGeneratorChoice = NULL;
    m_cmSearchQuery = NULL;
    m_cmShowAdvanced = NULL;
    m_cmOptions = NULL;
    m_cmLog = NULL;
    m_cmDescription = NULL;
    m_ConfigureButton = NULL;
    m_OkButton = NULL;
    m_CancelButton = NULL;
    m_DeleteCacheButton = NULL;
    m_ClearLogButton = NULL;
    m_cmBrowseCell = NULL;
////@end CMakeSetupFrm member initialisation

    wxFrame::Create( parent, id, caption, pos, size, style );

    // make sure the developer does not assign more then 100
    // would be rediculous but also overlap other id's
    wxASSERT(CM_MAX_RECENT_PATHS < 100);

    m_ExitTimer = 0;

    m_progressDlg = 0;
    m_noRefresh = false;
    m_quitAfterGenerating = false;

    m_config = new wxConfig("CMakeSetup");

    wxIcon icon(CMakeIcon_xpm);
    SetIcon(icon);

    CreateControls();
    
    //SetIcon(GetIconResource(wxT("cmake_icon.xpm")));
    //SetIcon(wxIcon("NGDialog.ico", wxBITMAP_TYPE_ICO_RESOURCE));
    Centre();

    // is it needed to hide console?
    m_RunningConfigure = false;
    cmSystemTools::SetRunCommandHideConsole(true);
    cmSystemTools::SetErrorCallback(MFCMessageCallback, (void *)this);

    // create our cmake instance
    m_cmake = new cmake;
    m_cmake->SetProgressCallback(updateProgress, (void *)this);

    return TRUE;
}

CMakeSetupFrm::~CMakeSetupFrm()
{
    wxString str;

    // write configs back to disk
    m_config->Write(CM_LASTPROJECT_PATH, m_cmProjectPath->GetValue());
    m_config->Write(CM_LASTBUILD_PATH, m_cmBuildPath->GetValue());

    // clear the config first
    for(size_t i = 0 ; i < CM_MAX_RECENT_PATHS; i++)
    {
        str.Printf("%s%i", _(CM_RECENT_BUILD_PATH), i);
        m_config->Write(str, _(""));
    }

    // write the last CM_MAX_RECENT_PATHS items back to config
    int i = (m_recentPaths.Count() >= CM_MAX_RECENT_PATHS ? CM_MAX_RECENT_PATHS : m_recentPaths.Count());
    while(i > 0)
    {
        str.Printf("%s%i", _(CM_RECENT_BUILD_PATH), i);
        m_config->Write(str, m_recentPaths[i - 1]);
        i--;
    }
    
    // write recent query list to config
    for(int j = 0; j < m_cmSearchQuery->GetCount(); j++)
    {
        // allow max to be written
        if(j < CM_MAX_SEARCH_QUERIES)
        {
            str.Printf("%s%i", _(CM_SEARCH_QUERY), j);
            m_config->Write(str, m_cmSearchQuery->GetString(j));
        }
        else
            break;
    }

    // set window pos + size in settings
    if(!IsIconized() && !IsMaximized())
    {
        int xsize, ysize;
        GetSize(&xsize, &ysize);
        if(xsize > 0 && ysize > 0) 
        {
            m_config->Write(CM_XSIZE, (long)xsize);
            m_config->Write(CM_YSIZE, (long)ysize);
        }

        if(m_splitter->GetSashPosition() > 0)
            m_config->Write(CM_SPLITTERPOS, (long)m_splitter->GetSashPosition());

        GetPosition(&xsize, &ysize);
        if(xsize != 0 && ysize != 0) 
        {
            m_config->Write(CM_XPOS, (long)xsize);
            m_config->Write(CM_YPOS, (long)ysize);
        }
    }

    // write changes (will be done before deletion)
    delete m_config;
    
    // delete timer
    if(m_ExitTimer)
        delete m_ExitTimer;

    // delete our cmake instance again
    if(m_cmake)
        delete m_cmake;
}

void CMakeSetupFrm::UpdateWindowState()
{
    bool dogenerate = !m_RunningConfigure && !m_cmOptions->IsCacheDirty() && 
                       (m_cmOptions->GetCount() != 0);
    
    // when configure is running, disable a lot of stuff
    m_cmProjectPath->Enable(!m_RunningConfigure);
    m_BrowseProjectPathButton->Enable(!m_RunningConfigure);
    m_cmBuildPath->Enable(!m_RunningConfigure);
    m_BrowseSourcePathButton->Enable(!m_RunningConfigure);
    m_cmGeneratorChoice->Enable(!m_RunningConfigure);
    m_cmShowAdvanced->Enable(!m_RunningConfigure);
    m_cmOptions->Enable(!m_RunningConfigure);
    m_ConfigureButton->Enable(!m_RunningConfigure);
    m_OkButton->Enable(dogenerate);
    m_CancelButton->Enable(m_RunningConfigure);
    m_DeleteCacheButton->Enable(!m_RunningConfigure);
    m_ClearLogButton->Enable(!m_RunningConfigure);
    if(m_RunningConfigure)
        m_cmBrowseCell->Enable(false);

    // when cache loaded (items available show other control)
    m_cmGeneratorChoice->Enable(m_cmOptions->GetCount() == 0 && !m_RunningConfigure);
    m_cmSearchQuery->Enable(!m_RunningConfigure);
    m_cmBrowseCell->Enable(!m_RunningConfigure && m_cmOptions->IsSelectedItemBrowsable());

    // disable the menus when configuring
    if(GetMenuBar())
    {
        // disable configure button when there is nothing, and generate and exit
        // only when it is allowed to generate
        GetMenuBar()->Enable(ID_MENU_EXITGENERATE, dogenerate);
        GetMenuBar()->Enable(ID_MENU_CONFIGURE, !m_RunningConfigure);

        for(size_t i = 0; i < GetMenuBar()->GetMenuCount(); i++)
            GetMenuBar()->EnableTop(i, !m_RunningConfigure); 
    }
}

void CMakeSetupFrm::LogMessage(int logkind, const char *msg)
{
    // put CR first but prevent a CR at the end
#ifndef __LINUX__   
    if(m_cmLog->IsModified())
        (*m_cmLog) << wxT("\n");
#else
    // Linux requires a different approach
    if(!m_cmLog->GetValue().IsEmpty())
        (*m_cmLog) << wxT("\n");
#endif        

    // log error, warning, or message
    wxTextAttr defattr = m_cmLog->GetDefaultStyle();
    
    switch(logkind)
    {
    // user message
    case 1:
        {
            wxTextAttr colattr(*wxBLUE);
            m_cmLog->SetDefaultStyle(colattr);
            (*m_cmLog) << msg;
            m_cmLog->SetDefaultStyle(defattr);
        }
        break;

    // progress
    case 0:
        (*m_cmLog) << msg;
        break;

    // error
    case -1:
        {
            wxTextAttr colattr(*wxRED);
            m_cmLog->SetDefaultStyle(colattr);
            (*m_cmLog) << msg;
            m_cmLog->SetDefaultStyle(defattr);
        }
        break;
    }
        
    IssueUpdate();
}

void CMakeSetupFrm::IssueUpdate()
{
    //::wxSafeYield(m_CancelButton, true);
    ::wxYield();

    // when we pressed cancel on the progress dialog
    // stop all activities
    if(m_progressDlg)
    {
        if(m_progressDlg->CancelPressed() && !m_progressDlg->IsCancelling())
        {           
            m_progressDlg->CancelAcknowledged();

            // send a button event to cancel the progress
            wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, ID_DO_CANCEL);
            wxPostEvent(this, event);
        }
    }
}

/*!
 * Control creation for CMakeSetupFrm
 */

void CMakeSetupFrm::CreateControls()
{    
////@begin CMakeSetupFrm content construction
    CMakeSetupFrm* itemFrame1 = this;

    wxMenuBar* menuBar = new wxMenuBar;
    wxMenu* itemMenu37 = new wxMenu;
    itemMenu37->Append(ID_MENU_RELOAD_CACHE, _("&Reload Cache\tCtrl+R"), _("Reload the cache from disk"), wxITEM_NORMAL);
    itemMenu37->Append(ID_MENU_DELETE_CACHE, _("&Delete Cache\tCtrl+D"), _("Delete the cache on disk of the current path"), wxITEM_NORMAL);
    itemMenu37->AppendSeparator();
    itemMenu37->Append(ID_MENU_QUIT, _("E&xit\tAlt+F4"), _("Quit CMake Setup"), wxITEM_NORMAL);
    menuBar->Append(itemMenu37, _("&File"));
    wxMenu* itemMenu42 = new wxMenu;
    itemMenu42->Append(ID_MENU_CONFIGURE, _("&Configure\tCtrl+N"), _T(""), wxITEM_NORMAL);
    itemMenu42->Append(ID_MENU_EXITGENERATE, _("&Generate and Exit\tCtrl+G"), _T(""), wxITEM_NORMAL);
    itemMenu42->Append(ID_MENU_TOGGLE_ADVANCED, _("Toggle &Advanced\tCtrl+A"), _T(""), wxITEM_NORMAL);
    itemMenu42->AppendSeparator();
    itemMenu42->Append(ID_CMAKE_OPTIONS, _("&Options\tCtrl+O"), _T(""), wxITEM_NORMAL);
    menuBar->Append(itemMenu42, _("&Tools"));
    wxMenu* itemMenu48 = new wxMenu;
    itemMenu48->Append(ID_ABOUTDLG, _("&About ..."), _("Shows the about dialog ..."), wxITEM_NORMAL);
    menuBar->Append(itemMenu48, _("&Help"));
    itemFrame1->SetMenuBar(menuBar);

    m_splitter = new wxSplitterWindow( itemFrame1, ID_SPLITTERWINDOW, wxDefaultPosition, wxSize(100, 100), wxSP_3DBORDER|wxSP_3DSASH|wxNO_BORDER );

    wxPanel* itemPanel3 = new wxPanel( m_splitter, ID_MAINPANEL, wxDefaultPosition, wxSize(600, 400), wxNO_BORDER|wxTAB_TRAVERSAL );
    itemPanel3->SetExtraStyle(itemPanel3->GetExtraStyle()|wxWS_EX_VALIDATE_RECURSIVELY);
    wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxVERTICAL);
    itemPanel3->SetSizer(itemBoxSizer4);

    wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer4->Add(itemBoxSizer5, 0, wxGROW|wxTOP|wxBOTTOM, 5);
    wxFlexGridSizer* itemFlexGridSizer6 = new wxFlexGridSizer(2, 3, 0, 0);
    itemFlexGridSizer6->AddGrowableRow(1);
    itemFlexGridSizer6->AddGrowableCol(1);
    itemBoxSizer5->Add(itemFlexGridSizer6, 1, wxALIGN_TOP|wxLEFT, 5);
    wxStaticText* itemStaticText7 = new wxStaticText( itemPanel3, wxID_STATIC, _("CMake project path"), wxDefaultPosition, wxDefaultSize, 0 );
    itemFlexGridSizer6->Add(itemStaticText7, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxADJUST_MINSIZE, 5);

    m_cmProjectPath = new wxTextCtrl( itemPanel3, ID_PROJECT_PATH, _T(""), wxDefaultPosition, wxSize(50, -1), 0 );
    itemFlexGridSizer6->Add(m_cmProjectPath, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM, 5);

    m_BrowseProjectPathButton = new wxButton( itemPanel3, ID_BROWSE_PROJECT, _("Browse"), wxDefaultPosition, wxSize(55, -1), 0 );
    itemFlexGridSizer6->Add(m_BrowseProjectPathButton, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxStaticText* itemStaticText10 = new wxStaticText( itemPanel3, wxID_STATIC, _("Project build path"), wxDefaultPosition, wxDefaultSize, 0 );
    itemFlexGridSizer6->Add(itemStaticText10, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxADJUST_MINSIZE, 5);

    m_cmBuildPath = new wxTextCtrl( itemPanel3, ID_SOURCE_BUILD_PATH, _T(""), wxDefaultPosition, wxSize(50, -1), 0 );
    itemFlexGridSizer6->Add(m_cmBuildPath, 1, wxGROW|wxALIGN_TOP|wxTOP|wxBOTTOM, 5);

    m_BrowseSourcePathButton = new wxButton( itemPanel3, ID_BROWSE_BUILD, _("Browse"), wxDefaultPosition, wxSize(55, -1), 0 );
    itemFlexGridSizer6->Add(m_BrowseSourcePathButton, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxBoxSizer* itemBoxSizer13 = new wxBoxSizer(wxVERTICAL);
    itemBoxSizer5->Add(itemBoxSizer13, 0, wxGROW|wxLEFT|wxRIGHT, 5);
    wxFlexGridSizer* itemFlexGridSizer14 = new wxFlexGridSizer(2, 2, 0, 0);
    itemBoxSizer13->Add(itemFlexGridSizer14, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT|wxRIGHT, 5);
    wxStaticText* itemStaticText15 = new wxStaticText( itemPanel3, wxID_STATIC, _("Generate"), wxDefaultPosition, wxDefaultSize, 0 );
    itemFlexGridSizer14->Add(itemStaticText15, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxADJUST_MINSIZE, 5);

    wxString* m_cmGeneratorChoiceStrings = NULL;
    m_cmGeneratorChoice = new wxComboBox( itemPanel3, ID_CHOOSE_GENERATOR, _T(""), wxDefaultPosition, wxSize(170, -1), 0, m_cmGeneratorChoiceStrings, wxCB_READONLY );
    itemFlexGridSizer14->Add(m_cmGeneratorChoice, 1, wxALIGN_CENTER_HORIZONTAL|wxGROW|wxTOP|wxBOTTOM, 5);

    wxStaticText* itemStaticText17 = new wxStaticText( itemPanel3, wxID_STATIC, _("Search"), wxDefaultPosition, wxDefaultSize, 0 );
    itemFlexGridSizer14->Add(itemStaticText17, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxADJUST_MINSIZE, 5);

    wxString* m_cmSearchQueryStrings = NULL;
    m_cmSearchQuery = new wxComboBox( itemPanel3, ID_SEARCHQUERY, _T(""), wxDefaultPosition, wxSize(170, -1), 0, m_cmSearchQueryStrings, wxWANTS_CHARS );
    itemFlexGridSizer14->Add(m_cmSearchQuery, 1, wxALIGN_CENTER_HORIZONTAL|wxGROW|wxTOP|wxBOTTOM, 5);

    m_cmShowAdvanced = new wxCheckBox( itemPanel3, ID_SHOW_ADVANCED, _("Show advanced values"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE );
    m_cmShowAdvanced->SetValue(FALSE);
    itemBoxSizer13->Add(m_cmShowAdvanced, 0, wxALIGN_RIGHT|wxLEFT|wxRIGHT, 5);

    m_cmOptions = new wxPropertyList( itemPanel3, ID_OPTIONS, wxDefaultPosition, wxSize(200, 150), wxSTATIC_BORDER|wxWANTS_CHARS|wxVSCROLL );
    m_cmOptions->SetDefaultColSize(250);
    m_cmOptions->SetDefaultRowSize(25);
    m_cmOptions->SetColLabelSize(20);
    m_cmOptions->SetRowLabelSize(0);
    m_cmOptions->CreateGrid(10, 2, wxGrid::wxGridSelectRows);
    itemBoxSizer4->Add(m_cmOptions, 1, wxGROW|wxALL, 5);

    wxPanel* itemPanel21 = new wxPanel( m_splitter, ID_LOGPANEL, wxDefaultPosition, wxSize(-1, 100), wxNO_BORDER|wxTAB_TRAVERSAL );
    wxBoxSizer* itemBoxSizer22 = new wxBoxSizer(wxVERTICAL);
    itemPanel21->SetSizer(itemBoxSizer22);

    wxBoxSizer* itemBoxSizer23 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer22->Add(itemBoxSizer23, 1, wxGROW|wxLEFT|wxRIGHT|wxTOP, 5);
    m_cmLog = new wxTextCtrl( itemPanel21, ID_LOG_AREA, _("Select your project path (where CMakeLists.txt is) and then select the build path (where the projects should be saved), or select a previous build path.\n\nRight click on a cache value for additional options (delete and ignore). Press configure to update and display new values in red, press OK to generate the projects and exit."), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH2|wxSTATIC_BORDER );
    itemBoxSizer23->Add(m_cmLog, 1, wxGROW|wxRIGHT, 5);

    m_cmDescription = new wxTextCtrl( itemPanel21, ID_DESCRIPTION, _T(""), wxDefaultPosition, wxSize(200, -1), wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH2|wxSTATIC_BORDER );
    itemBoxSizer23->Add(m_cmDescription, 0, wxGROW|wxLEFT, 5);

    wxBoxSizer* itemBoxSizer26 = new wxBoxSizer(wxHORIZONTAL);
    itemBoxSizer22->Add(itemBoxSizer26, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
    m_ConfigureButton = new wxButton( itemPanel21, ID_DO_CONFIGURE, _("Co&nfigure"), wxDefaultPosition, wxDefaultSize, 0 );
    m_ConfigureButton->SetDefault();
    itemBoxSizer26->Add(m_ConfigureButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    m_OkButton = new wxButton( itemPanel21, ID_DO_OK, _("&Generate!"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer26->Add(m_OkButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    m_CancelButton = new wxButton( itemPanel21, ID_DO_CANCEL, _("C&ancel"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer26->Add(m_CancelButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

#if defined(__WXMSW__)
    wxStaticLine* itemStaticLine30 = new wxStaticLine( itemPanel21, wxID_STATIC, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    itemBoxSizer26->Add(itemStaticLine30, 0, wxGROW|wxALL, 5);
#endif

    m_DeleteCacheButton = new wxButton( itemPanel21, ID_DO_DELETE_CACHE, _("&Delete Cache"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer26->Add(m_DeleteCacheButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    m_ClearLogButton = new wxButton( itemPanel21, ID_CLEAR_LOG, _("Clear &Log"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer26->Add(m_ClearLogButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

#if defined(__WXMSW__)
    wxStaticLine* itemStaticLine33 = new wxStaticLine( itemPanel21, wxID_STATIC, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    itemBoxSizer26->Add(itemStaticLine33, 0, wxGROW|wxALL, 5);
#endif

    m_cmBrowseCell = new wxButton( itemPanel21, ID_BROWSE_GRID, _("&Browse"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer26->Add(m_cmBrowseCell, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    m_splitter->SplitHorizontally(itemPanel3, itemPanel21, 300);

    wxStatusBar* itemStatusBar35 = new wxStatusBar( itemFrame1, ID_STATUSBAR, wxST_SIZEGRIP|wxNO_BORDER );
    itemStatusBar35->SetFieldsCount(2);
    itemFrame1->SetStatusBar(itemStatusBar35);

////@end CMakeSetupFrm content construction
}

void CMakeSetupFrm::DoInitFrame(cmCommandLineInfo &cm, const wxString &fn)
{
    // create accelerator table for some commands
    // not very useful if the focus is on an edit ctrl all the time ;-)
    //wxAcceleratorEntry entries[3];
    //entries[0].Set(wxACCEL_NORMAL,  (int) 'c', ID_MENU_CONFIGURE);
    //entries[1].Set(wxACCEL_NORMAL,  (int) 'g', ID_MENU_EXITGENERATE);
    //entries[2].Set(wxACCEL_NORMAL,  (int) 't', ID_MENU_TOGGLE_ADVANCED);
    //wxAcceleratorTable accel(3, entries);
    //SetAcceleratorTable(accel);
    
    // path to where cmake.exe is
    // m_PathToExecutable = cm.GetPathToExecutable().c_str();
    m_PathToExecutable = fn;

    // adjust size of last bar, to display % progress
    wxStatusBar *bar = GetStatusBar();
    if(bar)
    {
        wxASSERT(bar->GetFieldsCount() > 1);
        
        // fill all with -1. Why this way? because the count of the status bars
        // can change. All of the widths must be accounted for and initialised
        int *widths = new int[bar->GetFieldsCount()];
        for(int i = 0; i < bar->GetFieldsCount(); i++)
            widths[i] = -1;

        // the % field
        widths[1] = 75;
        bar->SetStatusWidths(bar->GetFieldsCount(), widths);
        delete widths;
    }

    wxString name, generator;
    std::vector<std::string> names;
  
    m_RunningConfigure = false;

    // set grid labels
    m_cmOptions->SetColLabelValue(0, wxT("Cache Name"));
    m_cmOptions->SetColLabelValue(1, wxT("Cache Value"));
    m_cmOptions->SetProjectGenerated(false);

    // set drop target
    m_cmOptions->SetDropTarget(new DnDFile(m_cmBuildPath));

    m_cmake->GetRegisteredGenerators(names);
    for(std::vector<std::string>::iterator i = names.begin(); i != names.end(); ++i)
    {
        name = i->c_str();
        m_cmGeneratorChoice->Append(name);
    }
    
    // sync advanced option with grid
    m_cmOptions->SetShowAdvanced(m_cmShowAdvanced->GetValue());

    // if none selected, we will see if VS8, VS7 or VS6 is present
    if(m_cmGeneratorChoice->GetValue().IsEmpty())
    {
        std::string mp;
        mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup;Dbghelp_path]";
        cmSystemTools::ExpandRegistryValues(mp);
        if(mp != "/registry")
            generator = wxT("Visual Studio 8 2005");
        else
        {
            mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]";
            cmSystemTools::ExpandRegistryValues(mp);
            if (mp != "/registry")
                generator = wxT("Visual Studio 7 .NET 2003");
            else
            {
                mp = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.0;InstallDir]";
                cmSystemTools::ExpandRegistryValues(mp);
                if (mp != "/registry")
                    generator = wxT("Visual Studio 7");
                else
                    generator = wxT("Visual Studio 6");         
            }
        }
    }

    // set proper discovered generator
    m_cmGeneratorChoice->SetStringSelection(generator);
    
    wxString str;
    //str.Printf("CMake %d.%d - %s", cmake::GetMajorVersion(), cmake::GetMinorVersion(), cmake::GetReleaseVersion());
    str.Printf("CMakeSetup v%i.%i%s", CMAKEGUI_MAJORVER, CMAKEGUI_MINORVER, CMAKEGUI_ADDVER);

    SetTitle(str);
    wxString path;
    
    // get last 5 used projects
    for(size_t i = 0; i < CM_MAX_RECENT_PATHS; i++)
    {
        path.Printf("%s%i", _(CM_RECENT_BUILD_PATH), i);
        if(m_config->Read(path, &str))
            AppendPathToRecentList(str);
    }

    // get query items
    for(size_t i = 0; i < CM_MAX_SEARCH_QUERIES; i++)
    {
        path.Printf("%s%i", _(CM_SEARCH_QUERY), i);
        if(m_config->Read(path, &str))
            m_cmSearchQuery->Append(str);
    }


    // make sure the call to update grid is not executed
    m_noRefresh = true;
    m_cmSearchQuery->SetValue(_(""));
    m_noRefresh = false;

    // Get the parameters from the command line info
    // If an unknown parameter is found, try to interpret it too, since it
    // is likely to be a file dropped on the shortcut :)
    bool sourceDirLoaded = false,
         buildDirLoaded = false;
    
    if(cm.m_LastUnknownParameter.empty())
    {
        if(cm.m_WhereSource.size() > 0 )
        {
            m_cmProjectPath->SetValue(cm.m_WhereSource.c_str());
            sourceDirLoaded = true;
        }   
    
        if (cm.m_WhereBuild.size() > 0 )
        {
            m_cmBuildPath->SetValue(cm.m_WhereBuild.c_str());
            buildDirLoaded = true;
        }
            
        m_cmShowAdvanced->SetValue(cm.m_AdvancedValues);
    }
    else
    {
        m_cmShowAdvanced->SetValue(false);
        
        // TODO: Interpret directory from dropped shortcut
        //this->ChangeDirectoriesFromFile(cmdInfo->m_LastUnknownParameter.c_str());
    }

    if (cm.m_ExitAfterLoad)
    {
        int id = GetId();
        m_ExitTimer = new wxTimer(this, id);
        m_ExitTimer->Start(3000);

        Connect( id, wxEVT_TIMER,(wxObjectEventFunction) &CMakeSetupFrm::OnExitTimer ); 

    } 

    // retrieve settings, this needs to be done here
    // because writing to the m_cmBuildPath triggers a cache reload
    if(!sourceDirLoaded && m_config->Read(CM_LASTPROJECT_PATH, &str))
        m_cmProjectPath->SetValue(str);

    if(!buildDirLoaded)
    {
        m_cmOptions->RemoveAll();
        if(m_config->Read(CM_LASTBUILD_PATH, &str))
            m_cmBuildPath->SetValue(str);
    }

    // set window size from settings
    long xsize, ysize, splitpos;
    if(m_config->Read(CM_XSIZE, &xsize) && m_config->Read(CM_YSIZE, &ysize) &&
       m_config->Read(CM_SPLITTERPOS, &splitpos))
    {
        SetSize(xsize, ysize);
        m_splitter->SetSashPosition(splitpos);
    }

    if(m_config->Read(CM_XPOS, &xsize) && m_config->Read(CM_YPOS, &ysize))
        SetSize(xsize, ysize, -1, -1, wxSIZE_USE_EXISTING);

    UpdateWindowState();
}

void CMakeSetupFrm::LoadCacheFromDiskToGUI()
{
    wxString builddir = m_cmBuildPath->GetValue();  
    
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    if(cachem && !builddir.Trim().IsEmpty())
    {
        if(cachem->LoadCache(builddir.c_str()))
            AppendPathToRecentList(builddir);

        // represent this cache in the grid, but not before we
        // wiped all of the old items
        FillCacheGUIFromCacheManager();
    
        // set the generator string to the one used in the cache
        cmCacheManager::CacheIterator it = cachem->GetCacheIterator("CMAKE_GENERATOR");
        if(!it.IsAtEnd())
        {
            wxString curGen = it.GetValue();
            m_cmGeneratorChoice->SetStringSelection(curGen);
        }
    }
}

void CMakeSetupFrm::AppendPathToRecentList(const wxString &p)
{
    wxFileName path;
    wxString str;

    if(p.IsEmpty())
        return;
    
    // cheap way to get rid of trailing seperators
    path.AssignDir(p);
    str = path.GetPath();

    // append the item, or add it to end to make sure
    // it is remembered between sessions
    for(size_t i = 0; i < m_recentPaths.Count(); i++)
    {
        if(m_recentPaths[i].IsSameAs(str, false))
        {
            m_recentPaths.RemoveAt(i);
            
            // only re-add when item is still valid
            if(::wxDirExists(str))
                m_recentPaths.Add(str);
            else
                return;  // no add when the item is not existing

            return;
        }
    }
 
    if(GetMenuBar())
    {
        // get file menu
        int lastUsedID = 0;
        wxMenu *mnu = GetMenuBar()->GetMenu(0);
        wxASSERT(mnu != 0);
        
        if(::wxDirExists(str))
        {
            // add to array
            if(m_recentPaths.Count() == 0)
                mnu->AppendSeparator();

            lastUsedID = CM_RECENT_BUILD_ITEM + m_recentPaths.Count();
            m_recentPaths.Add(str);

            // when we have more in list then we can display, prune and 
            // remove some menu items until we have room (and available ID's again)
            if(m_recentPaths.Count() > CM_MAX_RECENT_PATHS)
            {
                // prune the list
                while(m_recentPaths.Count() > CM_MAX_RECENT_PATHS)
                    m_recentPaths.RemoveAt(0);  

                // now determine count, and remove until we have room
                int index = mnu->GetMenuItemCount() - 1;
                int count = 0;
                wxASSERT(index > 0);
                
                wxMenuItem *item;
                do
                {
                    item = mnu->FindItemByPosition(index);
                    if(item)
                    {
                        if(item->IsSeparator())
                        {
                            // next index is valid item
                            index ++;
                            break;
                        }
                        else
                            count ++;
                    }

                    index --;
                }
                while(index >= 0 && item);

                // ok, if count > CM_MAX_RECENT_PATHS then we are going to
                // delete some items on the index position
                if(count >= CM_MAX_RECENT_PATHS)
                {
                    // delete items that are exceeding
                    while(count >= CM_MAX_RECENT_PATHS)
                    {
                        lastUsedID = mnu->FindItemByPosition(index)->GetId();
                        mnu->Delete(lastUsedID);
                        count --;
                    }
                }
            }

            // append item
            mnu->Append(lastUsedID, str);
        }
    }
}

bool CMakeSetupFrm::PerformCacheRun()
{
    bool enable = false;
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    cmCacheManager::CacheIterator it = cachem->NewIterator();

    // remove all items that are no longer present
    size_t j = 0;
    while(j < m_cmOptions->GetCount())
    {
        // check to see if it is still in the CMake cache
        // if it is still in the cache then it is no longer new
        wxPropertyItem *item = m_cmOptions->GetItem(j);
        if ( !it.Find((const char*)item->GetPropName().c_str()) )
            m_cmOptions->RemoveProperty(item);
        else
        {
            // ok we found it, mark as old
            item->SetNewValue(false);
            int row = m_cmOptions->FindProperty(item);
            if(row != -1) 
                m_cmOptions->UpdatePropertyItem(item, row);
            j++;
        }
    }

    if(cachem->GetSize() > 0 && !cmSystemTools::GetErrorOccuredFlag())
    {
        bool enable = true;     
        for(size_t i = 0; i < m_cmOptions->GetCount(); i++)
        {
            wxPropertyItem* item = m_cmOptions->GetItem(i);
            if(item->GetAdvanced())
            {
                if(item->GetNewValue() && m_cmOptions->GetShowAdvanced())
                {
                    // if one new value then disable to OK button
                    enable = false;
                    break;
                }
            }
            else
            {
                if(item->GetNewValue())
                {
                    // if one new value then disable to OK button
                    enable = false;
                    break;
                }
            }
        }
    }

    return enable;  
}

void CMakeSetupFrm::FillCacheGUIFromCacheManager()
{
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    cmCacheManager::CacheIterator it = cachem->NewIterator();
  
    // remove all items that are no longer present
    size_t j = 0;
    while(j < m_cmOptions->GetCount())
    {
        // check to see if it is still in the CMake cache
        // if it is still in the cache then it is no longer new
        wxPropertyItem *item = m_cmOptions->GetItem(j);
        if ( !it.Find((const char*)item->GetPropName().c_str()) )
            m_cmOptions->RemoveProperty(item);
        else
            j++;
    }

    // if there are already entries in the cache, then
    // put the new ones in the top, so they show up first
    bool reverseOrder = false;
    for(cmCacheManager::CacheIterator i = cachem->NewIterator(); !i.IsAtEnd(); i.Next())
    {
        const char* key = i.GetName();

        // if value has trailing space or tab, enclose it in single quotes
        // to enforce the fact that it has 'invisible' trailing stuff
        std::string value = i.GetValue();
        if (value.size() && (value[value.size() - 1] == ' ' ||  value[value.size() - 1] == '\t'))
            value = '\'' + value +  '\'';

        bool advanced = i.GetPropertyAsBool("ADVANCED");
        switch(i.GetType() )
        {
        case cmCacheManager::BOOL:
            {
                wxString OnOff;
                
                if(cmSystemTools::IsOn(value.c_str()))
                    OnOff = wxT("ON");
                else
                    OnOff = wxT("OFF");

                m_cmOptions->AddProperty(key,
                                         OnOff.c_str(),
                                         i.GetProperty("HELPSTRING"),
                                         wxPropertyList::CHECKBOX, "ON|OFF",
                                         reverseOrder,
                                         advanced );
            }
            break;

        case cmCacheManager::PATH:
            m_cmOptions->AddProperty(key, 
                                     value.c_str(),
                                     i.GetProperty("HELPSTRING"),
                                     wxPropertyList::PATH,"",
                                     reverseOrder, advanced);
            break;
        
        case cmCacheManager::FILEPATH:
            m_cmOptions->AddProperty(key, 
                                     value.c_str(),
                                     i.GetProperty("HELPSTRING"),
                                     wxPropertyList::FILE,"",
                                     reverseOrder, advanced);
            break;
      
        case cmCacheManager::STRING:
            m_cmOptions->AddProperty(key,
                                     value.c_str(),
                                     i.GetProperty("HELPSTRING"),
                                     wxPropertyList::EDIT,"",
                                     reverseOrder, advanced);
            break;
      
        case cmCacheManager::INTERNAL:
            {
                wxPropertyItem *pItem = m_cmOptions->FindPropertyByName(key);
                if(pItem)
                    m_cmOptions->RemoveProperty(pItem);
            }
            break;          
        }
    }
}

void CMakeSetupFrm::OnExitTimer(wxTimerEvent &event)
{
    Close();
} 

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BROWSE_PROJECT
 */

void CMakeSetupFrm::OnButtonBrowseProject( wxCommandEvent& event )
{
    const wxString& dir = wxDirSelector("Select project directory", m_cmProjectPath->GetValue());
    if(!dir.IsEmpty())
        m_cmProjectPath->SetValue(dir);
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BROWSE_BUILD
 */

void CMakeSetupFrm::OnButtonBrowseBuild( wxCommandEvent& event )
{
    const wxString& dir = wxDirSelector("Select build directory", m_cmBuildPath->GetValue());
    if(!dir.IsEmpty())
        m_cmBuildPath->SetValue(dir);
}

/*!
 * wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_SHOW_ADVANCED
 */

void CMakeSetupFrm::OnShowAdvancedValues( wxCommandEvent& event )
{
    if(m_cmShowAdvanced->GetValue())
        m_cmOptions->ShowAdvanced();
    else
        m_cmOptions->HideAdvanced();
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_DO_CONFIGURE
 */

void CMakeSetupFrm::OnButtonConfigure( wxCommandEvent& event )
{
    DoConfigure();
}

void CMakeSetupFrm::DoConfigure()
{
    // enable error messages each time configure is pressed
    cmSystemTools::EnableMessages();
    m_cmOptions->HideControls();

    cmSystemTools::ResetErrorOccuredFlag(); 
    
    // instantiate a dialog for the progress meter

    PerformCacheRun();
    RunCMake(false);
}

int CMakeSetupFrm::RunCMake(bool generateProjectFiles)
{
    int value = -1;
    
    // clear log
    m_cmLog->Clear();
    m_cmLog->DiscardEdits();

    wxString builddir = m_cmBuildPath->GetValue(), 
             sourcedir = m_cmProjectPath->GetValue(),
             err = wxT("Error in configuration process, project files may be invalid");


    // sanity check for people pressing OK on empty dirs
    if(builddir.Trim().IsEmpty() || sourcedir.Trim().IsEmpty())
    {
        wxMessageBox(wxT("Please enter a valid source directory and build directory"), wxT("Error"), wxOK | wxICON_ERROR, this);
        return -1;
    }

    // check if the directory exists, if not, create it
    if(!cmSystemTools::FileExists(builddir.c_str()))
    {
        wxString str;
        str << wxT("Build directory does not exist, should I create it?\n\nDirectory: ") << builddir;
    
        int answer = wxMessageBox(str, wxT("Create directory"), wxYES_NO, this);
        if (answer == wxYES)
        {
            if(!cmSystemTools::MakeDirectory(builddir.c_str()))
            {
                // could not create, tell and abort
                wxMessageBox(wxT("Could not create directory"), wxT("Error"), wxOK | wxICON_ERROR, this);
                return -1;
            }
        }
        else
        {
            // we abort because the user did not want to make the directory
            wxMessageBox(wxT("Build Project aborted, nothing done."), wxT("Aborted"), 
                         wxOK | wxICON_EXCLAMATION, this);
            return -1;
        }
    }

    /** show progress dialog that informs the user with a progress bar */ 
    if(m_progressDlg)
        m_progressDlg->Destroy();

    m_progressDlg = new CMProgressDialog(this);
    m_progressDlg->Show();

    // set the wait cursor
    m_RunningConfigure = true;
    UpdateWindowState();

    // always save the current gui values to disk
    SaveCacheFromGUI();
  
    // Make sure we are working from the cache on disk
    LoadCacheFromDiskToGUI(); 

    // setup the cmake instance
    if (generateProjectFiles)
    {
        if(m_cmake->Generate() != 0)
        {
            wxMessageBox(err, wxT("Error"), wxOK | wxICON_ERROR, this);
            cmSystemTools::Error(err.c_str());
            value = -1;
        }
        else
        {
            value = 0;
            m_cmOptions->SetProjectGenerated(true); // clear cache dirty when generated
        }
    }
    else
    {
        // set paths 
        m_cmake->SetHomeDirectory(m_cmProjectPath->GetValue().c_str());
        m_cmake->SetStartDirectory(m_cmProjectPath->GetValue().c_str());
        m_cmake->SetHomeOutputDirectory(m_cmBuildPath->GetValue().c_str());
        m_cmake->SetStartOutputDirectory(m_cmBuildPath->GetValue().c_str());
        
        m_cmake->SetGlobalGenerator(m_cmake->CreateGlobalGenerator(m_cmGeneratorChoice->GetValue().c_str()));
        m_cmake->SetCMakeCommand(m_PathToExecutable.c_str());
        m_cmake->LoadCache();
        if(m_cmake->Configure() != 0)
        {
            wxMessageBox(err, wxT("Error"), wxOK | wxICON_ERROR, this);
            cmSystemTools::Error(err.c_str());
        }
        
        // update the GUI with any new values in the caused by the
        // generation process
        LoadCacheFromDiskToGUI();
    }

    m_RunningConfigure = false;
    
    if(!value)
        cmSystemTools::ResetErrorOccuredFlag();

    m_progressDlg->Destroy();
    m_progressDlg = 0;

    // reset the statusbar progress 
    wxStatusBar *bar = GetStatusBar();
    if(bar)
        bar->SetStatusText(wxEmptyString, 1);

    UpdateWindowState();
    return value;
}

//! Save GUI values to cmCacheManager and then save to disk.
void CMakeSetupFrm::SaveCacheFromGUI()
{
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    FillCacheManagerFromCacheGUI();
  
    // write the cache to disk
    if(!m_cmBuildPath->GetValue().Trim().IsEmpty())
        cachem->SaveCache(m_cmBuildPath->GetValue().c_str());
}

void CMakeSetupFrm::FillCacheManagerFromCacheGUI()
{ 
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    
    cmCacheManager::CacheIterator it = cachem->NewIterator();
    for(size_t i = 0; i < m_cmOptions->GetCount(); i++)
    {
        wxPropertyItem* item = m_cmOptions->GetItem(i); 
        if ( it.Find((const char*)item->GetPropName().c_str()) )
        {
            // if value is enclosed in single quotes ('foo') then remove them
            // they were used to enforce the fact that it had 'invisible' 
            // trailing stuff
            if (item->GetCurValue().Len() >= 2 &&
                item->GetCurValue().GetChar(0) == '\'' && 
                item->GetCurValue().GetChar(item->GetCurValue().Len() - 1) == '\'') 
            {
                it.SetValue(item->GetCurValue().Mid(1, item->GetCurValue().Len() - 2).c_str());
            }
            else
                it.SetValue(item->GetCurValue().c_str());
        }
    }
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_DO_OK
 */

void CMakeSetupFrm::OnButtonOk( wxCommandEvent& event )
{
    DoGenerate();
}

void CMakeSetupFrm::DoGenerate()
{
    cmSystemTools::EnableMessages();
    
    cmSystemTools::ResetErrorOccuredFlag(); 
    
    m_cmOptions->HideControls();
    PerformCacheRun();
  
    if(!RunCMake(true))
    {
        // issue a close when this is done (this is issued by menu "Generate and Exit"
        if(m_quitAfterGenerating)
            Close();
        else if(!wxGetKeyState(WXK_SHIFT))
        {
            bool close;
            m_config->Read(CM_CLOSEAFTERGEN, &close, CM_CLOSEAFTERGEN_DEF);
            
            if(!close)
                wxMessageBox(wxT("Building of project files succesful!"), wxT("Success!"), wxOK|wxICON_INFORMATION);
            else
                Close();
        }
    }
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_DO_CANCEL
 */

void CMakeSetupFrm::OnButtonCancel( wxCommandEvent& event )
{
    DoCancelButton();
}

void CMakeSetupFrm::DoCancelButton()
{
    if(m_RunningConfigure)
    {
        int result = wxMessageBox(wxT("You are in the middle of a Configure.\n"
                                      "If you Cancel now the configure information will be lost.\n"
                                      "Are you sure you want to Cancel?"), wxT("Warning"), wxYES_NO|wxICON_WARNING);
        if(result == wxYES)
            cmSystemTools::SetFatalErrorOccured();
        else
            if(m_progressDlg)
                m_progressDlg->ResetCancel();
    }
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_DO_DELETE_CACHE
 */

void CMakeSetupFrm::OnButtonDeleteCache( wxCommandEvent& event )
{
    DoDeleteCache();
}

void CMakeSetupFrm::DoDeleteCache()
{
    bool deletecache = true;
    if(m_cmOptions->IsCacheDirty() || (m_cmOptions->GetCount() > 0 && !m_cmOptions->IsGenerated()))
    {
        int result = ::wxMessageBox(_("You have changed options, are you sure you want to delete all items?\n"), 
                                    _("Warning"), wxYES_NO|wxICON_QUESTION);
        
        // when user wants to wait, wait.. else quit
        if(result == wxNO)
            deletecache = false;
            
    }

    if(deletecache)
    {
        // indicate that we haven't generated a project yet
        m_cmOptions->SetProjectGenerated(false);
        
        if(!m_cmBuildPath->GetValue().Trim().IsEmpty() && m_cmake != 0)
            m_cmake->GetCacheManager()->DeleteCache(m_cmBuildPath->GetValue().Trim());
      
        LoadCacheFromDiskToGUI();   
        UpdateWindowState();
    }
}

/*!
 * Should we show tooltips?
 */

bool CMakeSetupFrm::ShowToolTips()
{
    return TRUE;
}

/*!
 * Get bitmap resources
 */

wxBitmap CMakeSetupFrm::GetBitmapResource( const wxString& name )
{
    // Bitmap retrieval
////@begin CMakeSetupFrm bitmap retrieval
    return wxNullBitmap;
////@end CMakeSetupFrm bitmap retrieval
}

/*!
 * Get icon resources
 */

wxIcon CMakeSetupFrm::GetIconResource( const wxString& name )
{
    // Icon retrieval
////@begin CMakeSetupFrm icon retrieval
    if (name == wxT("cmake_icon.xpm"))
    {
        wxIcon icon(_T("cmake_icon.xpm"), wxBITMAP_TYPE_XPM);
        return icon;
    }
    return wxNullIcon;
////@end CMakeSetupFrm icon retrieval
}

/*!
 * wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING event handler for ID_SPLITTERWINDOW
 */

void CMakeSetupFrm::OnSplitterPosChanging( wxSplitterEvent& event )
{
    int width, height;

    GetSize(&width, &height);

    if((height > 100))
    {
        if(event.GetSashPosition() < 170)
            event.SetSashPosition(170);
        else
        {
            if(event.GetSashPosition() > (height - 180))
                event.SetSashPosition(height - 180);
        }
    }
    else
        event.Veto();

}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_CLEAR_LOG
 */

void CMakeSetupFrm::OnClearLogClick( wxCommandEvent& event )
{
    // delete the log text
    m_cmLog->Clear();
    m_cmLog->DiscardEdits();
}


/*!
 * wxEVT_COMMAND_TEXT_UPDATED event handler for ID_SOURCE_BUILD_PATH
 */

void CMakeSetupFrm::OnSourceBuildPathUpdated( wxCommandEvent& event )
{
    DoReloadCache();
}

void CMakeSetupFrm::DoReloadCache()
{
    wxString buildpath = m_cmBuildPath->GetValue();
    // The build dir has changed, check if there is a cache, and 
    // grab the source dir from it

    // make sure the call to update grid is not executed
    m_noRefresh = true;
    m_cmSearchQuery->SetValue(_(""));
    m_noRefresh = false;

    std::string path = buildpath.c_str();
    cmSystemTools::ConvertToUnixSlashes(path);

    // adjust the cmake instance
    m_cmake->SetHomeOutputDirectory(buildpath.c_str());
    m_cmake->SetStartOutputDirectory(buildpath.c_str());

    std::string cache_file = path;
    cache_file += "/CMakeCache.txt";

    // fill in the project path where the source is located, this is 
    // read from the CMake cache
    cmCacheManager *cachem = m_cmake->GetCacheManager();
    cmCacheManager::CacheIterator it = cachem->NewIterator();
    if (cmSystemTools::FileExists(cache_file.c_str()) && cachem->LoadCache(path.c_str()) && 
        it.Find("CMAKE_HOME_DIRECTORY"))
    {
        path = ConvertToWindowsPath(it.GetValue());
        m_cmProjectPath->SetValue(path.c_str());
    }

    m_cmOptions->RemoveAll();
    LoadCacheFromDiskToGUI();
    UpdateWindowState();
}


/*!
 * wxEVT_COMMAND_TEXT_ENTER event handler for ID_SOURCE_BUILD_PATH
 */

void CMakeSetupFrm::OnSourceBuildPathEnter( wxCommandEvent& event )
{
    OnSourceBuildPathUpdated(event);
}

/*!
 * wxEVT_MOTION event handler for ID_OPTIONS
 */

void CMakeSetupFrm::OnPropertyMotion( wxMouseEvent& event )
{
    ShowPropertyDescription(m_cmOptions->YToRow(event.GetY()));
    event.Skip();
}


/*!
 * wxEVT_GRID_SELECT_CELL event handler for ID_OPTIONS
 */

void CMakeSetupFrm::OnGridSelectCell( wxGridEvent& event )
{
    // show description 
    ShowPropertyDescription(event.GetRow());
    
    // enable or disable the browse button
    m_cmBrowseCell->Enable(m_cmOptions->IsSelectedItemBrowsable(event.GetRow()));
    event.Skip();
}

void CMakeSetupFrm::ShowPropertyDescription(int row)
{
    if(row == wxNOT_FOUND || row < 0)
        m_cmDescription->SetValue(wxEmptyString);
    else
    {
        wxPropertyItem *pItem = m_cmOptions->GetPropertyItemFromRow(row);
        if(pItem)
            m_cmDescription->SetValue(pItem->GetHelpString());
        else
            m_cmDescription->SetValue(wxEmptyString);
    }
}

/*!
 * wxEVT_GRID_CELL_CHANGE event handler for ID_OPTIONS
 */

void CMakeSetupFrm::OnCellChange( wxGridEvent& event )
{
    // update the button state when the cache is invalidated
    UpdateWindowState();
}

void CMakeSetupFrm::OnRecentFileMenu( wxCommandEvent &event )
{   
    if(GetMenuBar())
    {
        // get file menu
        wxMenu *mnu = GetMenuBar()->GetMenu(0);
        wxASSERT(mnu != 0);

        wxMenuItem *item = mnu->FindItem(event.GetId());
        if(item)
            m_cmBuildPath->SetValue(item->GetLabel());
    }
}
/*!
 * wxEVT_COMMAND_COMBOBOX_SELECTED event handler for ID_COMBOBOX
 */

void CMakeSetupFrm::OnSearchquerySelected( wxCommandEvent& event )
{
    m_cmOptions->SetQuery(m_cmSearchQuery->GetValue());
}

void CMakeSetupFrm::OnAddQuery ( wxCommandEvent &event )
{
    // add current text if not yet present
    if(m_cmSearchQuery->FindString(m_cmSearchQuery->GetValue()) == wxNOT_FOUND)
    {
        m_cmSearchQuery->Append(m_cmSearchQuery->GetValue());
        
        // if too many items are present, prune
        while(m_cmSearchQuery->GetCount() > CM_MAX_SEARCH_QUERIES)
            m_cmSearchQuery->Delete(0);     
    }
}

/*!
 * wxEVT_COMMAND_TEXT_UPDATED event handler for ID_SEARCHQUERY
 */

void CMakeSetupFrm::OnSearchqueryUpdated( wxCommandEvent& event )
{
    // only refresh when this event was caused by user
    if(!m_noRefresh)
        m_cmOptions->SetQuery(m_cmSearchQuery->GetValue());
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BROWSE_GRID
 */

void CMakeSetupFrm::OnBrowseGridClick( wxCommandEvent& event )
{
    m_cmOptions->BrowseSelectedItem();
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_RELOAD_CACHE
 */

void CMakeSetupFrm::OnMenuReloadCacheClick( wxCommandEvent& event )
{
    bool reload = true;
    if(m_cmOptions->IsCacheDirty() || (m_cmOptions->GetCount() > 0 && !m_cmOptions->IsGenerated()))
    {
        int result = ::wxMessageBox(_("You have changed options, are you sure you want to reload?\n"), 
                                    _("Warning"), wxYES_NO|wxICON_QUESTION);
        
        // when user wants to wait, wait.. else quit
        if(result == wxNO)
            reload = false;
            
    }

    if(reload) 
        DoReloadCache();
}

/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_DELETE_CACHE
 */

void CMakeSetupFrm::OnMenuDeleteCacheClick( wxCommandEvent& event )
{
    DoDeleteCache();
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_QUIT
 */

void CMakeSetupFrm::OnMenuQuitClick( wxCommandEvent& event )
{
    // the close event will veto if the user 
    // did not want to quit due to unsaved changes
    Close();
}


/*!
 * wxEVT_CLOSE_WINDOW event handler for ID_FRAME
 */

void CMakeSetupFrm::OnCloseWindow( wxCloseEvent& event )
{
    // ask quit if:
    //  - The cache is dirty
    //  - Or the cache is OK and has some items, and no project was generated recently (configure -> generate)
    if(m_cmOptions->IsCacheDirty() || (m_cmOptions->GetCount() > 0 && !m_cmOptions->IsGenerated()))
    {
        int result = ::wxMessageBox(_("You have changed options, but not yet generated the projects\n"
                                      "are you sure you want to quit?"), _("Warning"), wxYES_NO|wxICON_QUESTION);
        
        // when user wants to wait, wait.. else quit
        if(result == wxNO)
            event.Veto();
        else
            event.Skip();
    }
    else
        event.Skip();
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_ABOUTDLG
 */

void CMakeSetupFrm::OnAboutClick( wxCommandEvent& event )
{
    CMAboutDlg *dlg = new CMAboutDlg(this);
    
    wxArrayString generators;
    std::vector<std::string> names; 
    m_cmake->GetRegisteredGenerators(names);
    for(std::vector<std::string>::iterator i = names.begin(); i != names.end(); ++i)
        generators.Add(i->c_str());

    wxString cmversion, cmsversion;
    cmversion.Printf("v%i.%i %s", cmake::GetMajorVersion(), cmake::GetMinorVersion(), cmake::GetReleaseVersion());
    cmsversion.Printf("v%i.%i%s", CMAKEGUI_MAJORVER, CMAKEGUI_MINORVER, CMAKEGUI_ADDVER);

    dlg->SetAboutText(cmversion, cmsversion, generators);

    dlg->ShowModal();
    dlg->Destroy();
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_CMAKE_OPTIONS
 */

void CMakeSetupFrm::OnOptionsClick( wxCommandEvent& event )
{
    CMOptionsDlg *dlg = new CMOptionsDlg(this);

    dlg->SetConfig(m_config);
    if(dlg->ShowModal() == wxID_OK)
    {
        // store volatile settings
        dlg->GetConfig(m_config);
        
        // apply non volatile setting such as clear search query, recent menu, etc.
        SyncFormOptions(dlg);
    }

    dlg->Destroy();
}

void CMakeSetupFrm::SyncFormOptions(CMOptionsDlg *dlg)
{
    // TODO: Clear search query etc.
}
/*!
 * wxEVT_COMMAND_SPLITTER_DOUBLECLICKED event handler for ID_SPLITTERWINDOW
 */

void CMakeSetupFrm::OnSplitterwindowSashDClick( wxSplitterEvent& event )
{
    event.Veto(); 
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_CONFIGURE
 */

void CMakeSetupFrm::OnMenuConfigureClick( wxCommandEvent& event )
{
    DoConfigure();
}

/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_EXITGENERATE
 */

void CMakeSetupFrm::OnMenuGenerateClick( wxCommandEvent& event )
{
    // set flag so that a close command is issued
    // after generating the cmake cache to projects
    m_quitAfterGenerating = true;
    DoGenerate();
    m_quitAfterGenerating = false;
}


/*!
 * wxEVT_COMMAND_MENU_SELECTED event handler for ID_MENU_TOGGLE_ADVANCED
 */

void CMakeSetupFrm::OnMenuToggleAdvancedClick( wxCommandEvent& event )
{
    // toggle the check box
    m_cmShowAdvanced->SetValue(!m_cmShowAdvanced->GetValue());
    OnShowAdvancedValues(event);
}


