Source code of Windows XP (NT5)
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.

875 lines
19 KiB

  1. //
  2. // FileChooser.cpp
  3. //
  4. #include "stdafx.h"
  5. #include "common.h"
  6. #include "FileChooser.h"
  7. #include <Shlwapi.h>
  8. #include <ShlObj.h>
  9. #include <CommDlg.h>
  10. #ifdef _DEBUG
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14. const TCHAR QuotMark = _T('\"');
  15. const TCHAR AllExt[] = _T(".*");
  16. class CFileChooserControl :
  17. public CWindowImpl<CFileChooserControl>
  18. {
  19. public:
  20. CFileChooserControl()
  21. : m_pParent(NULL),
  22. m_pCtlParent(NULL),
  23. m_id(0)
  24. {
  25. }
  26. BOOL SubclassDlgItem(UINT id, CWindow * pParent)
  27. {
  28. HWND hwnd = pParent->GetDlgItem(id);
  29. ASSERT(hwnd != NULL);
  30. if (SubclassWindow(hwnd))
  31. {
  32. m_id = id;
  33. m_pCtlParent = pParent;
  34. return TRUE;
  35. }
  36. return FALSE;
  37. }
  38. void SetParent(CFileChooser * pParent)
  39. {
  40. ASSERT(pParent != NULL);
  41. m_pParent = pParent;
  42. }
  43. protected:
  44. UINT m_id;
  45. CWindow * m_pCtlParent;
  46. CFileChooser * m_pParent;
  47. };
  48. class CFileChooserEdit :
  49. public CFileChooserControl
  50. {
  51. public:
  52. BEGIN_MSG_MAP_EX(CFileChooserEdit)
  53. MESSAGE_HANDLER_EX(WM_CHAR, OnChar)
  54. MESSAGE_HANDLER_EX(WM_PASTE, OnPaste)
  55. MESSAGE_HANDLER_EX(WM_SETFOCUS, OnSetFocus)
  56. MESSAGE_HANDLER_EX(WM_KILLFOCUS, OnKillFocus)
  57. END_MSG_MAP()
  58. LRESULT OnChar(UINT nMsg, WPARAM, LPARAM);
  59. LRESULT OnPaste(UINT nMsg, WPARAM, LPARAM);
  60. LRESULT OnSetFocus(UINT nMsg, WPARAM, LPARAM);
  61. LRESULT OnKillFocus(UINT nMsg, WPARAM, LPARAM);
  62. };
  63. class CFileChooserButton :
  64. public CFileChooserControl
  65. {
  66. public:
  67. BEGIN_MSG_MAP_EX(CFileChooserButton)
  68. MESSAGE_HANDLER_EX(BM_SETSTATE, OnSetState)
  69. MSG_WM_LBUTTONDOWN(OnLButtonDown)
  70. MSG_WM_LBUTTONUP(OnLButtonUp)
  71. END_MSG_MAP()
  72. LRESULT OnSetState(UINT nMsg, WPARAM, LPARAM);
  73. void OnLButtonDown(UINT nFlags, CPoint point);
  74. void OnLButtonUp(UINT nFlags, CPoint point);
  75. };
  76. //----------------------
  77. LRESULT
  78. CFileChooserEdit::OnChar(UINT nMsg, WPARAM wParam, LPARAM lParam)
  79. {
  80. LRESULT res = 0;
  81. if (m_pParent->OnChar(wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)))
  82. {
  83. res = DefWindowProc(nMsg, wParam, lParam);
  84. }
  85. return res;
  86. }
  87. LRESULT
  88. CFileChooserEdit::OnPaste(UINT nMsg, WPARAM wParam, LPARAM lParam)
  89. {
  90. LRESULT res = m_pCtlParent->SendDlgItemMessage(WM_PASTE, wParam, lParam);
  91. m_pParent->OnPaste();
  92. return res;
  93. }
  94. LRESULT
  95. CFileChooserEdit::OnSetFocus(UINT nMsg, WPARAM wParam, LPARAM lParam)
  96. {
  97. m_pParent->OnSetEditFocus();
  98. return DefWindowProc(nMsg, wParam, lParam);
  99. }
  100. LRESULT
  101. CFileChooserEdit::OnKillFocus(UINT nMsg, WPARAM wParam, LPARAM lParam)
  102. {
  103. m_pParent->OnKillEditFocus();
  104. return DefWindowProc(nMsg, wParam, lParam);
  105. }
  106. //---------------------
  107. LRESULT
  108. CFileChooserButton::OnSetState(UINT nMsg, WPARAM wParam, LPARAM lParam)
  109. {
  110. // We are producing dialog on the way back
  111. if (!wParam)
  112. m_pParent->OnBrowseBtn();
  113. return DefWindowProc(nMsg, wParam, lParam);
  114. }
  115. void
  116. CFileChooserButton::OnLButtonDown(UINT nFlags, CPoint point)
  117. {
  118. m_pCtlParent->SendDlgItemMessage(m_id, BM_SETSTATE, TRUE, 0);
  119. }
  120. void
  121. CFileChooserButton::OnLButtonUp(UINT nFlags, CPoint point)
  122. {
  123. m_pCtlParent->SendDlgItemMessage(m_id, BM_SETSTATE, FALSE, 0);
  124. }
  125. //---------------------
  126. CFileChooser::~CFileChooser()
  127. {
  128. // ASSERT(m_edit != NULL || m_edit->m_hWnd == NULL);
  129. // ASSERT(m_button != NULL || m_button->m_hWnd == NULL);
  130. delete m_edit;
  131. delete m_button;
  132. }
  133. BOOL
  134. CFileChooser::Init(CWindow * pParent, DWORD dwStyle, UINT idEdit, UINT idButton)
  135. {
  136. ASSERT(NULL != pParent);
  137. ASSERT(NULL != pParent->GetDlgItem(idEdit));
  138. ASSERT(NULL != pParent->GetDlgItem(idButton));
  139. m_pParent = pParent;
  140. SetStyle(dwStyle);
  141. m_edit = new CFileChooserEdit;
  142. m_button = new CFileChooserButton;
  143. if (m_edit != NULL && m_button != NULL)
  144. {
  145. m_edit->SetParent(this);
  146. m_button->SetParent(this);
  147. if (StyleBitSet(FC_AUTOCOMPLETION))
  148. SHAutoComplete(pParent->GetDlgItem(idEdit), SHACF_FILESYSTEM);
  149. return m_edit->SubclassDlgItem(idEdit, pParent)
  150. && m_button->SubclassDlgItem(idButton, pParent);
  151. }
  152. return FALSE;
  153. }
  154. // External SetPath
  155. void
  156. CFileChooser::SetPath(const CString& path)
  157. {
  158. ASSERT(m_edit->m_hWnd != NULL);
  159. m_strPath = path;
  160. if (OpenForRead() && StyleBitSet(FC_PREPARE_DEFAULT))
  161. CreateDefaultPathForRead();
  162. SetPathToEdit(m_strPath);
  163. m_bEditDirty = FALSE;
  164. }
  165. BOOL
  166. CFileChooser::HasEditFocus()
  167. {
  168. ASSERT(m_edit->m_hWnd != NULL);
  169. return GetFocus() == m_edit->m_hWnd;
  170. }
  171. void
  172. CFileChooser::SetPathToEdit(LPCTSTR path)
  173. {
  174. if (HasEditFocus())
  175. {
  176. m_edit->SetWindowText(path);
  177. }
  178. else
  179. {
  180. SetCompactedPath(path);
  181. }
  182. }
  183. void
  184. CFileChooser::CreateDefaultPathForRead()
  185. {
  186. if (!PathFileExists(m_strPath))
  187. {
  188. // try to find first file with the first extension
  189. // from the extensions list
  190. BOOL bDefaultSet = FALSE;
  191. BOOL bPathEmpty = m_strPath.IsEmpty();
  192. TCHAR find_str[MAX_PATH];
  193. WIN32_FIND_DATA find_data;
  194. if (bPathEmpty)
  195. {
  196. GetCurrentDirectory(MAX_PATH, find_str);
  197. m_strPath = find_str;
  198. }
  199. else
  200. {
  201. StrCpy(find_str, m_strPath);
  202. if (!PathIsDirectory(find_str))
  203. {
  204. PathRemoveFileSpec(find_str);
  205. }
  206. }
  207. PathAppend(find_str, _T("*"));
  208. std::list<CFilterEntry>::iterator it;
  209. for (it = m_ext.begin(); it != m_ext.end(); it++)
  210. {
  211. CString ext = (*it).m_ext;
  212. PathAddExtension(find_str, ext);
  213. HANDLE hFind = FindFirstFile(find_str, &find_data);
  214. if ( hFind != INVALID_HANDLE_VALUE
  215. && (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0
  216. )
  217. {
  218. if (!bPathEmpty)
  219. {
  220. TCHAR buf[MAX_PATH];
  221. StrCpy(buf, m_strPath);
  222. PathRemoveFileSpec(buf);
  223. m_strPath = buf;
  224. }
  225. m_strPath += find_data.cFileName;
  226. FindClose(hFind);
  227. bDefaultSet = TRUE;
  228. break;
  229. }
  230. }
  231. if (!bDefaultSet && StyleBitSet(FC_WILDCARD_DEFAULT))
  232. {
  233. // if nothing found, just attach *.ext to the path
  234. // find_str was prepared before as xxx\*.
  235. m_strPath = find_str;
  236. if (!m_ext.empty())
  237. {
  238. m_strPath += m_ext.front().m_ext;
  239. }
  240. else
  241. {
  242. m_strPath += _T("*");
  243. }
  244. }
  245. }
  246. }
  247. BOOL
  248. CFileChooser::IsValidChar(UINT nChar, BOOL bExcludeWildcards)
  249. {
  250. switch (PathGetCharType((TCHAR)nChar))
  251. {
  252. case GCT_INVALID:
  253. return FALSE;
  254. case GCT_WILD:
  255. return !bExcludeWildcards;
  256. case GCT_LFNCHAR:
  257. case GCT_SEPARATOR:
  258. case GCT_SHORTCHAR:
  259. break;
  260. }
  261. return TRUE;
  262. }
  263. BOOL
  264. CFileChooser::IsValidPath(LPCTSTR path)
  265. {
  266. UINT len = lstrlen(path);
  267. BOOL bRes = TRUE;
  268. // BOOL quotOpen = FALSE;
  269. for (UINT i = 0; i < len; i++)
  270. {
  271. TCHAR c = path[i];
  272. /*
  273. if (c == QuotMark)
  274. {
  275. if (i == 0)
  276. {
  277. quotOpen = TRUE;
  278. continue;
  279. }
  280. else
  281. {
  282. if (!quotOpen)
  283. {
  284. bRes = FALSE;
  285. }
  286. break;
  287. }
  288. }
  289. */
  290. if (!IsValidChar(c, TRUE))
  291. {
  292. bRes = FALSE;
  293. break;
  294. }
  295. }
  296. return bRes;
  297. }
  298. // Character filtering routine for the edit control.
  299. // Returns TRUE if character should be passed to the CEdit
  300. //
  301. BOOL
  302. CFileChooser::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  303. {
  304. if (IsValidChar(nChar))
  305. {
  306. m_bEditDirty = TRUE;
  307. return TRUE;
  308. }
  309. else
  310. {
  311. switch (nChar)
  312. {
  313. case VK_DELETE:
  314. case VK_BACK:
  315. case _T('/'):
  316. return TRUE;
  317. }
  318. return FALSE;
  319. }
  320. }
  321. // Text was pasted to edit control
  322. void
  323. CFileChooser::OnPaste()
  324. {
  325. TCHAR buf[MAX_PATH];
  326. int len = m_edit->GetWindowText(buf, MAX_PATH);
  327. for (int i = 0; i < len || IsValidChar(buf[i]); i++)
  328. ;
  329. if (i < len)
  330. {
  331. m_edit->SendMessage(EM_SETSEL, i, len - 1);
  332. m_bTextValid = FALSE;
  333. }
  334. else
  335. {
  336. m_strPath = buf;
  337. SetPathToEdit(buf);
  338. m_bEditDirty = FALSE;
  339. }
  340. m_bEditDirty = TRUE;
  341. }
  342. void
  343. CFileChooser::OnSetEditFocus()
  344. {
  345. m_edit->SetWindowText(m_strPath);
  346. }
  347. void
  348. CFileChooser::OnKillEditFocus()
  349. {
  350. // update internal string buffer with path
  351. TCHAR buf[MAX_PATH];
  352. ZeroMemory(buf, MAX_PATH);
  353. if (m_bEditDirty)
  354. {
  355. m_edit->GetWindowText(buf, MAX_PATH);
  356. m_strPath = buf;
  357. }
  358. SetCompactedPath(m_strPath);
  359. m_bEditDirty = FALSE;
  360. }
  361. void
  362. CFileChooser::SetCompactedPath(LPCTSTR path)
  363. {
  364. // compact path before writing to edit
  365. CRect rc;
  366. m_edit->GetClientRect(&rc);
  367. HDC dc = m_edit->GetDC();
  368. TCHAR buf[MAX_PATH] = {0};
  369. StrCpy(buf, path);
  370. PathMakePretty(buf);
  371. PathCompactPath(dc, buf, rc.Width());
  372. m_edit->ReleaseDC(dc);
  373. m_edit->SetWindowText(buf);
  374. }
  375. DWORD
  376. CFileChooser::GetFileName(CString& strFile)
  377. {
  378. DWORD dwRes = FC_SUCCESS;
  379. TCHAR str[MAX_PATH];
  380. if ( !m_bTextValid
  381. || FC_SUCCESS != ExtractPath(str)
  382. || !IsValidPath(str)
  383. )
  384. return FC_TEXT_IS_INVALID;
  385. if (StyleBitSet(FC_PATH_CHECK))
  386. {
  387. if (OpenForRead())
  388. {
  389. if (!PathFileExists(str) && !PathIsDirectory(str))
  390. {
  391. BOOL bFound = FALSE;
  392. if (StyleBitSet(FC_CHECK_FILENAME_ONLY))
  393. {
  394. // try with default extension(s) if it is just filename
  395. // without any extensions
  396. LPTSTR p = PathFindExtension(str);
  397. if (p != NULL && *p == 0)
  398. {
  399. CString strExt, strTest = str;
  400. std::list<CFilterEntry>::iterator it;
  401. for (it = m_ext.begin(); it != m_ext.end(); it++)
  402. {
  403. strExt = (*it).m_ext;
  404. if (PathFileExists(strTest + strExt))
  405. {
  406. StrCat(str, strExt);
  407. bFound = TRUE;
  408. break;
  409. }
  410. }
  411. }
  412. }
  413. if (!bFound)
  414. dwRes = FC_FILE_DOES_NOT_EXIST;
  415. }
  416. else if (PathIsDirectory(str))
  417. {
  418. if (!StyleBitSet(FC_DIRECTORY_ONLY))
  419. {
  420. PathAddBackslash(str);
  421. dwRes = FC_FILENAME_IS_DIRECTORY;
  422. }
  423. }
  424. else if (StyleBitSet(FC_DIRECTORY_ONLY))
  425. {
  426. if (PathFileExists(str))
  427. dwRes = FC_FILENAME_IS_FILE;
  428. }
  429. }
  430. else if (StyleBitSet(FC_FORWRITE))
  431. {
  432. // TODO: make sure we have write access to this path
  433. }
  434. }
  435. if (dwRes == FC_SUCCESS)
  436. {
  437. if (StyleBitSet(FC_COMMANDLINE))
  438. {
  439. // We are returning whole command line, get it again
  440. GetText(str);
  441. }
  442. strFile = str;
  443. }
  444. return dwRes;
  445. }
  446. BOOL
  447. CFileChooser::BrowseForFile(CString& strPath, CString& strFile)
  448. {
  449. BOOL bRes = FALSE;
  450. OPENFILENAME ofn;
  451. TCHAR buf[MAX_PATH];
  452. ZeroMemory(&ofn, sizeof(OPENFILENAME));
  453. StrCpy(buf, strFile);
  454. ofn.lStructSize = sizeof(OPENFILENAME);
  455. // We are not using template
  456. ofn.hInstance = NULL;
  457. ofn.Flags |= m_ofn_Flags;
  458. ofn.Flags |= OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT;
  459. if (OpenForRead())
  460. ofn.Flags |= OFN_FILEMUSTEXIST;
  461. else
  462. ofn.Flags |= (OFN_NOREADONLYRETURN | OFN_NOTESTFILECREATE | OFN_HIDEREADONLY);
  463. #if (_WIN32_WINNT >= 0x0500)
  464. ofn.FlagsEx &= ~(OFN_EX_NOPLACESBAR);
  465. #endif
  466. // Create filter using our extensions list
  467. CString strFilter, strDefExt;
  468. CreateFilter(strFilter, strDefExt);
  469. ofn.lpstrDefExt = strDefExt;
  470. ofn.lpstrFile = buf;
  471. ofn.nMaxFile = MAX_PATH;
  472. ofn.lpstrInitialDir = strPath.IsEmpty() ? NULL : (LPCTSTR)strPath;
  473. ofn.lpstrFilter = strFilter;
  474. ofn.nFilterIndex = GetFilterIndex(strFile);
  475. // We better set the owner, or this dialog will be visible on task bar
  476. ofn.hwndOwner = m_pParent->m_hWnd;
  477. ofn.lpstrTitle = m_strTitle;
  478. if (StyleBitSet(FC_HIDEREADONLY))
  479. ofn.Flags |= OFN_HIDEREADONLY;
  480. if (!StyleBitSet(FC_FORWRITE))
  481. bRes = GetOpenFileName(&ofn);
  482. else
  483. bRes = GetSaveFileName(&ofn);
  484. if (bRes)
  485. {
  486. m_bDoReplaceFile = TRUE;
  487. }
  488. else
  489. {
  490. #ifdef _DEBUG
  491. DWORD dwError;
  492. ASSERT(0 == (dwError = CommDlgExtendedError()));
  493. #endif
  494. }
  495. strFile = buf;
  496. return bRes;
  497. }
  498. static int CALLBACK
  499. FileChooserCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  500. {
  501. CFileChooser * pThis = (CFileChooser *)lpData;
  502. ASSERT(pThis != NULL);
  503. return pThis->BrowseForFolderCallback(hwnd, uMsg, lParam);
  504. }
  505. int CFileChooser::BrowseForFolderCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
  506. {
  507. switch (uMsg)
  508. {
  509. case BFFM_INITIALIZED:
  510. ASSERT(m_pPathTemp != NULL);
  511. if (::PathIsNetworkPath(m_pPathTemp))
  512. return 0;
  513. while (!::PathIsDirectory(m_pPathTemp))
  514. {
  515. if (0 == ::PathRemoveFileSpec(m_pPathTemp) && !::PathIsRoot(m_pPathTemp))
  516. {
  517. return 0;
  518. }
  519. DWORD attr = GetFileAttributes(m_pPathTemp);
  520. if (StyleBitSet(FC_FORWRITE) && (attr & FILE_ATTRIBUTE_READONLY) == 0)
  521. break;
  522. }
  523. ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)m_pPathTemp);
  524. break;
  525. case BFFM_SELCHANGED:
  526. {
  527. LPITEMIDLIST pidl = (LPITEMIDLIST)lParam;
  528. TCHAR path[MAX_PATH];
  529. if (SHGetPathFromIDList(pidl, path))
  530. {
  531. ::SendMessage(hwnd, BFFM_ENABLEOK, 0, !PathIsNetworkPath(path));
  532. }
  533. }
  534. break;
  535. case BFFM_VALIDATEFAILED:
  536. break;
  537. }
  538. return 0;
  539. }
  540. BOOL
  541. CFileChooser::BrowseForFolder(CString& strPath)
  542. {
  543. LPITEMIDLIST pidl = NULL;
  544. HRESULT hr;
  545. BOOL bRes = FALSE;
  546. if (SUCCEEDED(hr = CoInitialize(NULL)))
  547. {
  548. if (SUCCEEDED(SHGetFolderLocation(NULL, CSIDL_DRIVES, NULL, 0, &pidl)))
  549. {
  550. LPITEMIDLIST pidList = NULL;
  551. BROWSEINFO bi;
  552. TCHAR buf[MAX_PATH];
  553. ZeroMemory(&bi, sizeof(bi));
  554. StrCpy(buf, strPath);
  555. bi.hwndOwner = m_pParent->m_hWnd;
  556. bi.pidlRoot = pidl;
  557. bi.pszDisplayName = m_pPathTemp = buf;
  558. bi.lpszTitle = m_strTitle;
  559. bi.ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
  560. bi.lpfn = FileChooserCallback;
  561. bi.lParam = (LPARAM)this;
  562. pidList = SHBrowseForFolder(&bi);
  563. if ( pidList != NULL
  564. && SHGetPathFromIDList(pidList, buf)
  565. )
  566. {
  567. strPath = buf;
  568. bRes = TRUE;
  569. }
  570. IMalloc * pMalloc;
  571. VERIFY(SUCCEEDED(SHGetMalloc(&pMalloc)));
  572. if (pidl != NULL)
  573. pMalloc->Free(pidl);
  574. pMalloc->Release();
  575. }
  576. CoUninitialize();
  577. }
  578. return bRes;
  579. }
  580. void
  581. CFileChooser::AddExtension(HINSTANCE hInst, UINT idText, UINT idExt)
  582. {
  583. CString text, ext;
  584. if (text.LoadString(hInst, idText) && ext.LoadString(hInst, idExt))
  585. {
  586. AddExtension(text, ext);
  587. }
  588. }
  589. void
  590. CFileChooser::AddExtension(LPCTSTR text, LPCTSTR ext)
  591. {
  592. ASSERT(ext != NULL && *ext == _T('.'));
  593. CFilterEntry entry(text, ext);
  594. m_ext.push_back(entry);
  595. }
  596. const TCHAR cDelimiter = _T('\n');
  597. void
  598. CFileChooser::CreateFilter(CString& strFilter, CString& strDefExt)
  599. {
  600. strFilter.Empty();
  601. strDefExt.Empty();
  602. BOOL bExtDone = FALSE;
  603. std::list<CFilterEntry>::iterator it;
  604. for (it = m_ext.begin(); it != m_ext.end(); it++)
  605. {
  606. CFilterEntry entry = (*it);
  607. strFilter += entry.m_text;
  608. if (m_dwStyle & FC_WILDCARD_DESC)
  609. {
  610. strFilter += _T(" (*");
  611. strFilter += entry.m_ext;
  612. strFilter += _T(")");
  613. }
  614. strFilter += cDelimiter;
  615. strFilter += _T('*');
  616. strFilter += entry.m_ext;
  617. strFilter += cDelimiter;
  618. if (!bExtDone)
  619. {
  620. LPCTSTR pExt = entry.m_ext;
  621. strDefExt =
  622. *pExt == _T('.') ? pExt + 1 : pExt;
  623. bExtDone = TRUE;
  624. }
  625. }
  626. if (!strFilter.IsEmpty())
  627. {
  628. strFilter += cDelimiter;
  629. for (int i = 0; i < strFilter.GetLength(); i++)
  630. {
  631. if (strFilter[i] == cDelimiter)
  632. strFilter.SetAt(i, 0);
  633. }
  634. }
  635. }
  636. int
  637. CFileChooser::GetFilterIndex(const CString& fileName)
  638. {
  639. LPTSTR p = PathFindExtension(fileName);
  640. if (p == NULL)
  641. p = (LPTSTR)AllExt;
  642. std::list<CFilterEntry>::iterator it;
  643. int idx = 1;
  644. for (it = m_ext.begin(); it != m_ext.end(); it++, idx++)
  645. {
  646. if (StrCmpI((*it).m_ext, p) == 0)
  647. return idx;
  648. }
  649. return 0;
  650. }
  651. void
  652. CFileChooser::GetText(LPTSTR buf)
  653. {
  654. ASSERT(buf != NULL);
  655. if (m_bEditDirty)
  656. {
  657. m_edit->GetWindowText(buf, MAX_PATH);
  658. }
  659. else
  660. {
  661. StrCpy(buf, m_strPath);
  662. }
  663. }
  664. int
  665. CFileChooser::ExtractPath(LPTSTR path)
  666. {
  667. ASSERT(path != NULL);
  668. int rc = FC_SUCCESS;
  669. TCHAR buf[MAX_PATH] = {0};
  670. LPTSTR start = buf;
  671. GetText(buf);
  672. if (StyleBitSet(FC_COMMANDLINE))
  673. {
  674. if (*buf == QuotMark)
  675. {
  676. LPTSTR end = StrChr(++start, QuotMark);
  677. if (end == NULL)
  678. {
  679. // Wrong format, closing quotation mark is not set
  680. rc = FC_NO_CLOSING_QUOTE;
  681. // Return part of the path up to first space
  682. PathRemoveArgs(buf);
  683. }
  684. else
  685. {
  686. ++end;
  687. *end = 0;
  688. PathUnquoteSpaces(buf);
  689. start = buf;
  690. }
  691. }
  692. else
  693. {
  694. PathRemoveArgs(buf);
  695. }
  696. }
  697. StrCpy(path, start);
  698. return rc;
  699. }
  700. int
  701. CFileChooser::ExtractArgs(LPTSTR buf)
  702. {
  703. ASSERT(buf != NULL);
  704. int rc = FC_SUCCESS;
  705. GetText(buf);
  706. LPTSTR p = PathGetArgs(buf);
  707. if (p != NULL)
  708. {
  709. StrCpy(buf, p);
  710. }
  711. else
  712. {
  713. *buf = 0;
  714. }
  715. return rc;
  716. }
  717. void
  718. CFileChooser::OnBrowseBtn()
  719. {
  720. BOOL bRes = FALSE;
  721. if (m_bDialogActive)
  722. return;
  723. m_bDialogActive = TRUE;
  724. TCHAR path[MAX_PATH] = {0};
  725. TCHAR args[MAX_PATH] = {0};
  726. int rc = ExtractPath(path);
  727. if (StyleBitSet(FC_COMMANDLINE))
  728. {
  729. ExtractArgs(args);
  730. }
  731. CString strFile, strBuffer;
  732. // m_strPath = path;
  733. strBuffer = path;
  734. if (StyleBitSet(FC_FORWRITE))
  735. {
  736. if (!PathIsDirectory(path))
  737. {
  738. if (PathRemoveFileSpec(path))
  739. {
  740. // check if path part of filename exists
  741. if (PathIsDirectory(path))
  742. {
  743. // we will use non-path part of spec as a filename
  744. strFile = PathFindFileName(strBuffer);
  745. }
  746. else
  747. {
  748. // it is wrong path, use default one
  749. // TODO: actually I need to take from filespec all existent
  750. // chunks of path and filename, for example c:\aa\bb\cc\dd.txt,
  751. // if c:\aa\bb exists, then strPath should be set to c:\aa\bb,
  752. // and strFile to dd.txt
  753. path[0] = 0;
  754. }
  755. }
  756. else
  757. {
  758. // it is filename only
  759. strFile = strBuffer;
  760. path[0] = 0;
  761. }
  762. }
  763. }
  764. else
  765. {
  766. if (!PathIsDirectory(path))
  767. {
  768. strFile = PathFindFileName(path);
  769. PathRemoveFileSpec(path);
  770. }
  771. }
  772. CString strPath(path);
  773. if (StyleBitSet(FC_DIRECTORY_ONLY))
  774. {
  775. bRes = BrowseForFolder(strPath);
  776. if (bRes)
  777. {
  778. StrCpy(path, strPath);
  779. }
  780. }
  781. else
  782. {
  783. bRes = BrowseForFile(strPath, strFile);
  784. if (bRes)
  785. {
  786. StrCpy(path, strFile);
  787. }
  788. }
  789. if (bRes)
  790. {
  791. if (StyleBitSet(FC_COMMANDLINE))
  792. {
  793. PathQuoteSpaces(path);
  794. m_strPath = path;
  795. if (*args != 0)
  796. {
  797. m_strPath += _T(' ');
  798. m_strPath += args;
  799. }
  800. }
  801. else
  802. m_strPath = path;
  803. SetPathToEdit(m_strPath);
  804. m_bEditDirty = FALSE;
  805. }
  806. m_bDialogActive = FALSE;
  807. }