//====================================================================
// Although great care has gone into developing this software,
// it is provided without any guarantee of reliability, accuracy
// of information, or correctness of operation. I am not responsible
// for any damages that may occur as a result of using this software.
// Use this software entirely at your own risk.
// Copyright 2003, Chris Richardson
//
// Description: Directory search options page.
//
//====================================================================
#include "stdafx.h"
#include "incfinder.h"
#include "DirectorySearchPage.h"
#include "Settings.h"
#include "FileIterator.h"
#include "Parser.h"
#include "DSObjects.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDirectoryFileIterator Implementation.
/////////////////////////////////////////////////////////////////////////////
class CDirectoryFileIterator : public CFileIterator
{
public:
CDirectoryFileIterator();
virtual ~CDirectoryFileIterator();
void ParseOptions( const TCHAR * p_pszDirectories,
const TCHAR * p_pszFileMasks,
const TCHAR * p_pszIncludeDirs,
BOOL p_bRecurseSubDirectories );
virtual void Prepare( HANDLE p_hEvent,
CParser * p_poParser );
virtual bool GetNextFile( CTCharString & p_rsFile );
protected:
CStdStringArray c_oSearchDirectories;
CStdStringArray c_oFileMasks;
CDSParsedSettings c_oSettings;
BOOL c_bRecurseSubDirectories;
int c_iCurrentDirectory;
int c_iCurrentMask;
bool c_bFoundLastFile;
CStdStringArray c_oFullDirectoryList;
CFileFind c_oFileFind;
void GetDirectoryList( const TCHAR * p_pszDir, CStdStringArray & p_roDirs );
};
CDirectoryFileIterator::CDirectoryFileIterator() :
c_bRecurseSubDirectories( FALSE ),
c_iCurrentDirectory( -1 ),
c_iCurrentMask( 0 ),
c_bFoundLastFile( true )
{
}
//
// ------------------------------------------------------------------
//
CDirectoryFileIterator::~CDirectoryFileIterator()
{
}
//
// ------------------------------------------------------------------
//
void CDirectoryFileIterator::ParseOptions( const TCHAR * p_pszDirectories,
const TCHAR * p_pszFileMasks,
const TCHAR * p_pszIncludeDirs,
BOOL p_bRecurseSubDirectories )
{
c_bRecurseSubDirectories = p_bRecurseSubDirectories;
c_iCurrentDirectory = -1;
c_iCurrentMask = 0;
c_bFoundLastFile = false;
c_oSearchDirectories.clear();
c_oSettings.Clear();
c_oFileMasks.clear();
// Parse the directories into a list.
ParseSeparatedList( p_pszDirectories, _T(";"), c_oSearchDirectories );
// Parse file masks into a list..
ParseSeparatedList( p_pszFileMasks, _T(";"), c_oFileMasks );
// Parse include dirs into a temporary list.
CStdStringArray a_oTempIncludeDirs;
ParseSeparatedList( p_pszIncludeDirs, _T(";"), a_oTempIncludeDirs );
CStdStringArray & a_roIncludeDirs = c_oSettings.GetIncludes();
// Expand include directory environment strings.
for( int dir = 0; dir<a_oTempIncludeDirs.size(); ++dir )
{
CTCharString a_sTemp = a_oTempIncludeDirs[dir];
if( a_sTemp[0] == _T('%') )
{
// Remove the '%'.
a_sTemp.erase( a_sTemp.begin() );
// Get the number of chars required to store the environment variable.
DWORD a_dwChars = GetEnvironmentVariable( a_sTemp.c_str(), NULL, 0 );
if( a_dwChars != 0 )
{
// Lookup the environment variable.
TCHAR * a_pszTemp = new TCHAR[a_dwChars + 1];
memset( a_pszTemp, 0, sizeof( TCHAR ) * (a_dwChars + 1) );
GetEnvironmentVariable( a_sTemp.c_str(), a_pszTemp, a_dwChars );
// Parse the environment variable into an array of strings.
CStdStringArray a_oExpandedDirectories;
ParseSeparatedList( a_pszTemp, _T(";"), a_oExpandedDirectories );
// Insert the directories of the environment variable into the include directory list.
a_roIncludeDirs.insert( a_roIncludeDirs.end(), a_oExpandedDirectories.begin(), a_oExpandedDirectories.end() );
delete [] a_pszTemp;
}
}
else
// It's not an environment string, just insert it as a regular path.
a_roIncludeDirs.push_back( a_sTemp );
}
}
//
// ------------------------------------------------------------------
//
void CDirectoryFileIterator::GetDirectoryList( const TCHAR * p_pszDir, CStdStringArray & p_roDirs )
{
TCHAR a_szDirectory[MAX_PATH + 1] = {0};
_tcscpy( a_szDirectory, p_pszDir );
int a_iLen = _tcslen( a_szDirectory );
if( a_szDirectory[a_iLen] != _T('\\') && a_szDirectory[a_iLen] != _T('/') )
_tcscat( a_szDirectory, _T("\\") );
// This doesn't quite get the job done. It doesn't find directories with dashes or dots in their name.
// How to fix without having to iterate all the files in each directory as well?
//_tcscat( a_szDirectory, _T("*..") );
_tcscat( a_szDirectory, _T("*.*") );
// Find all the subdirectories of p_pszDir.
CStdStringArray a_oDirectories;
CFileFind a_oFileFind;
BOOL a_bStop = FALSE;
if( a_oFileFind.FindFile( a_szDirectory ) )
{
while( 1 )
{
unsigned long a_ulResult = WaitForSingleObject( c_hStopEvent, 0 );
if( a_ulResult != WAIT_TIMEOUT )
{
a_bStop = TRUE;
break;
}
BOOL a_bBreak = !a_oFileFind.FindNextFile();
//TRACE( _T("%s\n"), (LPCTSTR)a_oFileFind.GetFilePath() );
if( a_oFileFind.IsDirectory() && !a_oFileFind.IsDots() )
a_oDirectories.push_back( (LPCTSTR)a_oFileFind.GetFilePath() );
if( a_bBreak )
break;
}
}
if( a_bStop )
return;
p_roDirs.insert( p_roDirs.end(), a_oDirectories.begin(), a_oDirectories.end() );
for( int i = 0; i<a_oDirectories.size(); ++i )
{
// Recursively find more subdirectories.
GetDirectoryList( a_oDirectories[i].c_str(), p_roDirs );
}
}
//
// ------------------------------------------------------------------
//
void CDirectoryFileIterator::Prepare( HANDLE p_hEvent,
CParser * p_poParser )
{
CFileIterator::Prepare( p_hEvent, p_poParser );
c_oFullDirectoryList.clear();
c_oFullDirectoryList.insert( c_oFullDirectoryList.end(), c_oSearchDirectories.begin(), c_oSearchDirectories.end() );
if( c_bRecurseSubDirectories )
{
for( int dir = 0; dir<c_oSearchDirectories.size(); ++dir )
{
// Build a list of all the sub-directories.
GetDirectoryList( c_oSearchDirectories[dir].c_str(), c_oFullDirectoryList );
unsigned long a_ulResult = WaitForSingleObject( c_hStopEvent, 1 );
if( a_ulResult != WAIT_TIMEOUT )
break;
}
}
}
//
// ------------------------------------------------------------------
//
bool CDirectoryFileIterator::GetNextFile( CTCharString & p_rsFile )
{
bool a_bStartFind = false;
if( c_iCurrentDirectory == -1 )
{
a_bStartFind = TRUE;
c_iCurrentDirectory = 0;
c_bFoundLastFile = false;
}
while( 1 )
{
if( !a_bStartFind && !c_bFoundLastFile )
{
BOOL a_bResult = c_oFileFind.FindNextFile();
if( !a_bResult )
{
c_iCurrentMask++;
if( c_iCurrentMask >= c_oFileMasks.size() )
{
c_iCurrentMask = 0;
c_iCurrentDirectory++;
}
a_bStartFind = TRUE;
c_bFoundLastFile = true;
}
p_rsFile = c_oFileFind.GetFilePath();
c_poParser->SetSettings( c_oSettings );
return true;
}
if( c_iCurrentDirectory >= c_oFullDirectoryList.size() )
return false;
TCHAR a_szDirectory[MAX_PATH + 1] = {0};
_tcscpy( a_szDirectory, c_oFullDirectoryList[c_iCurrentDirectory].c_str() );
int a_iLen = _tcslen( a_szDirectory );
if( a_szDirectory[a_iLen] != _T('\\') && a_szDirectory[a_iLen] != _T('/') )
_tcscat( a_szDirectory, _T("\\") );
CTCharString a_sMask = c_oFileMasks[c_iCurrentMask];
// Build a file spec of the current directory plus the current file mask.
TCHAR a_szFullSpec[MAX_PATH + 1] = {0};
_stprintf( a_szFullSpec, _T("%s%s"), a_szDirectory, a_sMask.c_str() );
if( c_oFileFind.FindFile( a_szFullSpec ) )
{
a_bStartFind = false;
c_bFoundLastFile = false;
continue;
}
else
{
c_iCurrentMask++;
if( c_iCurrentMask == c_oFileMasks.size() )
{
c_iCurrentMask = 0;
c_iCurrentDirectory++;
}
}
}
return false;
}
//
// ------------------------------------------------------------------
//
/////////////////////////////////////////////////////////////////////////////
// CDirectorySearchPage Implementation.
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CDirectorySearchPage, CSearchPropertyPage)
CDirectorySearchPage::CDirectorySearchPage() : CSearchPropertyPage(CDirectorySearchPage::IDD)
{
//{{AFX_DATA_INIT(CDirectorySearchPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
c_poIterator = new CDirectoryFileIterator;
}
//
// ------------------------------------------------------------------
//
CDirectorySearchPage::~CDirectorySearchPage()
{
if( c_poIterator )
{
delete c_poIterator;
c_poIterator = NULL;
}
}
//
// ------------------------------------------------------------------
//
void CDirectorySearchPage::DoDataExchange(CDataExchange* pDX)
{
CSearchPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDirectorySearchPage)
DDX_Control(pDX, IDC_SUB_DIRECTORIES, c_oSubDirectories);
DDX_Control(pDX, IDC_INCLUDE_DIRS, c_oIncludeDirs);
DDX_Control(pDX, IDC_BROWSE_DIRECTORY, c_oBrowseDirectory);
DDX_Control(pDX, IDC_FILE_MASK, c_oFileMask);
DDX_Control(pDX, IDC_SEARCH_DIRECTORY, c_oSearchDirectory);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDirectorySearchPage, CSearchPropertyPage)
//{{AFX_MSG_MAP(CDirectorySearchPage)
ON_WM_SIZE()
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BROWSE_DIRECTORY, OnBrowseDirectory)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDirectorySearchPage non-message handlers
/////////////////////////////////////////////////////////////////////////////
CFileIterator * CDirectorySearchPage::PrepareToStart()
{
CString a_sSearchPath;
HandleComboBox( &c_oSearchDirectory, a_sSearchPath );
CString a_sFileMask;
HandleComboBox( &c_oFileMask, a_sFileMask );
CString a_sIncludeDirs;
c_oIncludeDirs.GetWindowText( a_sIncludeDirs );
c_poIterator->ParseOptions( a_sSearchPath,
a_sFileMask,
a_sIncludeDirs,
(c_oSubDirectories.GetCheck() == 1) );
return c_poIterator;
}
//
// ------------------------------------------------------------------
//
void CDirectorySearchPage::SearchStopped()
{
}
//
// ------------------------------------------------------------------
//
/////////////////////////////////////////////////////////////////////////////
// CDirectorySearchPage message handlers
/////////////////////////////////////////////////////////////////////////////
BOOL CDirectorySearchPage::OnInitDialog()
{
CSearchPropertyPage::OnInitDialog();
CSettings & a_roSettings = CSettings::GetSettings();
// Load the previous directories and masks from the settings.
int i = 0;
for( i = 0; i<a_roSettings.c_oDirectories.size(); ++i )
{
c_oSearchDirectory.AddString( a_roSettings.c_oDirectories[i].c_str() );
}
c_oSearchDirectory.SetCurSel( 0 );
for( i = 0; i<a_roSettings.c_oFileMasks.size(); ++i )
{
c_oFileMask.AddString( a_roSettings.c_oFileMasks[i].c_str() );
}
c_oFileMask.SetCurSel( 0 );
c_oIncludeDirs.SetWindowText( a_roSettings.c_sIncludeDirs.c_str() );
c_oSubDirectories.SetCheck( a_roSettings.c_bRecurse != 0 );
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
//
// ------------------------------------------------------------------
//
void CDirectorySearchPage::OnSize(UINT nType, int cx, int cy)
{
CSearchPropertyPage::OnSize(nType, cx, cy);
if( !IsWindow( c_oSearchDirectory ) )
// Our controls haven't been subclassed yet.
return;
// Resize our controls.
//
int a_iBigBorder = 0;
CRect a_oRect;
c_oSearchDirectory.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
a_iBigBorder = a_oRect.top;
c_oBrowseDirectory.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
c_oBrowseDirectory.MoveWindow( cx - a_oRect.Width() - a_iBigBorder,
a_oRect.top,
a_oRect.Width(),
a_oRect.Height() );
c_oBrowseDirectory.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
int a_iComboRightEdge = a_oRect.left;
c_oSearchDirectory.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
c_oSearchDirectory.MoveWindow( a_oRect.left,
a_oRect.top,
a_iComboRightEdge - a_oRect.left,
a_oRect.Height() );
c_oFileMask.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
c_oFileMask.MoveWindow( a_oRect.left,
a_oRect.top,
a_iComboRightEdge - a_oRect.left,
a_oRect.Height() );
c_oIncludeDirs.GetWindowRect( &a_oRect );
ScreenToClient( &a_oRect );
c_oIncludeDirs.MoveWindow( a_oRect.left,
a_oRect.top,
a_iComboRightEdge - a_oRect.left,
a_oRect.Height() );
}
//
// ------------------------------------------------------------------
//
void CDirectorySearchPage::OnDestroy()
{
CSearchPropertyPage::OnDestroy();
// Save the directories and masks to the settings.
CSettings & a_roSettings = CSettings::GetSettings();
a_roSettings.c_oDirectories.clear();
int i = 0;
for( i = 0; i<c_oSearchDirectory.GetCount(); ++i )
{
CString a_sTemp;
c_oSearchDirectory.GetLBText( i, a_sTemp );
a_roSettings.c_oDirectories.push_back( (LPCTSTR)a_sTemp );
}
a_roSettings.c_oFileMasks.clear();
for( i = 0; i<c_oFileMask.GetCount(); ++i )
{
CString a_sTemp;
c_oFileMask.GetLBText( i, a_sTemp );
a_roSettings.c_oFileMasks.push_back( (LPCTSTR)a_sTemp );
}
CString a_sTemp;
c_oIncludeDirs.GetWindowText( a_sTemp );
a_roSettings.c_sIncludeDirs = a_sTemp;
a_roSettings.c_bRecurse = c_oSubDirectories.GetCheck() != 0;
}
//
// ------------------------------------------------------------------
//
void CDirectorySearchPage::OnBrowseDirectory()
{
// Let the user browse for a folder.
TCHAR a_szDisplayName[MAX_PATH] = {0};
BROWSEINFO a_stBrowseInfo;
memset( &a_stBrowseInfo, 0, sizeof( a_stBrowseInfo ) );
a_stBrowseInfo.hwndOwner = NULL;
a_stBrowseInfo.pszDisplayName = a_szDisplayName;
CString a_sTitle( (LPCTSTR)IDS_STR_DIRECTORY );
a_stBrowseInfo.lpszTitle = a_sTitle;
a_stBrowseInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST a_poItemIDList = SHBrowseForFolder( &a_stBrowseInfo );
if( a_poItemIDList )
{
IMalloc * a_poMalloc = NULL;
SHGetMalloc( &a_poMalloc );
TCHAR a_szPath[MAX_PATH] = {0};
SHGetPathFromIDList( a_poItemIDList, a_szPath );
c_oSearchDirectory.SetWindowText( a_szPath );
a_poMalloc->Free( a_poItemIDList );
a_poMalloc->Release();
}
}
//
// ------------------------------------------------------------------
//