//========= 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 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 &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 m_Data; }; bool ReadJpeg( IFileSystem *pFileSystem, const char *pFilename, CUtlVector &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 &srcData, int srcWidth, int srcHeight, CUtlVector &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 data; int width, height; if ( !ReadJpeg( pFileSystem, filename, data, width, height, pPathID ) ) return NULL; CUtlVector 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 &files ) { // Build a dictionary with all the .jpeg files. CUtlDict 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 &files ) { CUtlDict 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 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 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 );