Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1064 lines
26 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. // FileSystemOpenDlg.cpp : implementation file
  9. //
  10. #include "stdafx.h"
  11. #include "FileSystemOpenDlg.h"
  12. #include "jpeglib/jpeglib.h"
  13. #include "utldict.h"
  14. #include "resource.h"
  15. #include "tier2/tier2.h"
  16. #include "ifilesystemopendialog.h"
  17. #include "smartptr.h"
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. CFileInfo::CFileInfo()
  24. {
  25. m_pBitmap = NULL;
  26. }
  27. CFileInfo::~CFileInfo()
  28. {
  29. }
  30. /////////////////////////////////////////////////////////////////////////////
  31. // This caches the thumbnail bitmaps we generate to speed up browsing.
  32. /////////////////////////////////////////////////////////////////////////////
  33. class CBitmapCache
  34. {
  35. public:
  36. CBitmapCache()
  37. {
  38. m_CurMemoryUsage = 0;
  39. m_MaxMemoryUsage = 1024 * 1024 * 6;
  40. }
  41. void AddToCache( CBitmap *pBitmap, const char *pName, int memoryUsage, bool bLock )
  42. {
  43. Assert( m_Bitmaps.Find( pName ) == -1 );
  44. m_CurMemoryUsage += memoryUsage;
  45. CBitmapCacheEntry newEntry;
  46. newEntry.m_pBitmap = pBitmap;
  47. newEntry.m_MemoryUsage = memoryUsage;
  48. newEntry.m_bLocked = bLock;
  49. m_Bitmaps.Insert( pName, newEntry );
  50. EnsureMemoryUsage();
  51. }
  52. CBitmap* Find( const char *pName )
  53. {
  54. int i = m_Bitmaps.Find( pName );
  55. if ( i == -1 )
  56. return NULL;
  57. else
  58. return m_Bitmaps[i].m_pBitmap;
  59. }
  60. void UnlockAll()
  61. {
  62. for ( int i=m_Bitmaps.First(); i != m_Bitmaps.InvalidIndex(); i=m_Bitmaps.Next( i ) )
  63. {
  64. m_Bitmaps[i].m_bLocked = false;
  65. }
  66. }
  67. private:
  68. void EnsureMemoryUsage()
  69. {
  70. while ( m_CurMemoryUsage > m_MaxMemoryUsage )
  71. {
  72. // Free something.
  73. bool bFreed = false;
  74. for ( int i=m_Bitmaps.First(); i != m_Bitmaps.InvalidIndex(); i=m_Bitmaps.Next( i ) )
  75. {
  76. if ( !m_Bitmaps[i].m_bLocked )
  77. {
  78. delete m_Bitmaps[i].m_pBitmap;
  79. m_CurMemoryUsage -= m_Bitmaps[i].m_MemoryUsage;
  80. m_Bitmaps.RemoveAt( i );
  81. break;
  82. }
  83. }
  84. // Nothing left to free?
  85. if ( !bFreed )
  86. return;
  87. }
  88. }
  89. private:
  90. class CBitmapCacheEntry
  91. {
  92. public:
  93. CBitmap *m_pBitmap;
  94. int m_MemoryUsage;
  95. bool m_bLocked;
  96. };
  97. CUtlDict<CBitmapCacheEntry,int> m_Bitmaps;
  98. int m_CurMemoryUsage;
  99. int m_MaxMemoryUsage;
  100. };
  101. CBitmapCache g_BitmapCache;
  102. /////////////////////////////////////////////////////////////////////////////
  103. // CFileSystemOpenDlg dialog
  104. CFileSystemOpenDlg::CFileSystemOpenDlg(CreateInterfaceFn factory, CWnd* pParent )
  105. : CDialog(CFileSystemOpenDlg::IDD, pParent)
  106. {
  107. //{{AFX_DATA_INIT(CFileSystemOpenDlg)
  108. //}}AFX_DATA_INIT
  109. m_pFileSystem = (IFileSystem*)factory( FILESYSTEM_INTERFACE_VERSION, NULL );
  110. if ( !m_pFileSystem )
  111. {
  112. Error( "Unable to connect to %s!\n", FILESYSTEM_INTERFACE_VERSION );
  113. }
  114. m_bFilterMdlAndJpgFiles = false;
  115. }
  116. void CFileSystemOpenDlg::DoDataExchange(CDataExchange* pDX)
  117. {
  118. CDialog::DoDataExchange(pDX);
  119. //{{AFX_DATA_MAP(CFileSystemOpenDlg)
  120. DDX_Control(pDX, IDC_FILENAME_LABEL, m_FilenameLabel);
  121. DDX_Control(pDX, IDC_FILENAME, m_FilenameControl);
  122. DDX_Control(pDX, IDC_LOOKIN, m_LookInLabel);
  123. DDX_Control(pDX, IDC_FILE_LIST, m_FileList);
  124. //}}AFX_DATA_MAP
  125. }
  126. BEGIN_MESSAGE_MAP(CFileSystemOpenDlg, CDialog)
  127. //{{AFX_MSG_MAP(CFileSystemOpenDlg)
  128. ON_WM_CREATE()
  129. ON_WM_SIZE()
  130. ON_NOTIFY(NM_DBLCLK, IDC_FILE_LIST, OnDblclkFileList)
  131. ON_BN_CLICKED(IDC_UP_BUTTON, OnUpButton)
  132. ON_NOTIFY(LVN_ITEMCHANGED, IDC_FILE_LIST, OnItemchangedFileList)
  133. ON_WM_KEYDOWN()
  134. //}}AFX_MSG_MAP
  135. END_MESSAGE_MAP()
  136. /////////////////////////////////////////////////////////////////////////////
  137. // CFileSystemOpenDlg message handlers
  138. void CFileSystemOpenDlg::OnOK()
  139. {
  140. // Make sure it's a valid filename.
  141. CString testFilename;
  142. m_FilenameControl.GetWindowText( testFilename );
  143. CString fullFilename = m_CurrentDir + "\\" + testFilename;
  144. if ( m_pFileSystem->IsDirectory( fullFilename, GetPathID() ) )
  145. {
  146. m_CurrentDir = fullFilename;
  147. PopulateListControl();
  148. }
  149. else if ( m_pFileSystem->FileExists( fullFilename, GetPathID() ) )
  150. {
  151. m_Filename = fullFilename;
  152. // Translate .jpg to .mdl?
  153. if ( m_bFilterMdlAndJpgFiles )
  154. {
  155. char tempFilename[MAX_PATH];
  156. Q_strncpy( tempFilename, fullFilename, sizeof( tempFilename ) );
  157. char *pPos = strrchr( tempFilename, '.' );
  158. if ( pPos )
  159. {
  160. if ( Q_stricmp( pPos, ".jpeg" ) == 0 || Q_stricmp( pPos, ".jpg" ) == 0 )
  161. {
  162. Q_strncpy( pPos, ".mdl", 5 );
  163. m_Filename = tempFilename;
  164. }
  165. }
  166. }
  167. EndDialog( IDOK );
  168. }
  169. else
  170. {
  171. // No file or directory here.
  172. CString str;
  173. str.FormatMessage( "File %1!s! doesn't exist.", (const char*)fullFilename );
  174. AfxMessageBox( str, MB_OK );
  175. }
  176. }
  177. void CFileSystemOpenDlg::SetInitialDir( const char *pDir, const char *pPathID )
  178. {
  179. m_CurrentDir = pDir;
  180. if ( pPathID )
  181. m_PathIDString = pPathID;
  182. else
  183. m_PathIDString = "";
  184. }
  185. CString CFileSystemOpenDlg::GetFilename() const
  186. {
  187. return m_Filename;
  188. }
  189. BOOL CFileSystemOpenDlg::OnInitDialog()
  190. {
  191. CDialog::OnInitDialog();
  192. // Setup our anchor list.
  193. AddAnchor( IDC_FILE_LIST, 2, 2 );
  194. AddAnchor( IDC_FILE_LIST, 3, 3 );
  195. AddAnchor( IDC_FILENAME, 1, 3 );
  196. AddAnchor( IDC_FILENAME, 3, 3 );
  197. AddAnchor( IDC_FILENAME, 2, 2 );
  198. AddAnchor( IDC_FILENAME_LABEL, 0, 0 );
  199. AddAnchor( IDC_FILENAME_LABEL, 2, 0 );
  200. AddAnchor( IDC_FILENAME_LABEL, 1, 3 );
  201. AddAnchor( IDC_FILENAME_LABEL, 3, 3 );
  202. AddAnchor( IDOK, 0, 2 );
  203. AddAnchor( IDOK, 2, 2 );
  204. AddAnchor( IDOK, 1, 3 );
  205. AddAnchor( IDOK, 3, 3 );
  206. AddAnchor( IDCANCEL, 0, 2 );
  207. AddAnchor( IDCANCEL, 2, 2 );
  208. AddAnchor( IDCANCEL, 1, 3 );
  209. AddAnchor( IDCANCEL, 3, 3 );
  210. AddAnchor( IDC_LOOKIN, 2, 2 );
  211. AddAnchor( IDC_UP_BUTTON, 0, 2 );
  212. AddAnchor( IDC_UP_BUTTON, 2, 2 );
  213. // Setup our image list.
  214. m_ImageList.Create( PREVIEW_IMAGE_SIZE, PREVIEW_IMAGE_SIZE, ILC_COLOR32, 0, 512 );
  215. m_BitmapFolder.LoadBitmap( IDB_LABEL_FOLDER );
  216. m_iLabel_Folder = m_ImageList.Add( &m_BitmapFolder, (CBitmap*)NULL );
  217. m_BitmapMdl.LoadBitmap( IDB_LABEL_MDL );
  218. m_iLabel_Mdl = m_ImageList.Add( &m_BitmapMdl, (CBitmap*)NULL );
  219. m_BitmapFile.LoadBitmap( IDB_LABEL_FILE );
  220. m_iLabel_File = m_ImageList.Add( &m_BitmapFile, (CBitmap*)NULL );
  221. m_FileList.SetImageList( &m_ImageList, LVSIL_NORMAL );
  222. // Populate the list with the contents of our current directory.
  223. PopulateListControl();
  224. return TRUE; // return TRUE unless you set the focus to a control
  225. // EXCEPTION: OCX Property Pages should return FALSE
  226. }
  227. void CFileSystemOpenDlg::GetEntries( const char *pMask, CUtlVector<CString> &entries, GetEntriesMode_t mode )
  228. {
  229. CString searchStr = m_CurrentDir + "\\" + pMask;
  230. // Workaround Steam bug.
  231. if ( searchStr == ".\\*.*" )
  232. searchStr = "*.*";
  233. FileFindHandle_t handle;
  234. const char *pFile = m_pFileSystem->FindFirst( searchStr, &handle );
  235. while ( pFile )
  236. {
  237. bool bIsDir = m_pFileSystem->FindIsDirectory( handle );
  238. if ( (mode == GETENTRIES_DIRECTORIES_ONLY && bIsDir) || (mode == GETENTRIES_FILES_ONLY && !bIsDir) )
  239. {
  240. entries.AddToTail( pFile );
  241. }
  242. pFile = m_pFileSystem->FindNext( handle );
  243. }
  244. m_pFileSystem->FindClose( handle );
  245. }
  246. class CJpegSourceMgr : public jpeg_source_mgr
  247. {
  248. public:
  249. CJpegSourceMgr()
  250. {
  251. this->init_source = &CJpegSourceMgr::imp_init_source;
  252. this->fill_input_buffer = &CJpegSourceMgr::imp_fill_input_buffer;
  253. this->skip_input_data = &CJpegSourceMgr::imp_skip_input_data;
  254. this->resync_to_restart = &CJpegSourceMgr::imp_resync_to_restart;
  255. this->term_source = &CJpegSourceMgr::imp_term_source;
  256. this->next_input_byte = 0;
  257. this->bytes_in_buffer = 0;
  258. }
  259. bool Init( IFileSystem *pFileSystem, FileHandle_t fp )
  260. {
  261. m_Data.SetSize( pFileSystem->Size( fp ) );
  262. return pFileSystem->Read( m_Data.Base(), m_Data.Count(), fp ) == m_Data.Count();
  263. }
  264. static void imp_init_source(j_decompress_ptr cinfo)
  265. {
  266. }
  267. static boolean imp_fill_input_buffer(j_decompress_ptr cinfo)
  268. {
  269. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  270. return 0;
  271. }
  272. static void imp_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
  273. {
  274. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  275. }
  276. static boolean imp_resync_to_restart(j_decompress_ptr cinfo, int desired)
  277. {
  278. Assert( false ); // They should never need to call these functions since we give them all the data up front.
  279. return false;
  280. }
  281. static void imp_term_source(j_decompress_ptr cinfo)
  282. {
  283. }
  284. public:
  285. CUtlVector<char> m_Data;
  286. };
  287. bool ReadJpeg( IFileSystem *pFileSystem, const char *pFilename, CUtlVector<unsigned char> &buf, int &width, int &height, const char *pPathID )
  288. {
  289. // Read the data.
  290. FileHandle_t fp = pFileSystem->Open( pFilename, "rb", pPathID );
  291. if ( fp == FILESYSTEM_INVALID_HANDLE )
  292. return false;
  293. CJpegSourceMgr sourceMgr;
  294. bool bRet = sourceMgr.Init( pFileSystem, fp );
  295. pFileSystem->Close( fp );
  296. if ( !bRet )
  297. return false;
  298. sourceMgr.bytes_in_buffer = sourceMgr.m_Data.Count();
  299. sourceMgr.next_input_byte = (unsigned char*)sourceMgr.m_Data.Base();
  300. // Load the jpeg.
  301. struct jpeg_decompress_struct jpegInfo;
  302. struct jpeg_error_mgr jerr;
  303. memset( &jpegInfo, 0, sizeof( jpegInfo ) );
  304. jpegInfo.err = jpeg_std_error(&jerr);
  305. jpeg_create_decompress(&jpegInfo);
  306. jpegInfo.src = &sourceMgr;
  307. if (jpeg_read_header(&jpegInfo, TRUE) != JPEG_HEADER_OK)
  308. {
  309. return false;
  310. }
  311. // start the decompress with the jpeg engine.
  312. if (jpeg_start_decompress(&jpegInfo) != TRUE || jpegInfo.output_components != 3)
  313. {
  314. jpeg_destroy_decompress(&jpegInfo);
  315. return false;
  316. }
  317. // now that we've started the decompress with the jpeg lib, we have the attributes of the
  318. // image ready to be read out of the decompress struct.
  319. int row_stride = jpegInfo.output_width * jpegInfo.output_components;
  320. int mem_required = jpegInfo.image_height * jpegInfo.image_width * jpegInfo.output_components;
  321. JSAMPROW row_pointer[1];
  322. int cur_row = 0;
  323. width = jpegInfo.output_width;
  324. height = jpegInfo.output_height;
  325. // allocate the memory to read the image data into.
  326. buf.SetSize( mem_required );
  327. // read in all the scan lines of the image into our image data buffer.
  328. bool working = true;
  329. while (working && (jpegInfo.output_scanline < jpegInfo.output_height))
  330. {
  331. row_pointer[0] = &(buf[cur_row * row_stride]);
  332. if (jpeg_read_scanlines(&jpegInfo, row_pointer, 1) != TRUE)
  333. {
  334. working = false;
  335. }
  336. ++cur_row;
  337. }
  338. if (!working)
  339. {
  340. jpeg_destroy_decompress(&jpegInfo);
  341. return false;
  342. }
  343. jpeg_finish_decompress(&jpegInfo);
  344. return true;
  345. }
  346. void DownsampleRGBToRGBAImage(
  347. CUtlVector<unsigned char> &srcData,
  348. int srcWidth,
  349. int srcHeight,
  350. CUtlVector<unsigned char> &destData,
  351. int destWidth,
  352. int destHeight )
  353. {
  354. int srcPixelSize = 3;
  355. int destPixelSize = 4;
  356. destData.SetSize( destWidth * destHeight * destPixelSize );
  357. memset( destData.Base(), 0xFF, destWidth * destHeight * destPixelSize );
  358. // This preserves the aspect ratio of the image.
  359. int scaledDestWidth = destWidth;
  360. int scaledDestHeight = destHeight;
  361. int destOffsetX = 0, destOffsetY = 0;
  362. if ( srcWidth > srcHeight )
  363. {
  364. scaledDestHeight = (srcHeight * destHeight) / srcWidth;
  365. destOffsetY = (destHeight - scaledDestHeight) / 2;
  366. }
  367. else if ( srcHeight > srcWidth )
  368. {
  369. scaledDestWidth = (srcWidth * destWidth) / srcHeight;
  370. destOffsetX = (destWidth - scaledDestWidth) / 2;
  371. }
  372. for ( int destY=0; destY < scaledDestHeight; destY++ )
  373. {
  374. unsigned char *pDestLine = &destData[(destY + destOffsetY) * destWidth * destPixelSize + (destOffsetX * destPixelSize)];
  375. unsigned char *pDestPos = pDestLine;
  376. float destYPercent = (float)destY / (scaledDestHeight-1);
  377. int srcY = (int)( destYPercent * (srcHeight-1) );
  378. for ( int destX=0; destX < scaledDestWidth; destX++ )
  379. {
  380. float destXPercent = (float)destX / (scaledDestWidth-1);
  381. int srcX = (int)( destXPercent * (srcWidth-1) );
  382. unsigned char *pSrcPos = &srcData[(srcY * srcWidth + srcX) * srcPixelSize];
  383. pDestPos[0] = pSrcPos[2];
  384. pDestPos[1] = pSrcPos[1];
  385. pDestPos[2] = pSrcPos[0];
  386. pDestPos[3] = 255;
  387. pDestPos += destPixelSize;
  388. }
  389. }
  390. }
  391. CBitmap* SetupJpegLabel( IFileSystem *pFileSystem, CString filename, int labelSize, const char *pPathID )
  392. {
  393. CBitmap *pBitmap = g_BitmapCache.Find( filename );
  394. if ( pBitmap )
  395. return pBitmap;
  396. CUtlVector<unsigned char> data;
  397. int width, height;
  398. if ( !ReadJpeg( pFileSystem, filename, data, width, height, pPathID ) )
  399. return NULL;
  400. CUtlVector<unsigned char> downsampled;
  401. DownsampleRGBToRGBAImage( data, width, height, downsampled, labelSize, labelSize );
  402. pBitmap = new CBitmap;
  403. if ( pBitmap->CreateBitmap( labelSize, labelSize, 1, 32, downsampled.Base() ) )
  404. {
  405. g_BitmapCache.AddToCache( pBitmap, filename, downsampled.Count(), true );
  406. return pBitmap;
  407. }
  408. else
  409. {
  410. delete pBitmap;
  411. return NULL;
  412. }
  413. }
  414. int CFileSystemOpenDlg::SetupLabelImage( CFileInfo *pInfo, CString name, bool bIsDir )
  415. {
  416. if ( bIsDir )
  417. return m_iLabel_Folder;
  418. CString extension = name.Right( 4 );
  419. extension.MakeLower();
  420. if ( extension == ".jpg" || extension == ".jpeg" )
  421. {
  422. pInfo->m_pBitmap = SetupJpegLabel( m_pFileSystem, m_CurrentDir + "\\" + name, PREVIEW_IMAGE_SIZE, GetPathID() );
  423. if ( pInfo->m_pBitmap )
  424. return m_ImageList.Add( pInfo->m_pBitmap, (CBitmap*)NULL );
  425. else
  426. return m_iLabel_File;
  427. }
  428. else
  429. {
  430. return (extension == ".mdl") ? m_iLabel_Mdl : m_iLabel_File;
  431. }
  432. }
  433. void FilterMdlAndJpgFiles( CUtlVector<CString> &files )
  434. {
  435. // Build a dictionary with all the .jpeg files.
  436. CUtlDict<int,int> jpgFiles;
  437. for ( int i=0; i < files.Count(); i++ )
  438. {
  439. CString extension = files[i].Right( 4 );
  440. extension.MakeLower();
  441. if ( extension == ".jpg" || extension == ".jpeg" )
  442. {
  443. CString base = files[i].Left( files[i].GetLength() - 4 );
  444. jpgFiles.Insert( base, 1 );
  445. }
  446. }
  447. // Now look for all mdls and remove them if they have a jpg.
  448. for ( int i=0; i < files.Count(); i++ )
  449. {
  450. CString extension = files[i].Right( 4 );
  451. extension.MakeLower();
  452. if ( extension == ".mdl" )
  453. {
  454. CString base = files[i].Left( files[i].GetLength() - 4 );
  455. if ( jpgFiles.Find( base ) != -1 )
  456. {
  457. files.Remove( i );
  458. --i;
  459. }
  460. }
  461. }
  462. }
  463. int CALLBACK FileListSortCallback( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
  464. {
  465. CFileSystemOpenDlg *pDlg = (CFileSystemOpenDlg*)lParamSort;
  466. CFileInfo *pInfo1 = &pDlg->m_FileInfos[lParam1];
  467. CFileInfo *pInfo2 = &pDlg->m_FileInfos[lParam2];
  468. if ( pInfo1->m_bIsDir != pInfo2->m_bIsDir )
  469. return pInfo1->m_bIsDir ? -1 : 1;
  470. return Q_stricmp( pInfo1->m_Name, pInfo2->m_Name );
  471. }
  472. void RemoveDuplicates( CUtlVector<CString> &files )
  473. {
  474. CUtlDict<int,int> uniqueFilenames;
  475. for ( int i=0; i < files.Count(); i++ )
  476. {
  477. int iPreviousIndex = uniqueFilenames.Find( files[i] );
  478. if ( iPreviousIndex == -1 )
  479. {
  480. uniqueFilenames.Insert( files[i], i );
  481. }
  482. else
  483. {
  484. files.Remove( i );
  485. --i;
  486. }
  487. }
  488. }
  489. void CFileSystemOpenDlg::PopulateListControl()
  490. {
  491. m_FileList.DeleteAllItems();
  492. g_BitmapCache.UnlockAll();
  493. m_LookInLabel.SetWindowText( CString( "[ROOT]\\" ) + m_CurrentDir );
  494. int iItem = 0;
  495. // First add directories at the top.
  496. CUtlVector<CString> directories;
  497. GetEntries( "*.*", directories, GETENTRIES_DIRECTORIES_ONLY );
  498. RemoveDuplicates( directories );
  499. for ( int i=0; i < directories.Count(); i++ )
  500. {
  501. if ( directories[i] == "." || directories[i] == ".." )
  502. continue;
  503. LVITEM item;
  504. item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  505. item.iItem = iItem++;
  506. item.iSubItem = 0;
  507. item.pszText = directories[i].GetBuffer(0);
  508. item.lParam = m_FileInfos.AddToTail();
  509. m_FileInfos[item.lParam].m_bIsDir = true;
  510. m_FileInfos[item.lParam].m_Name = directories[i];
  511. item.iImage = SetupLabelImage( &m_FileInfos[item.lParam], directories[i], true );
  512. m_FileList.InsertItem( &item );
  513. }
  514. CUtlVector<CString> files;
  515. for ( int iMask=0; iMask < m_FileMasks.Count(); iMask++ )
  516. {
  517. GetEntries( m_FileMasks[iMask], files, GETENTRIES_FILES_ONLY );
  518. }
  519. RemoveDuplicates( files );
  520. if ( m_bFilterMdlAndJpgFiles )
  521. FilterMdlAndJpgFiles( files );
  522. for ( int i=0; i < files.Count(); i++ )
  523. {
  524. LVITEM item;
  525. item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  526. item.iItem = iItem++;
  527. item.iSubItem = 0;
  528. item.iImage = m_iLabel_Mdl;
  529. item.pszText = files[i].GetBuffer(0);
  530. item.lParam = m_FileInfos.AddToTail();
  531. m_FileInfos[item.lParam].m_bIsDir = false;
  532. m_FileInfos[item.lParam].m_Name = files[i];
  533. item.iImage = SetupLabelImage( &m_FileInfos[item.lParam], files[i], false );
  534. m_FileList.InsertItem( &item );
  535. }
  536. m_FileList.SortItems( FileListSortCallback, (DWORD)this );
  537. }
  538. void CFileSystemOpenDlg::AddFileMask( const char *pMask )
  539. {
  540. m_FileMasks.AddToTail( pMask );
  541. }
  542. BOOL CFileSystemOpenDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
  543. {
  544. return CDialog::Create(IDD, pParentWnd);
  545. }
  546. int CFileSystemOpenDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
  547. {
  548. if (CDialog::OnCreate(lpCreateStruct) == -1)
  549. return -1;
  550. return 0;
  551. }
  552. LONG& GetSideCoord( RECT &rect, int iSide )
  553. {
  554. if ( iSide == 0 )
  555. return rect.left;
  556. else if ( iSide == 1 )
  557. return rect.top;
  558. else if ( iSide == 2 )
  559. return rect.right;
  560. else
  561. return rect.bottom;
  562. }
  563. LONG GetSideScreenCoord( CWnd *pWnd, int iSide )
  564. {
  565. RECT rect;
  566. pWnd->GetWindowRect( &rect );
  567. return GetSideCoord( rect, iSide );
  568. }
  569. void CFileSystemOpenDlg::ProcessAnchor( CWindowAnchor *pAnchor )
  570. {
  571. RECT rect, parentRect;
  572. GetWindowRect( &parentRect );
  573. pAnchor->m_pWnd->GetWindowRect( &rect );
  574. GetSideCoord( rect, pAnchor->m_Side ) = GetSideCoord( parentRect, pAnchor->m_ParentSide ) + pAnchor->m_OriginalDist;
  575. ScreenToClient( &rect );
  576. pAnchor->m_pWnd->MoveWindow( &rect );
  577. }
  578. void CFileSystemOpenDlg::AddAnchor( int iDlgItem, int iSide, int iParentSide )
  579. {
  580. CWnd *pItem = GetDlgItem( iDlgItem );
  581. if ( !pItem )
  582. return;
  583. CWindowAnchor *pAnchor = &m_Anchors[m_Anchors.AddToTail()];
  584. pAnchor->m_pWnd = pItem;
  585. pAnchor->m_Side = iSide;
  586. pAnchor->m_ParentSide = iParentSide;
  587. pAnchor->m_OriginalDist = GetSideScreenCoord( pItem, iSide ) - GetSideScreenCoord( this, iParentSide );
  588. }
  589. void CFileSystemOpenDlg::OnSize(UINT nType, int cx, int cy)
  590. {
  591. CDialog::OnSize(nType, cx, cy);
  592. for ( int i=0; i < m_Anchors.Count(); i++ )
  593. ProcessAnchor( &m_Anchors[i] );
  594. if ( m_FileList.GetSafeHwnd() )
  595. PopulateListControl();
  596. }
  597. void CFileSystemOpenDlg::OnDblclkFileList(NMHDR* pNMHDR, LRESULT* pResult)
  598. {
  599. /*int iSelected = m_FileList.GetNextItem( -1, LVNI_SELECTED );
  600. if ( iSelected != -1 )
  601. {
  602. DWORD iItem = m_FileList.GetItemData( iSelected );
  603. if ( iItem < (DWORD)m_FileInfos.Count() )
  604. {
  605. CFileInfo *pInfo = &m_FileInfos[iItem];
  606. if ( pInfo->m_bIsDir )
  607. {
  608. m_CurrentDir += "\\" + m_FileInfos[iItem].m_Name;
  609. PopulateListControl();
  610. }
  611. else
  612. {
  613. m_Filename = m_CurrentDir + "\\" + m_FileInfos[iItem].m_Name;
  614. EndDialog( IDOK );
  615. }
  616. }
  617. else
  618. {
  619. Assert( false );
  620. }
  621. }*/
  622. OnOK();
  623. *pResult = 0;
  624. }
  625. void CFileSystemOpenDlg::OnUpButton()
  626. {
  627. char str[MAX_PATH];
  628. Q_strncpy( str, m_CurrentDir, sizeof( str ) );
  629. Q_StripLastDir( str, sizeof( str ) );
  630. if ( str[0] == 0 )
  631. Q_strncpy( str, ".", sizeof( str ) );
  632. if ( str[strlen(str)-1] == '\\' || str[strlen(str)-1] == '/' )
  633. str[strlen(str)-1] = 0;
  634. m_CurrentDir = str;
  635. PopulateListControl();
  636. }
  637. void CFileSystemOpenDlg::OnItemchangedFileList(NMHDR* pNMHDR, LRESULT* pResult)
  638. {
  639. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  640. DWORD iItem = m_FileList.GetItemData( pNMListView->iItem );
  641. if ( iItem < (DWORD)m_FileInfos.Count() )
  642. {
  643. CFileInfo *pInfo = &m_FileInfos[iItem];
  644. if ( (pNMListView->uChanged & LVIF_STATE) &&
  645. (pNMListView->uNewState & LVIS_SELECTED) )
  646. {
  647. m_FilenameControl.SetWindowText( pInfo->m_Name );
  648. }
  649. }
  650. *pResult = 0;
  651. }
  652. void CFileSystemOpenDlg::SetFilterMdlAndJpgFiles( bool bFilter )
  653. {
  654. m_bFilterMdlAndJpgFiles = bFilter;
  655. }
  656. const char* CFileSystemOpenDlg::GetPathID()
  657. {
  658. if ( m_PathIDString == "" )
  659. return NULL;
  660. else
  661. return (const char*)m_PathIDString;
  662. }
  663. // ------------------------------------------------------------------------------------------------ //
  664. // Implementation of IFileSystemOpenDialog.
  665. // ------------------------------------------------------------------------------------------------ //
  666. // IFileSystemOpenDialog implementation.
  667. class CFileSystemOpenDialogWrapper : public IFileSystemOpenDialog
  668. {
  669. public:
  670. CFileSystemOpenDialogWrapper()
  671. {
  672. m_pDialog = 0;
  673. m_bLastModalWasWindowsDialog = false;
  674. m_bAllowMultiSelect = false;
  675. m_RelativeFilename = NULL;
  676. }
  677. ~CFileSystemOpenDialogWrapper()
  678. {
  679. delete m_RelativeFilename;
  680. }
  681. virtual void Release()
  682. {
  683. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  684. delete m_pDialog;
  685. delete this;
  686. }
  687. // You must call this first to set the hwnd.
  688. virtual void Init( CreateInterfaceFn factory, void *parentHwnd )
  689. {
  690. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  691. Assert( !m_pDialog );
  692. m_hParentWnd = (HWND)parentHwnd;
  693. m_pDialog = new CFileSystemOpenDlg( factory, CWnd::FromHandle( m_hParentWnd ) );
  694. }
  695. virtual void AddFileMask( const char *pMask )
  696. {
  697. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  698. Assert( m_pDialog );
  699. m_pDialog->AddFileMask( pMask );
  700. }
  701. virtual void SetInitialDir( const char *pDir, const char *pPathID )
  702. {
  703. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  704. Assert( m_pDialog );
  705. m_pDialog->SetInitialDir( pDir, pPathID );
  706. }
  707. virtual void SetFilterMdlAndJpgFiles( bool bFilter )
  708. {
  709. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  710. Assert( m_pDialog );
  711. m_pDialog->SetFilterMdlAndJpgFiles( bFilter );
  712. }
  713. virtual void GetFilename( char *pOut, int outLen ) const
  714. {
  715. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  716. Assert( m_pDialog );
  717. if ( m_bLastModalWasWindowsDialog )
  718. {
  719. Q_strncpy( pOut, m_RelativeFilename ? m_RelativeFilename : "", outLen );
  720. }
  721. else
  722. {
  723. Q_strncpy( pOut, m_pDialog->GetFilename(), outLen );
  724. }
  725. }
  726. virtual int GetFilenameBufferSize() const
  727. {
  728. if ( m_bLastModalWasWindowsDialog )
  729. return m_RelativeFilename ? strlen( m_RelativeFilename ) + 1 : 1;
  730. else
  731. return m_pDialog->GetFilename().GetLength() + 1;
  732. }
  733. virtual bool DoModal()
  734. {
  735. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  736. Assert( m_pDialog );
  737. m_bLastModalWasWindowsDialog = false;
  738. return m_pDialog->DoModal() == IDOK;
  739. }
  740. virtual bool DoModal_WindowsDialog()
  741. {
  742. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  743. Assert( m_pDialog );
  744. m_bLastModalWasWindowsDialog = true;
  745. // Get the full filename, then make sure it's a relative path.
  746. char defExt[MAX_PATH] = {0};
  747. if ( m_pDialog->m_FileMasks.Count() > 0 )
  748. {
  749. CString ext = m_pDialog->m_FileMasks[m_pDialog->m_FileMasks.Count()-1].Right( 4 );
  750. const char *pStr = ext;
  751. if ( pStr[0] == '.' )
  752. Q_strncpy( defExt, pStr+1, sizeof( defExt ) );
  753. }
  754. char pFileNameBuf[MAX_PATH];
  755. const char *pFileName = m_pDialog->m_pFileSystem->RelativePathToFullPath( m_pDialog->m_CurrentDir, m_pDialog->m_PathIDString, pFileNameBuf, MAX_PATH );
  756. Q_strcat( pFileNameBuf, "\\", sizeof(pFileNameBuf) );
  757. // Build the list of file filters.
  758. char filters[1024];
  759. if ( m_pDialog->m_FileMasks.Count() == 0 )
  760. {
  761. Q_strncpy( filters, "All Files (*.*)|*.*||", sizeof( filters ) );
  762. }
  763. else
  764. {
  765. filters[0] = 0;
  766. for ( int i=0; i < m_pDialog->m_FileMasks.Count(); i++ )
  767. {
  768. if ( i > 0 )
  769. Q_strncat( filters, "|", sizeof( filters ), COPY_ALL_CHARACTERS );
  770. Q_strncat( filters, m_pDialog->m_FileMasks[i], sizeof( filters ), COPY_ALL_CHARACTERS );
  771. Q_strncat( filters, "|", sizeof( filters ), COPY_ALL_CHARACTERS );
  772. Q_strncat( filters, m_pDialog->m_FileMasks[i], sizeof( filters ), COPY_ALL_CHARACTERS );
  773. if ( pFileName )
  774. {
  775. Q_strncat( pFileNameBuf, m_pDialog->m_FileMasks[i], sizeof( filters ), COPY_ALL_CHARACTERS );
  776. Q_strcat( pFileNameBuf, ";", sizeof(pFileNameBuf) );
  777. }
  778. }
  779. Q_strncat( filters, "||", sizeof( filters ), COPY_ALL_CHARACTERS );
  780. }
  781. DWORD dwDlgFlags = OFN_ENABLESIZING;
  782. if ( m_bAllowMultiSelect )
  783. {
  784. dwDlgFlags |= OFN_ALLOWMULTISELECT;
  785. }
  786. CFileDialog dlg(
  787. true, // open dialog?
  788. defExt[0]==0 ? NULL : defExt, // default file extension
  789. pFileName, // initial filename
  790. dwDlgFlags, // flags
  791. filters,
  792. CWnd::FromHandle( m_hParentWnd ) );
  793. CArrayAutoPtr< char > spMultiSelectBuffer;
  794. if ( m_bAllowMultiSelect )
  795. {
  796. dlg.m_ofn.nMaxFile = 128 * 1024;
  797. spMultiSelectBuffer.Attach( new char[ dlg.m_ofn.nMaxFile ] );
  798. memset( spMultiSelectBuffer.Get(), 0, dlg.m_ofn.nMaxFile );
  799. dlg.m_ofn.lpstrFile = spMultiSelectBuffer.Get();
  800. }
  801. while ( dlg.DoModal() == IDOK )
  802. {
  803. CStringList strPathList;
  804. int numCharsTotal = MAX_PATH;
  805. if ( m_bAllowMultiSelect )
  806. {
  807. for ( POSITION pos = dlg.GetStartPosition(); pos; )
  808. {
  809. strPathList.AddTail( dlg.GetNextPathName( pos ) );
  810. numCharsTotal += strPathList.GetTail().GetLength();
  811. }
  812. }
  813. else
  814. {
  815. strPathList.AddTail( dlg.GetPathName() );
  816. numCharsTotal += strPathList.GetTail().GetLength();
  817. }
  818. numCharsTotal += 2 * strPathList.GetCount();
  819. if ( strPathList.IsEmpty() )
  820. {
  821. AfxMessageBox( IDS_NO_RELATIVE_PATH );
  822. continue;
  823. }
  824. // Allocate the buffer
  825. delete m_RelativeFilename;
  826. m_RelativeFilename = new char[ numCharsTotal ];
  827. char *pchFill = m_RelativeFilename;
  828. char chBuffer[ MAX_PATH ];
  829. bool bFailed = false;
  830. for ( POSITION pos = strPathList.GetHeadPosition(); pos; )
  831. {
  832. CString const &strPath = strPathList.GetNext( pos );
  833. if ( pchFill != m_RelativeFilename )
  834. *( pchFill ++ ) = ' ';
  835. // Make sure we can make this into a relative path.
  836. if ( m_pDialog->m_pFileSystem->FullPathToRelativePath( strPath,
  837. chBuffer, sizeof( chBuffer ) ) )
  838. {
  839. // Replace .jpg or .jpeg extension with .mdl?
  840. char *pEnd = chBuffer;
  841. while ( Q_stristr( pEnd+1, ".jpeg" ) || Q_stristr( pEnd+1, ".jpg" ) )
  842. pEnd = max( Q_stristr( pEnd, ".jpeg" ), Q_stristr( pEnd, ".jpg" ) );
  843. if ( pEnd && pEnd != chBuffer )
  844. Q_strncpy( pEnd, ".mdl", sizeof( chBuffer ) - (pEnd - chBuffer) );
  845. strcpy( pchFill, chBuffer );
  846. pchFill += strlen( pchFill );
  847. }
  848. else
  849. {
  850. AfxMessageBox( IDS_NO_RELATIVE_PATH );
  851. bFailed = true;
  852. break;
  853. }
  854. }
  855. if ( !bFailed )
  856. return true;
  857. }
  858. return false;
  859. }
  860. virtual void AllowMultiSelect( bool bAllow )
  861. {
  862. m_bAllowMultiSelect = bAllow;
  863. }
  864. private:
  865. CFileSystemOpenDlg *m_pDialog;
  866. HWND m_hParentWnd;
  867. char *m_RelativeFilename;
  868. bool m_bLastModalWasWindowsDialog;
  869. bool m_bAllowMultiSelect;
  870. };
  871. EXPOSE_INTERFACE( CFileSystemOpenDialogWrapper, IFileSystemOpenDialog, FILESYSTEMOPENDIALOG_VERSION );