From 9c149dda8124ed87ebcf381abf8723128bc5cfc8 Mon Sep 17 00:00:00 2001 From: Bill Hoffman Date: Tue, 5 Jun 2001 17:26:48 -0400 Subject: [PATCH] ENH: add better path chooser dialog --- Source/MFCDialog/CMakeSetupDialog.cpp | 55 +--- Source/MFCDialog/PathDialog.cpp | 380 ++++++++++++++++++++++++++ Source/MFCDialog/PathDialog.h | 74 +++++ Source/MFCDialog/PropertyList.cpp | 37 +-- 4 files changed, 469 insertions(+), 77 deletions(-) create mode 100644 Source/MFCDialog/PathDialog.cpp create mode 100644 Source/MFCDialog/PathDialog.h diff --git a/Source/MFCDialog/CMakeSetupDialog.cpp b/Source/MFCDialog/CMakeSetupDialog.cpp index d6819eb4f..0c558dcda 100644 --- a/Source/MFCDialog/CMakeSetupDialog.cpp +++ b/Source/MFCDialog/CMakeSetupDialog.cpp @@ -3,6 +3,7 @@ #include "stdafx.h" #include "CMakeSetup.h" +#include "PathDialog.h" #include "CMakeSetupDialog.h" #include "../cmCacheManager.h" #include "../cmake.h" @@ -205,57 +206,19 @@ HCURSOR CMakeSetupDialog::OnQueryDragIcon() -// Insane Microsoft way of setting the initial directory -// for the Shbrowseforfolder function... -// SetSelProc -// Callback procedure to set the initial selection of the browser. -int CALLBACK CMakeSetupDialog_SetSelProc( HWND hWnd, UINT uMsg, - LPARAM lParam, LPARAM lpData ) -{ - if (uMsg==BFFM_INITIALIZED) - { - ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData ); - } - return 0; -} - -inline void ILFree(LPITEMIDLIST pidl) -{ - LPMALLOC pMalloc; - if (pidl) - { - SHGetMalloc(&pMalloc); - pMalloc->Free( pidl); - pMalloc->Release(); - } -} - - // Browse button bool CMakeSetupDialog::Browse(CString &result, const char *title) { -// don't know what to do with initial right now... - char szPathName[4096]; - BROWSEINFO bi; - - bi.hwndOwner = m_hWnd; - bi.pidlRoot = NULL; - bi.pszDisplayName = (LPTSTR)szPathName; - bi.lpszTitle = title; - bi.ulFlags = BIF_BROWSEINCLUDEFILES; - // set up initial directory code - bi.lpfn = CMakeSetupDialog_SetSelProc; - bi.lParam = (LPARAM)(LPCSTR) result; - // open the directory chooser - LPITEMIDLIST pidl = SHBrowseForFolder(&bi); - // get the result - bool bSuccess = (SHGetPathFromIDList(pidl, szPathName) ? true : false); - if(bSuccess) + CPathDialog dlg("Select Path", title, result); + if(dlg.DoModal()==IDOK) { - result = szPathName; + result = dlg.GetPathName(); + return true; + } + else + { + return false; } - ILFree(pidl); - return bSuccess; } diff --git a/Source/MFCDialog/PathDialog.cpp b/Source/MFCDialog/PathDialog.cpp new file mode 100644 index 000000000..58337f994 --- /dev/null +++ b/Source/MFCDialog/PathDialog.cpp @@ -0,0 +1,380 @@ +////////////////////////////////////////////////////////////////////////// +//PathDialog.h file +// +//Written by Nguyen Tan Hung +////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "PathDialog.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#define IDC_FOLDERTREE 0x3741 +#define IDC_TITLE 0x3742 +#define IDC_STATUSTEXT 0x3743 + +#define IDC_NEW_EDIT_PATH 0x3744 + +// Class CDlgWnd +BEGIN_MESSAGE_MAP(CPathDialogSub, CWnd) + ON_BN_CLICKED(IDOK, OnOK) + ON_EN_CHANGE(IDC_NEW_EDIT_PATH, OnChangeEditPath) + END_MESSAGE_MAP() + + void CPathDialogSub::OnOK() +{ + ::GetWindowText(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH), + m_pPathDialog->m_szPathName, MAX_PATH); + + if(CPathDialog::MakeSurePathExists(m_pPathDialog->m_szPathName)==0) + { + m_pPathDialog->m_bGetSuccess=TRUE; + ::EndDialog(m_pPathDialog->m_hWnd, IDOK); + } + else + { + ::SetFocus(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH)); + } +} + +void CPathDialogSub::OnChangeEditPath() +{ + ::GetWindowText(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH), + m_pPathDialog->m_szPathName, MAX_PATH); + BOOL bEnableOKButton = (_tcslen(m_pPathDialog->m_szPathName)>0); + SendMessage(BFFM_ENABLEOK, 0, bEnableOKButton); +} +///////////////////////////////////////////////////////////////////////////// +// CPathDialog dialog + + +CPathDialog::CPathDialog(LPCTSTR lpszCaption, + LPCTSTR lpszTitle, + LPCTSTR lpszInitialPath, + CWnd* pParent) +{ + m_hWnd=NULL; + m_PathDialogSub.m_pPathDialog= this; + m_bParentDisabled = FALSE; + + // Get the true parent of the dialog + m_pParentWnd = CWnd::GetSafeOwner(pParent); + + m_lpszCaption = lpszCaption; + m_lpszInitialPath = lpszInitialPath; + + memset(&m_bi, 0, sizeof(BROWSEINFO) ); + m_bi.hwndOwner = (m_pParentWnd==NULL)?NULL:m_pParentWnd->GetSafeHwnd(); + m_bi.pszDisplayName = 0; + m_bi.pidlRoot = 0; + m_bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT; + m_bi.lpfn = BrowseCallbackProc; + m_bi.lpszTitle = lpszTitle; +} + + +///////////////////////////////////////////////////////////////////////////// +// CPathDialog message handlers + +CString CPathDialog::GetPathName() +{ + return CString(m_szPathName); +} + +int CALLBACK CPathDialog::BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam, LPARAM pData) +{ + CPathDialog* pDlg = (CPathDialog*)pData; + + switch(uMsg) + { + case BFFM_INITIALIZED: + { + RECT rc; + HWND hEdit; + HFONT hFont; + + pDlg->m_hWnd = hwnd; + + if(pDlg->m_lpszCaption!=NULL) + { + ::SetWindowText(hwnd, pDlg->m_lpszCaption); + } + + VERIFY(pDlg->m_PathDialogSub.SubclassWindow(hwnd)); + ::ShowWindow(::GetDlgItem(hwnd, IDC_STATUSTEXT), SW_HIDE); + ::GetWindowRect(::GetDlgItem(hwnd, IDC_FOLDERTREE), &rc); + rc.bottom = rc.top - 4; + rc.top = rc.bottom - 23; + ::ScreenToClient(hwnd, (LPPOINT)&rc); + ::ScreenToClient(hwnd, ((LPPOINT)&rc)+1); + hEdit = ::CreateWindowEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""), + WS_CHILD|WS_TABSTOP|WS_VISIBLE|ES_AUTOHSCROLL, + rc.left, rc.top, + rc.right-rc.left, rc.bottom-rc.top, + hwnd, NULL, NULL, NULL); + ::SetWindowLong(hEdit, GWL_ID, IDC_NEW_EDIT_PATH); + ::ShowWindow(hEdit, SW_SHOW); + + hFont = (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0); + ::SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); + + LPCTSTR lpszPath = pDlg->m_lpszInitialPath; + TCHAR szTemp[MAX_PATH]; + if(lpszPath==NULL) + { + ::GetCurrentDirectory(MAX_PATH, szTemp ); + lpszPath = szTemp; + } + // WParam is TRUE since you are passing a path. + // It would be FALSE if you were passing a pidl. + ::SendMessage(hwnd,BFFM_SETSELECTION,TRUE, + (LPARAM)lpszPath); + break; + } + case BFFM_SELCHANGED: + { + char szSelection[MAX_PATH]; + if(!::SHGetPathFromIDList((LPITEMIDLIST)lParam, szSelection) || + (szSelection[1] !=':' && szSelection[1] != '\\')) + { + szSelection[0] = '\0'; + ::SendMessage(hwnd, BFFM_ENABLEOK, 0, FALSE); + } + else + { + ::SendMessage(hwnd, BFFM_ENABLEOK, 0, TRUE); + } + ::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szSelection); + ::SetWindowText(::GetDlgItem(hwnd, IDC_NEW_EDIT_PATH), szSelection); + break; + } + default: + break; + } + return 0; +} + + + +int CPathDialog::DoModal() +{ + + ///////////////////////////////////////////////////////// + TCHAR szPathTemp[MAX_PATH]; + m_bi.lpfn = BrowseCallbackProc; // address of callback function + m_bi.lParam = (LPARAM)this; // pass address of object to callback function + m_bi.pszDisplayName = szPathTemp; + + LPITEMIDLIST pidl; + LPMALLOC pMalloc; + + int iResult=-1; + if(SUCCEEDED(SHGetMalloc(&pMalloc))) + { + m_bGetSuccess = FALSE; + pidl = SHBrowseForFolder(&m_bi); + if (pidl!=NULL) + { + //not need do this because OnOK function did + //bSucceeded = SHGetPathFromIDList(pidl, m_szPathName); + // In C++: + pMalloc->Free(pidl); + //In C: + //pMalloc->lpVtbl->Free(pMalloc,pidl); + //pMalloc->lpVtbl->Release(pMalloc); + } + if(m_bGetSuccess) + { + iResult = IDOK; + } + pMalloc->Release(); + } + + if(m_bParentDisabled && (m_pParentWnd!=NULL)) + { + m_pParentWnd->EnableWindow(TRUE); + } + m_bParentDisabled=FALSE; + + return iResult; +} + +BOOL CPathDialog::IsFileNameValid(LPCTSTR lpFileName) +{ + return TRUE; +} + +const TCHAR c_FolderDoesNotExist[] = _T( + "The folder:\n\n" + "%s\n\n" + "does not exist. Do you want the folder to be created?"); +const TCHAR c_szErrInvalidPath[] = _T( + "The folder:" + "\n\n" + "%s\n\n" + "is invalid. Please reenter."); +const TCHAR c_szErrCreatePath[] = _T( + "The folder:" + "\n\n" + "%s" + "\n\ncan not be created. Please double check."); + +//return -1: user break; +//return 0: no error +//return 1: lpPath is invalid +//return 2: can not create lpPath +int CPathDialog::MakeSurePathExists(LPCTSTR lpPath) +{ + CString strMsg; + int iRet; + try + { + //validate path + iRet=Touch(lpPath, TRUE); + if(iRet!=0) + { + throw iRet; + } + + if(_taccess(lpPath, 0)==0) + { + return (int)0; + } + + strMsg.Format(c_FolderDoesNotExist, lpPath); + if(AfxMessageBox(strMsg, MB_YESNO|MB_ICONQUESTION) != IDYES) + { + return (int)-1; + } + + //create path + iRet=Touch(lpPath, FALSE); + if(iRet!=0) + { + throw iRet; + } + + return 0; + } + catch(int nErrCode) + { + switch(nErrCode) + { + case 1: + strMsg.Format(c_szErrInvalidPath, lpPath); + break; + case 2: + default: + strMsg.Format(c_szErrCreatePath, lpPath); + break; + } + + AfxMessageBox(strMsg, MB_OK|MB_ICONEXCLAMATION); + + } + + return iRet; +} + +//return 0: no error +//return 1: lpPath is invalid +//return 2: lpPath can not be created(bValidate==FALSE) +int CPathDialog::Touch(LPCTSTR lpPath, BOOL bValidate) +{ + if(lpPath==NULL) + { + return 1; + } + + TCHAR szPath[MAX_PATH]; + _tcscpy(szPath, lpPath); + int nLen = _tcslen(szPath); + + int i; + if(nLen==3) + { + if(!bValidate) + { + if(_access(szPath, 0)!=0) + { + return 2; + } + } + return 0; + } + + i = 3; + BOOL bLastOne=TRUE; + LPTSTR lpCurrentName; + while(szPath[i]!=0) + { + lpCurrentName = &szPath[i]; + while( (szPath[i]!=0) && (szPath[i]!=_T('\\')) ) + { + i++; + } + + bLastOne =(szPath[i]==0); + szPath[i] = 0; + + if(!bValidate) + { + CreateDirectory(szPath, NULL); + if(_taccess(szPath, 0)!=0) + { + return 2; + } + } + + if(bLastOne) + { + break; //it's done + } + else + { + szPath[i] = _T('\\'); + } + + i++; + } + + return (bLastOne?0:1); +} + +//return 0: ok +//return 1: error +int CPathDialog::ConcatPath(LPTSTR lpRoot, LPCTSTR lpMorePath) +{ + if(lpRoot==NULL) + { + return 1; + } + + int nLen = _tcslen(lpRoot); + + if(nLen<3) + { + return 1; + } + + if(lpMorePath==NULL) + { + return 0; + } + + if(nLen==3) + { + _tcscat(lpRoot, lpMorePath); + return 0; + } + + _tcscat(lpRoot, _T("\\")); + _tcscat(lpRoot, lpMorePath); + + return 0; +} diff --git a/Source/MFCDialog/PathDialog.h b/Source/MFCDialog/PathDialog.h new file mode 100644 index 000000000..6a184293a --- /dev/null +++ b/Source/MFCDialog/PathDialog.h @@ -0,0 +1,74 @@ +////////////////////////////////////////////////////////////////////////// +//PathDialog.h file +// +//Written by Nguyen Tan Hung +////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_PATHDIALOG_H__0F70BC86_11DB_11D4_B012_0000E8DD8DAA__INCLUDED_) +#define AFX_PATHDIALOG_H__0F70BC86_11DB_11D4_B012_0000E8DD8DAA__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PathDialog.h : header file +// +#include "shlobj.h" + +class CPathDialog; + +// CPathDialogSub - intercepts messages from child controls +class CPathDialogSub : public CWnd +{ + friend CPathDialog; +public: + CPathDialog* m_pPathDialog; +protected: + afx_msg void OnOK(); // OK button clicked + afx_msg void OnChangeEditPath(); + DECLARE_MESSAGE_MAP() +private: +}; + +///////////////////////////////////////////////////////////////////////////// +// CPathDialog dialog + +class CPathDialog +{ + friend CPathDialogSub; +// Construction +public: + CPathDialog(LPCTSTR lpszCaption=NULL, + LPCTSTR lpszTitle=NULL, + LPCTSTR lpszInitialPath=NULL, + CWnd* pParent = NULL); + + CString GetPathName(); + virtual int DoModal(); + + static Touch(LPCTSTR lpPath, BOOL bValidate=TRUE); + static int MakeSurePathExists(LPCTSTR lpPath); + static BOOL IsFileNameValid(LPCTSTR lpFileName); + static int ConcatPath(LPTSTR lpRoot, LPCTSTR lpMorePath); + +private: + static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam, LPARAM pData); + + LPCTSTR m_lpszCaption; + LPCTSTR m_lpszInitialPath; + + TCHAR m_szPathName[MAX_PATH]; + + BROWSEINFO m_bi; + HWND m_hWnd; + CWnd* m_pParentWnd; + BOOL m_bParentDisabled; + BOOL m_bGetSuccess; + + CPathDialogSub m_PathDialogSub; + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PATHDIALOG_H__0F70BC86_11DB_11D4_B012_0000E8DD8DAA__INCLUDED_) diff --git a/Source/MFCDialog/PropertyList.cpp b/Source/MFCDialog/PropertyList.cpp index 407278ea7..903ca456c 100644 --- a/Source/MFCDialog/PropertyList.cpp +++ b/Source/MFCDialog/PropertyList.cpp @@ -3,6 +3,7 @@ #include "stdafx.h" #include "PropertyList.h" +#include "PathDialog.h" #include "../cmCacheManager.h" #define IDC_PROPCMBBOX 712 @@ -366,20 +367,6 @@ void CPropertyList::OnCheckBox() m_Dirty = true; } -// Insane Microsoft way of setting the initial directory -// for the Shbrowseforfolder function... -// SetSelProc -// Callback procedure to set the initial selection of the browser. - -int CALLBACK SetSelProc( HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM - lpData ) -{ - if (uMsg==BFFM_INITIALIZED) - { - ::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData ); - } - return 0; -} void CPropertyList::OnButton() { @@ -471,24 +458,12 @@ void CPropertyList::OnButton() initialDir = currPath.Left(endSlash); } initialDir.Replace("/", "\\"); - char szPathName[4096]; - BROWSEINFO bi; - bi.lpfn = SetSelProc; - bi.lParam = (LPARAM)(LPCSTR) initialDir; - - bi.hwndOwner = m_hWnd; - bi.pidlRoot = NULL; - bi.pszDisplayName = (LPTSTR)szPathName; - bi.lpszTitle = "Select Directory"; - bi.ulFlags = BIF_EDITBOX | BIF_RETURNONLYFSDIRS; - - LPITEMIDLIST pidl = SHBrowseForFolder(&bi); - - BOOL bSuccess = SHGetPathFromIDList(pidl, szPathName); - CString SelectedFile; - if(bSuccess) + CString title = "Setting Cache Value: "; + title += pItem->m_propName; + CPathDialog dlg("Select Path", title, initialDir); + if(dlg.DoModal()==IDOK) { - SelectedFile = szPathName; + CString SelectedFile = dlg.GetPathName(); m_btnCtrl.ShowWindow(SW_HIDE); pItem->m_curValue = SelectedFile; m_Dirty = true;