hl2_src-leak-2017/src/utils/FileSystemOpenDialog/FileSystemOpenDlg.cpp

998 lines
24 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// FileSystemOpenDlg.cpp : implementation file
//
#include "stdafx.h"
#include "FileSystemOpenDlg.h"
#include "jpeglib/jpeglib.h"
#include "utldict.h"
#include "resource.h"
#include "ifilesystemopendialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CFileInfo::CFileInfo()
{
m_pBitmap = NULL;
}
CFileInfo::~CFileInfo()
{
}
/////////////////////////////////////////////////////////////////////////////
// This caches the thumbnail bitmaps we generate to speed up browsing.
/////////////////////////////////////////////////////////////////////////////
class CBitmapCache
{
public:
CBitmapCache()
{
m_CurMemoryUsage = 0;
m_MaxMemoryUsage = 1024 * 1024 * 6;
}
void AddToCache( CBitmap *pBitmap, const char *pName, int memoryUsage, bool bLock )
{
Assert( m_Bitmaps.Find( pName ) == -1 );
m_CurMemoryUsage += memoryUsage;
CBitmapCacheEntry newEntry;
newEntry.m_pBitmap = pBitmap;
newEntry.m_MemoryUsage = memoryUsage;
newEntry.m_bLocked = bLock;
m_Bitmaps.Insert( pName, newEntry );
EnsureMemoryUsage();
}
CBitmap* Find( const char *pName )
{
int i = m_Bitmaps.Find( pName );
if ( i == -1 )
return NULL;
else
return m_Bitmaps[i].m_pBitmap;
}
void UnlockAll()
{
for ( int i=m_Bitmaps.First(); i != m_Bitmaps.InvalidIndex(); i=m_Bitmaps.Next( i ) )
{
m_Bitmaps[i].m_bLocked = false;
}
}
private:
void EnsureMemoryUsage()
{
while ( m_CurMemoryUsage > m_MaxMemoryUsage )
{
// Free something.
bool bFreed = false;
for ( int i=m_Bitmaps.First(); i != m_Bitmaps.InvalidIndex(); i=m_Bitmaps.Next( i ) )
{
if ( !m_Bitmaps[i].m_bLocked )
{
delete m_Bitmaps[i].m_pBitmap;
m_CurMemoryUsage -= m_Bitmaps[i].m_MemoryUsage;
m_Bitmaps.RemoveAt( i );
break;
}
}
// Nothing left to free?
if ( !bFreed )
return;
}
}
private:
class CBitmapCacheEntry
{
public:
CBitmap *m_pBitmap;
int m_MemoryUsage;
bool m_bLocked;
};
CUtlDict<CBitmapCacheEntry,int> m_Bitmaps;
int m_CurMemoryUsage;
int m_MaxMemoryUsage;
};
CBitmapCache g_BitmapCache;
/////////////////////////////////////////////////////////////////////////////
// CFileSystemOpenDlg dialog
CFileSystemOpenDlg::CFileSystemOpenDlg(CreateInterfaceFn factory, CWnd* pParent )
: CDialog(CFileSystemOpenDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CFileSystemOpenDlg)
//}}AFX_DATA_INIT
m_pFileSystem = (IFileSystem*)factory( FILESYSTEM_INTERFACE_VERSION, NULL );
if ( !m_pFileSystem )
{
Error( "Unable to connect to %s!\n", FILESYSTEM_INTERFACE_VERSION );
}
m_bFilterMdlAndJpgFiles = false;
}
void CFileSystemOpenDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFileSystemOpenDlg)
DDX_Control(pDX, IDC_FILENAME_LABEL, m_FilenameLabel);
DDX_Control(pDX, IDC_FILENAME, m_FilenameControl);
DDX_Control(pDX, IDC_LOOKIN, m_LookInLabel);
DDX_Control(pDX, IDC_FILE_LIST, m_FileList);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFileSystemOpenDlg, CDialog)
//{{AFX_MSG_MAP(CFileSystemOpenDlg)
ON_WM_CREATE()
ON_WM_SIZE()
ON_NOTIFY(NM_DBLCLK, IDC_FILE_LIST, OnDblclkFileList)
ON_BN_CLICKED(IDC_UP_BUTTON, OnUpButton)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_FILE_LIST, OnItemchangedFileList)
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFileSystemOpenDlg message handlers
void CFileSystemOpenDlg::OnOK()
{
// Make sure it's a valid filename.
CString testFilename;
m_FilenameControl.GetWindowText( testFilename );
CString fullFilename = m_CurrentDir + "\\" + testFilename;
if ( m_pFileSystem->IsDirectory( fullFilename, GetPathID() ) )
{
m_CurrentDir = fullFilename;
PopulateListControl();
}
else if ( m_pFileSystem->FileExists( fullFilename, GetPathID() ) )
{
m_Filename = fullFilename;
// Translate .jpg to .mdl?
if ( m_bFilterMdlAndJpgFiles )
{
char tempFilename[MAX_PATH];
V_strcpy_safe( tempFilename, fullFilename );
char *pPos = strrchr( tempFilename, '.' );
if ( pPos )
{
if ( Q_stricmp( pPos, ".jpeg" ) == 0 || Q_stricmp( pPos, ".jpg" ) == 0 )
{
pPos[0] = 0;
V_strcat_safe( tempFilename, ".mdl" );
m_Filename = tempFilename;
}
}
}
EndDialog( IDOK );
}
else
{
// No file or directory here.
CString str;
str.FormatMessage( "File %1!s! doesn't exist.", (const char*)fullFilename );
AfxMessageBox( str, MB_OK );
}
}
void CFileSystemOpenDlg::SetInitialDir( const char *pDir, const char *pPathID )
{
m_CurrentDir = pDir;
if ( pPathID )
m_PathIDString = pPathID;
else
m_PathIDString = "";
}
CString CFileSystemOpenDlg::GetFilename() const
{
return m_Filename;
}
BOOL CFileSystemOpenDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Setup our anchor list.
AddAnchor( IDC_FILE_LIST, 2, 2 );
AddAnchor( IDC_FILE_LIST, 3, 3 );
AddAnchor( IDC_FILENAME, 1, 3 );
AddAnchor( IDC_FILENAME, 3, 3 );
AddAnchor( IDC_FILENAME, 2, 2 );
AddAnchor( IDC_FILENAME_LABEL, 0, 0 );
AddAnchor( IDC_FILENAME_LABEL, 2, 0 );
AddAnchor( IDC_FILENAME_LABEL, 1, 3 );
AddAnchor( IDC_FILENAME_LABEL, 3, 3 );
AddAnchor( IDOK, 0, 2 );
AddAnchor( IDOK, 2, 2 );
AddAnchor( IDOK, 1, 3 );
AddAnchor( IDOK, 3, 3 );
AddAnchor( IDCANCEL, 0, 2 );
AddAnchor( IDCANCEL, 2, 2 );
AddAnchor( IDCANCEL, 1, 3 );
AddAnchor( IDCANCEL, 3, 3 );
AddAnchor( IDC_LOOKIN, 2, 2 );
AddAnchor( IDC_UP_BUTTON, 0, 2 );
AddAnchor( IDC_UP_BUTTON, 2, 2 );
// Setup our image list.
m_ImageList.Create( PREVIEW_IMAGE_SIZE, PREVIEW_IMAGE_SIZE, ILC_COLOR32, 0, 512 );
m_BitmapFolder.LoadBitmap( IDB_LABEL_FOLDER );
m_iLabel_Folder = m_ImageList.Add( &m_BitmapFolder, (CBitmap*)NULL );
m_BitmapMdl.LoadBitmap( IDB_LABEL_MDL );
m_iLabel_Mdl = m_ImageList.Add( &m_BitmapMdl, (CBitmap*)NULL );
m_BitmapFile.LoadBitmap( IDB_LABEL_FILE );
m_iLabel_File = m_ImageList.Add( &m_BitmapFile, (CBitmap*)NULL );
m_FileList.SetImageList( &m_ImageList, LVSIL_NORMAL );
// Populate the list with the contents of our current directory.
PopulateListControl();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CFileSystemOpenDlg::GetEntries( const char *pMask, CUtlVector<CString> &entries, GetEntriesMode_t mode )
{
CString searchStr = m_CurrentDir + "\\" + pMask;
// Workaround Steam bug.
if ( searchStr == ".\\*.*" )
searchStr = "*.*";
FileFindHandle_t handle;
const char *pFile = m_pFileSystem->FindFirst( searchStr, &handle );
while ( pFile )
{
bool bIsDir = m_pFileSystem->FindIsDirectory( handle );
if ( (mode == GETENTRIES_DIRECTORIES_ONLY && bIsDir) || (mode == GETENTRIES_FILES_ONLY && !bIsDir) )
{
entries.AddToTail( pFile );
}
pFile = m_pFileSystem->FindNext( handle );
}
m_pFileSystem->FindClose( handle );
}
class CJpegSourceMgr : public jpeg_source_mgr
{
public:
CJpegSourceMgr()
{
this->init_source = &CJpegSourceMgr::imp_init_source;
this->fill_input_buffer = &CJpegSourceMgr::imp_fill_input_buffer;
this->skip_input_data = &CJpegSourceMgr::imp_skip_input_data;
this->resync_to_restart = &CJpegSourceMgr::imp_resync_to_restart;
this->term_source = &CJpegSourceMgr::imp_term_source;
this->next_input_byte = 0;
this->bytes_in_buffer = 0;
}
bool Init( IFileSystem *pFileSystem, FileHandle_t fp )
{
m_Data.SetSize( pFileSystem->Size( fp ) );
return pFileSystem->Read( m_Data.Base(), m_Data.Count(), fp ) == m_Data.Count();
}
static void imp_init_source(j_decompress_ptr cinfo)
{
}
static boolean imp_fill_input_buffer(j_decompress_ptr cinfo)
{
Assert( false ); // They should never need to call these functions since we give them all the data up front.
return 0;
}
static void imp_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
AssertOnce( false ); // They should never need to call these functions since we give them all the data up front.
}
static boolean imp_resync_to_restart(j_decompress_ptr cinfo, int desired)
{
Assert( false ); // They should never need to call these functions since we give them all the data up front.
return false;
}
static void imp_term_source(j_decompress_ptr cinfo)
{
}
static void error_exit( j_common_ptr cptr )
{
CJpegSourceMgr *pInstance = (CJpegSourceMgr*)cptr->client_data;
longjmp( pInstance->m_JmpBuf, 1 );
}
public:
jmp_buf m_JmpBuf;
CUtlVector<char> m_Data;
};
bool ReadJpeg( IFileSystem *pFileSystem, const char *pFilename, CUtlVector<unsigned char> &buf, int &width, int &height, const char *pPathID )
{
width = height = 0;
// Read the data.
FileHandle_t fp = pFileSystem->Open( pFilename, "rb", pPathID );
if ( fp == FILESYSTEM_INVALID_HANDLE )
return false;
CJpegSourceMgr sourceMgr;
bool bRet = sourceMgr.Init( pFileSystem, fp );
pFileSystem->Close( fp );
if ( !bRet )
return false;
sourceMgr.bytes_in_buffer = sourceMgr.m_Data.Count();
sourceMgr.next_input_byte = (unsigned char*)sourceMgr.m_Data.Base();
// Load the jpeg.
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr jerr;
memset( &jpegInfo, 0, sizeof( jpegInfo ) );
jpegInfo.client_data = &sourceMgr;
jpegInfo.err = jpeg_std_error(&jerr);
jerr.error_exit = &CJpegSourceMgr::error_exit;
jpeg_create_decompress(&jpegInfo);
jpegInfo.src = &sourceMgr;
if ( setjmp( sourceMgr.m_JmpBuf ) == 1 )
{
jpeg_destroy_decompress(&jpegInfo);
return false;
}
if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
{
return false;
}
// start the decompress with the jpeg engine.
if (jpeg_start_decompress(&jpegInfo) != TRUE || jpegInfo.output_components != 3)
{
jpeg_destroy_decompress(&jpegInfo);
return false;
}
// now that we've started the decompress with the jpeg lib, we have the attributes of the
// image ready to be read out of the decompress struct.
int row_stride = jpegInfo.output_width * jpegInfo.output_components;
int mem_required = jpegInfo.image_height * jpegInfo.image_width * jpegInfo.output_components;
JSAMPROW row_pointer[1];
int cur_row = 0;
width = jpegInfo.output_width;
height = jpegInfo.output_height;
// allocate the memory to read the image data into.
buf.SetSize( mem_required );
// read in all the scan lines of the image into our image data buffer.
bool working = true;
while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
{
row_pointer[0] = &(buf[cur_row * row_stride]);
if (jpeg_read_scanlines(&jpegInfo, row_pointer, 1) != TRUE)
{
working = false;
}
++cur_row;
}
if (!working)
{
jpeg_destroy_decompress(&jpegInfo);
return false;
}
jpeg_finish_decompress(&jpegInfo);
return true;
}
void DownsampleRGBToRGBAImage(
CUtlVector<unsigned char> &srcData,
int srcWidth,
int srcHeight,
CUtlVector<unsigned char> &destData,
int destWidth,
int destHeight )
{
int srcPixelSize = 3;
int destPixelSize = 4;
destData.SetSize( destWidth * destHeight * destPixelSize );
memset( destData.Base(), 0xFF, destWidth * destHeight * destPixelSize );
// This preserves the aspect ratio of the image.
int scaledDestWidth = destWidth;
int scaledDestHeight = destHeight;
int destOffsetX = 0, destOffsetY = 0;
if ( srcWidth > srcHeight )
{
scaledDestHeight = (srcHeight * destHeight) / srcWidth;
destOffsetY = (destHeight - scaledDestHeight) / 2;
}
else if ( srcHeight > srcWidth )
{
scaledDestWidth = (srcWidth * destWidth) / srcHeight;
destOffsetX = (destWidth - scaledDestWidth) / 2;
}
for ( int destY=0; destY < scaledDestHeight; destY++ )
{
unsigned char *pDestLine = &destData[(destY + destOffsetY) * destWidth * destPixelSize + (destOffsetX * destPixelSize)];
unsigned char *pDestPos = pDestLine;
float destYPercent = (float)destY / (scaledDestHeight-1);
int srcY = (int)( destYPercent * (srcHeight-1) );
for ( int destX=0; destX < scaledDestWidth; destX++ )
{
float destXPercent = (float)destX / (scaledDestWidth-1);
int srcX = (int)( destXPercent * (srcWidth-1) );
unsigned char *pSrcPos = &srcData[(srcY * srcWidth + srcX) * srcPixelSize];
pDestPos[0] = pSrcPos[2];
pDestPos[1] = pSrcPos[1];
pDestPos[2] = pSrcPos[0];
pDestPos[3] = 255;
pDestPos += destPixelSize;
}
}
}
CBitmap* SetupJpegLabel( IFileSystem *pFileSystem, CString filename, int labelSize, const char *pPathID )
{
CBitmap *pBitmap = g_BitmapCache.Find( filename );
if ( pBitmap )
return pBitmap;
CUtlVector<unsigned char> data;
int width, height;
if ( !ReadJpeg( pFileSystem, filename, data, width, height, pPathID ) )
return NULL;
CUtlVector<unsigned char> downsampled;
DownsampleRGBToRGBAImage( data, width, height, downsampled, labelSize, labelSize );
pBitmap = new CBitmap;
if ( pBitmap->CreateBitmap( labelSize, labelSize, 1, 32, downsampled.Base() ) )
{
g_BitmapCache.AddToCache( pBitmap, filename, downsampled.Count(), true );
return pBitmap;
}
else
{
delete pBitmap;
return NULL;
}
}
int CFileSystemOpenDlg::SetupLabelImage( CFileInfo *pInfo, CString name, bool bIsDir )
{
if ( bIsDir )
return m_iLabel_Folder;
CString extension = name.Right( 4 );
extension.MakeLower();
if ( extension == ".jpg" || extension == ".jpeg" )
{
pInfo->m_pBitmap = SetupJpegLabel( m_pFileSystem, m_CurrentDir + "\\" + name, PREVIEW_IMAGE_SIZE, GetPathID() );
if ( pInfo->m_pBitmap )
return m_ImageList.Add( pInfo->m_pBitmap, (CBitmap*)NULL );
else
return m_iLabel_File;
}
else
{
return (extension == ".mdl") ? m_iLabel_Mdl : m_iLabel_File;
}
}
void FilterMdlAndJpgFiles( CUtlVector<CString> &files )
{
// Build a dictionary with all the .jpeg files.
CUtlDict<int,int> jpgFiles;
for ( int i=0; i < files.Count(); i++ )
{
CString extension = files[i].Right( 4 );
extension.MakeLower();
if ( extension == ".jpg" || extension == ".jpeg" )
{
CString base = files[i].Left( files[i].GetLength() - 4 );
jpgFiles.Insert( base, 1 );
}
}
// Now look for all mdls and remove them if they have a jpg.
for ( int i=0; i < files.Count(); i++ )
{
CString extension = files[i].Right( 4 );
extension.MakeLower();
if ( extension == ".mdl" )
{
CString base = files[i].Left( files[i].GetLength() - 4 );
if ( jpgFiles.Find( base ) != -1 )
{
files.Remove( i );
--i;
}
}
}
}
int CALLBACK FileListSortCallback( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
{
CFileSystemOpenDlg *pDlg = (CFileSystemOpenDlg*)lParamSort;
CFileInfo *pInfo1 = &pDlg->m_FileInfos[lParam1];
CFileInfo *pInfo2 = &pDlg->m_FileInfos[lParam2];
if ( pInfo1->m_bIsDir != pInfo2->m_bIsDir )
return pInfo1->m_bIsDir ? -1 : 1;
return Q_stricmp( pInfo1->m_Name, pInfo2->m_Name );
}
void RemoveDuplicates( CUtlVector<CString> &files )
{
CUtlDict<int,int> uniqueFilenames;
for ( int i=0; i < files.Count(); i++ )
{
int iPreviousIndex = uniqueFilenames.Find( files[i] );
if ( iPreviousIndex == -1 )
{
uniqueFilenames.Insert( files[i], i );
}
else
{
files.Remove( i );
--i;
}
}
}
void CFileSystemOpenDlg::PopulateListControl()
{
m_FileList.DeleteAllItems();
g_BitmapCache.UnlockAll();
m_LookInLabel.SetWindowText( CString( "[ROOT]\\" ) + m_CurrentDir );
int iItem = 0;
// First add directories at the top.
CUtlVector<CString> directories;
GetEntries( "*.*", directories, GETENTRIES_DIRECTORIES_ONLY );
RemoveDuplicates( directories );
for ( int i=0; i < directories.Count(); i++ )
{
if ( directories[i] == "." || directories[i] == ".." )
continue;
LVITEM item;
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
item.iItem = iItem++;
item.iSubItem = 0;
item.pszText = directories[i].GetBuffer(0);
item.lParam = m_FileInfos.AddToTail();
m_FileInfos[item.lParam].m_bIsDir = true;
m_FileInfos[item.lParam].m_Name = directories[i];
item.iImage = SetupLabelImage( &m_FileInfos[item.lParam], directories[i], true );
m_FileList.InsertItem( &item );
}
CUtlVector<CString> files;
for ( int iMask=0; iMask < m_FileMasks.Count(); iMask++ )
{
GetEntries( m_FileMasks[iMask], files, GETENTRIES_FILES_ONLY );
}
RemoveDuplicates( files );
if ( m_bFilterMdlAndJpgFiles )
FilterMdlAndJpgFiles( files );
for ( int i=0; i < files.Count(); i++ )
{
LVITEM item;
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
item.iItem = iItem++;
item.iSubItem = 0;
item.iImage = m_iLabel_Mdl;
item.pszText = files[i].GetBuffer(0);
item.lParam = m_FileInfos.AddToTail();
m_FileInfos[item.lParam].m_bIsDir = false;
m_FileInfos[item.lParam].m_Name = files[i];
item.iImage = SetupLabelImage( &m_FileInfos[item.lParam], files[i], false );
m_FileList.InsertItem( &item );
}
m_FileList.SortItems( FileListSortCallback, (DWORD)this );
}
void CFileSystemOpenDlg::AddFileMask( const char *pMask )
{
m_FileMasks.AddToTail( pMask );
}
BOOL CFileSystemOpenDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
return CDialog::Create(IDD, pParentWnd);
}
int CFileSystemOpenDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
LONG& GetSideCoord( RECT &rect, int iSide )
{
if ( iSide == 0 )
return rect.left;
else if ( iSide == 1 )
return rect.top;
else if ( iSide == 2 )
return rect.right;
else
return rect.bottom;
}
LONG GetSideScreenCoord( CWnd *pWnd, int iSide )
{
RECT rect;
pWnd->GetWindowRect( &rect );
return GetSideCoord( rect, iSide );
}
void CFileSystemOpenDlg::ProcessAnchor( CWindowAnchor *pAnchor )
{
RECT rect, parentRect;
GetWindowRect( &parentRect );
pAnchor->m_pWnd->GetWindowRect( &rect );
GetSideCoord( rect, pAnchor->m_Side ) = GetSideCoord( parentRect, pAnchor->m_ParentSide ) + pAnchor->m_OriginalDist;
ScreenToClient( &rect );
pAnchor->m_pWnd->MoveWindow( &rect );
}
void CFileSystemOpenDlg::AddAnchor( int iDlgItem, int iSide, int iParentSide )
{
CWnd *pItem = GetDlgItem( iDlgItem );
if ( !pItem )
return;
CWindowAnchor *pAnchor = &m_Anchors[m_Anchors.AddToTail()];
pAnchor->m_pWnd = pItem;
pAnchor->m_Side = iSide;
pAnchor->m_ParentSide = iParentSide;
pAnchor->m_OriginalDist = GetSideScreenCoord( pItem, iSide ) - GetSideScreenCoord( this, iParentSide );
}
void CFileSystemOpenDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
for ( int i=0; i < m_Anchors.Count(); i++ )
ProcessAnchor( &m_Anchors[i] );
if ( m_FileList.GetSafeHwnd() )
PopulateListControl();
}
void CFileSystemOpenDlg::OnDblclkFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
/*int iSelected = m_FileList.GetNextItem( -1, LVNI_SELECTED );
if ( iSelected != -1 )
{
DWORD iItem = m_FileList.GetItemData( iSelected );
if ( iItem < (DWORD)m_FileInfos.Count() )
{
CFileInfo *pInfo = &m_FileInfos[iItem];
if ( pInfo->m_bIsDir )
{
m_CurrentDir += "\\" + m_FileInfos[iItem].m_Name;
PopulateListControl();
}
else
{
m_Filename = m_CurrentDir + "\\" + m_FileInfos[iItem].m_Name;
EndDialog( IDOK );
}
}
else
{
Assert( false );
}
}*/
OnOK();
*pResult = 0;
}
void CFileSystemOpenDlg::OnUpButton()
{
char str[MAX_PATH];
V_strcpy_safe( str, m_CurrentDir );
Q_StripLastDir( str, sizeof( str ) );
if ( str[0] == 0 )
V_strcpy_safe( str, "." );
if ( str[strlen(str)-1] == '\\' || str[strlen(str)-1] == '/' )
str[strlen(str)-1] = 0;
m_CurrentDir = str;
PopulateListControl();
}
void CFileSystemOpenDlg::OnItemchangedFileList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
DWORD iItem = m_FileList.GetItemData( pNMListView->iItem );
if ( iItem < (DWORD)m_FileInfos.Count() )
{
CFileInfo *pInfo = &m_FileInfos[iItem];
if ( (pNMListView->uChanged & LVIF_STATE) &&
(pNMListView->uNewState & LVIS_SELECTED) )
{
m_FilenameControl.SetWindowText( pInfo->m_Name );
}
}
*pResult = 0;
}
void CFileSystemOpenDlg::SetFilterMdlAndJpgFiles( bool bFilter )
{
m_bFilterMdlAndJpgFiles = bFilter;
}
const char* CFileSystemOpenDlg::GetPathID()
{
if ( m_PathIDString == "" )
return NULL;
else
return (const char*)m_PathIDString;
}
// ------------------------------------------------------------------------------------------------ //
// Implementation of IFileSystemOpenDialog.
// ------------------------------------------------------------------------------------------------ //
// IFileSystemOpenDialog implementation.
class CFileSystemOpenDialogWrapper : public IFileSystemOpenDialog
{
public:
CFileSystemOpenDialogWrapper()
{
m_pDialog = 0;
m_bLastModalWasWindowsDialog = false;
}
virtual void Release()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
delete m_pDialog;
delete this;
}
// You must call this first to set the hwnd.
virtual void Init( CreateInterfaceFn factory, void *parentHwnd )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( !m_pDialog );
m_hParentWnd = (HWND)parentHwnd;
m_pDialog = new CFileSystemOpenDlg( factory, CWnd::FromHandle( m_hParentWnd ) );
}
virtual void AddFileMask( const char *pMask )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
m_pDialog->AddFileMask( pMask );
}
virtual void SetInitialDir( const char *pDir, const char *pPathID )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
m_pDialog->SetInitialDir( pDir, pPathID );
}
virtual void SetFilterMdlAndJpgFiles( bool bFilter )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
m_pDialog->SetFilterMdlAndJpgFiles( bFilter );
}
virtual void GetFilename( char *pOut, int outLen ) const
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
if ( m_bLastModalWasWindowsDialog )
{
Q_strncpy( pOut, m_RelativeFilename, outLen );
}
else
{
Q_strncpy( pOut, m_pDialog->GetFilename(), outLen );
}
}
virtual bool DoModal()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
m_bLastModalWasWindowsDialog = false;
return m_pDialog->DoModal() == IDOK;
}
virtual bool DoModal_WindowsDialog()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
Assert( m_pDialog );
m_bLastModalWasWindowsDialog = true;
// Get the full filename, then make sure it's a relative path.
char defExt[MAX_PATH] = {0};
if ( m_pDialog->m_FileMasks.Count() > 0 )
{
CString ext = m_pDialog->m_FileMasks[m_pDialog->m_FileMasks.Count()-1].Right( 4 );
const char *pStr = ext;
if ( pStr[0] == '.' )
V_strcpy_safe( defExt, pStr+1 );
}
char pFileNameBuf[MAX_PATH];
const char *pFileName = m_pDialog->m_pFileSystem->RelativePathToFullPath( m_pDialog->m_CurrentDir, m_pDialog->m_PathIDString, pFileNameBuf, MAX_PATH );
V_strcat_safe( pFileNameBuf, "\\" );
// Build the list of file filters.
char filters[1024];
if ( m_pDialog->m_FileMasks.Count() == 0 )
{
V_strcpy_safe( filters, "All Files (*.*)|*.*||" );
}
else
{
filters[0] = 0;
for ( int i=0; i < m_pDialog->m_FileMasks.Count(); i++ )
{
if ( i > 0 )
V_strcat_safe( filters, "|" );
V_strcat_safe( filters, m_pDialog->m_FileMasks[i] );
V_strcat_safe( filters, "|" );
V_strcat_safe( filters, m_pDialog->m_FileMasks[i] );
if ( pFileName )
{
V_strcat_safe( pFileNameBuf, m_pDialog->m_FileMasks[i] );
V_strcat_safe( pFileNameBuf, ";" );
}
}
V_strcat_safe( filters, "||" );
}
CFileDialog dlg(
true, // open dialog?
defExt[0]==0 ? NULL : defExt, // default file extension
pFileName, // initial filename
OFN_ENABLESIZING, // flags
filters,
CWnd::FromHandle( m_hParentWnd ) );
while ( dlg.DoModal() == IDOK )
{
// Make sure we can make this into a relative path.
if ( m_pDialog->m_pFileSystem->FullPathToRelativePath( dlg.GetPathName(), m_RelativeFilename, sizeof( m_RelativeFilename ) ) )
{
// Replace .jpg or .jpeg extension with .mdl?
char *pEnd = m_RelativeFilename;
while ( Q_stristr( pEnd+1, ".jpeg" ) || Q_stristr( pEnd+1, ".jpg" ) )
pEnd = max( Q_stristr( pEnd, ".jpeg" ), Q_stristr( pEnd, ".jpg" ) );
if ( pEnd && pEnd != m_RelativeFilename )
Q_strncpy( pEnd, ".mdl", sizeof( m_RelativeFilename ) - (pEnd - m_RelativeFilename) );
return true;
}
else
{
AfxMessageBox( IDS_NO_RELATIVE_PATH );
}
}
return false;
}
private:
CFileSystemOpenDlg *m_pDialog;
HWND m_hParentWnd;
char m_RelativeFilename[MAX_PATH];
bool m_bLastModalWasWindowsDialog;
};
EXPOSE_INTERFACE( CFileSystemOpenDialogWrapper, IFileSystemOpenDialog, FILESYSTEMOPENDIALOG_VERSION );