GME
13
|
00001 // DirDialog.cpp - implements class CDirDialog 00002 00003 // The CDirDialog class implements a directory selection dialog by deriving from the file 00004 // selection dialog class (CFileDialog). This dialog has the advantages of the standard 00005 // file open dialog (resizeable, ability to create/delete directories etc) but is 00006 // customized for the selection of a directory rather than a file. 00007 // 00008 // USER INTERFACE 00009 // -------------- 00010 // 00011 // For example, the user can double click on a directory name or type it into the 00012 // edit control to open it in the directory listing display. To say that this is 00013 // the directory they want the user must click the "Open" button. When the user 00014 // enters a backslash (\) as the last character in the edit control the display is 00015 // changed to show the contents of the directory if it exists. The same is done if 00016 // the user presses the Enter key except that if the directory does not exist the 00017 // user is asked if they want to create it. 00018 // 00019 // When the user enters other characters and the contents don't end in a backslash 00020 // then automatic directory name completion is attempted. If the contents of the 00021 // edit box are the first character(s) of one unique existing directory then the 00022 // rest of the directory name is added to the end of the edit box. These characters 00023 // are selected so that the user can type something else and it they will be ignored. 00024 // 00025 // When selecting a directory you would normally not want to see files, but you may on 00026 // occasion. The normal "Files of Type:" drop down list is available but it has an 00027 // extra entry "Show Folders Only" that is selected by default. When files are 00028 // displayed double clicking of them is ignored (unlike the normal File Open dialog). 00029 // Double-clicking a directory name changes to that directory as normal. 00030 // 00031 // PROGRAMMER INTERFACE 00032 // -------------------- 00033 // 00034 // Add DirDialog.cpp and DirDialog.h to your project. Include DirDialog.h 00035 // in the source file(s) where you want to use the CDirDialog class. 00036 // 00037 // Create a CDirDialog object using the constructor described below. If necessary 00038 // you may then modify values in the m_ofn member of the CFileDialog base class 00039 // (see the Win32 documentation for OPENFILENAME). For example, to change the 00040 // text that appears in the title bar of the dialog use m_ofn.lpstrTitle. 00041 // 00042 // Call DoModal() to activate the dialog. If DoModal() return IDOK you can then 00043 // call GetPath() to obtain the name of the directory that the user selected. 00044 // 00045 // 00046 // CDirDialog::CDirDialog(LPCTSTR lpstrInitialDir = NULL, 00047 // LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL); 00048 // 00049 // lpstrInitialDir 00050 // The initial directory. If NULL then the current directory is used. 00051 // See lpstrInitialDir in the Win32 documentation for OPENFILENAME for more info. 00052 // 00053 // lpszFilter 00054 // The string pairs that specify the file filters to use. See lpszFilter 00055 // in the documentation for the CFileDialog constructor for more info. 00056 // Note that an extra entry is always added that allows the user to hide the 00057 // display of all files. If NULL is used (the default) then only the 00058 // "no files" entry and an "all files" entry are provided. 00059 // 00060 // pParentWnd 00061 // A pointer to the dialog parent window. 00062 // 00063 // virtual int CDirDialog::DoModal() 00064 // 00065 // see CFileDialog::DoModal(). 00066 // 00067 // CString CDirDialog::GetPath() 00068 // 00069 // return value 00070 // The full path name chosen by the user. 00071 // 00072 // Example: 00073 // 00074 // // Called when the Browse button is clicked in CMyDialog 00075 // void CMyDialog::OnBrowseDir() 00076 // { 00077 // if (!UpdateData(TRUE)) // Update current value of m_dir from control 00078 // return; 00079 // 00080 // CDirDialog dlg(m_dir, 00081 // "JPEG Files (*.jpg; *.jpeg)|*.jpg;*.jpeg|All Files (*.*)|*.*||", 00082 // this); 00083 // dlg.m_ofn.lpstrTitle = "Select Folder to Store Images"; 00084 // 00085 // if (dlg.DoModal() == IDOK) 00086 // { 00087 // m_dir = dlg.GetPath(); // Store selected directory name back into the control 00088 // UpdateData(FALSE); 00089 // } 00090 // } 00091 // 00092 // 00093 // INTERNAL DESIGN 00094 // --------------- 00095 // 00096 // The following changes are made to the controls in the standard file open dialog: 00097 // 00098 // The "Open" button is hidden and replaced with another button (IDC_OPEN). 00099 // The normal edit control (edt1) where the file name is entered is hidden and replaced 00100 // by a "subclassed" edit control (IDC_DIR) of class CDirEdit (derived from CEdit). 00101 // By hiding and replacing these controls we can manipulate the behaviour 00102 // of the dialog in ways not provided for in any other way. For example, by changing 00103 // the contents of the hidden edit control (edt1) and simulating a click of the hidden 00104 // Open button (IDOK) we can force the contents of a directory to be displayed. 00105 // 00106 // An extra entry is added to the file types drop down combo called "Show Folders Only" 00107 // that causes no files to be displayed. (If no filters are supplied at all by using 00108 // the default value of NULL, then an "All Files" filter type is also added.) 00109 // The filter string is a single dot (full-stop) which will match no files. 00110 // 00111 // The new edit control (IDC_DIR) is subclassed so that the contents are monitored and 00112 // the some keys can be intercepted. When the contents are changed and they end with 00113 // a backslash the current display is changed to point to the directory entered (if it 00114 // exists). When return is pressed the directory is also changed, but if it doesn't 00115 // exist then the user is asked if he wants to create it. The way the directory is 00116 // changed (ie. the files of that directory are shown in the display) is by putting the 00117 // directory name into the original edit control (edt1) and simulating a click of the 00118 // original Open button (IDOK). Directory name completion is also performed as the 00119 // user types in a directory name. 00120 // 00121 // The IDC_OPEN button is used as a replacement for the IDOK button while still allowing 00122 // the hidden IDOK button to be used to change the displayed directory. 00123 // 00124 // The CDirDialog class is derived from CFileDialog. The following base class members 00125 // are overridden: 00126 // - OnInitDone: so that the dialog controls can be reorganized 00127 // - OnFolderChange: so that when the user clicks on a folder name the edit control can 00128 // be updated to reflect the name of the currently selected directory 00129 // - OnFileNameOK: always returns TRUE so that the user can't select files by 00130 // double-clicking them (this is a DIRECTORY selection dialog after all) 00131 00132 00133 #include "stdafx.h" 00134 00135 // If you don't want this as part of your project (eg to put in a library) remove 00136 // the above #include "stdafx.h" and uncomment the following 3 lines: 00137 //#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 00138 //#include <afxwin.h> // MFC core and standard components 00139 //#include <afxext.h> // MFC extensions 00140 00141 #include <Dlgs.h> // For file dialog control IDs 00142 #include <imagehlp.h> // For ::MakeSureDirectoryPathExists() 00143 00144 #include "DirDialog.h" // Our own header file 00145 00146 #ifdef _DEBUG 00147 #define new DEBUG_NEW 00148 #undef THIS_FILE 00149 static char THIS_FILE[] = __FILE__; 00150 #endif 00151 00152 #define IDC_DIR 181 // New edit control for entering the directory name 00153 #define IDC_OPEN 182 // New "Open" button 00154 00155 // Class CDlgWnd 00156 BEGIN_MESSAGE_MAP(CDlgWnd, CWnd) 00157 ON_BN_CLICKED(IDC_OPEN, OnOpen) 00158 END_MESSAGE_MAP() 00159 00160 void CDlgWnd::OnOpen() 00161 { 00162 // Get the text and check whether it is a valid directory 00163 CString ss; 00164 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_DIR); 00165 ASSERT(pEdit != NULL); 00166 pEdit->GetWindowText(ss); 00167 int len = ss.GetLength(); 00168 00169 if (len == 2 && ss[0] == '\\' && ss[1] == '\\') 00170 { 00171 AfxMessageBox(ss + _T("\nThis is not a valid folder.")); 00172 pEdit->SetFocus(); 00173 return; 00174 } 00175 else if (len == 0 || len == 1 && ss[0] == '\\') 00176 { 00177 // Current directory or root of the current drive (therefore must be valid) 00178 ; 00179 } 00180 else if ((len == 2 && ss[1] == ':') || 00181 (len == 3 && ss[1] == ':' && ss[2] == '\\') ) 00182 { 00183 _TCHAR rootdir[4] = _T("?:\\"); 00184 rootdir[0] = ss[0]; 00185 00186 if (GetDriveType(rootdir) <= DRIVE_NO_ROOT_DIR) 00187 { 00188 AfxMessageBox(ss + _T("\nThe drive is invalid.")); 00189 pEdit->SetFocus(); 00190 return; 00191 } 00192 } 00193 else 00194 { 00195 // Check that it's a valid directory 00196 if (ss[len-1] == '\\') 00197 ss = ss.Left(--len); 00198 DWORD attr = GetFileAttributes(ss); 00199 if (attr == 0xFFFFFFFF) 00200 { 00201 const TCHAR *ss2; 00202 00203 // Directory not found but maybe it's an invalid drive 00204 _TCHAR rootdir[4] = _T("?:\\"); 00205 rootdir[0] = ss[0]; 00206 00207 if (len > 1 && ss[1] == ':' && GetDriveType(rootdir) <= DRIVE_NO_ROOT_DIR) 00208 { 00209 AfxMessageBox(ss + _T("\nThe drive is invalid.")); 00210 pEdit->SetFocus(); 00211 return; 00212 } 00213 else if (len >= 2 && ss[0] == '\\' && ss[1] == '\\' && 00214 ( (ss2 = _tcschr((const TCHAR *)ss+2, '\\')) == NULL || _tcschr(ss2+1, '\\') == NULL) ) 00215 { 00216 AfxMessageBox(ss + _T("\nThis is not a valid folder.")); 00217 pEdit->SetFocus(); 00218 return; 00219 } 00220 else 00221 { 00222 // Appears to be a valid drive (or relative path) 00223 CString mess(ss); 00224 mess += _T("\nThis folder does not exist.\n\n") 00225 _T("Do you want to create it?"); 00226 if (AfxMessageBox(mess, MB_YESNO) == IDYES) 00227 { 00228 if (!::SHCreateDirectoryEx(NULL, ss + _T("\\"), NULL)) 00229 { 00230 switch (GetDriveType(rootdir)) 00231 { 00232 case DRIVE_CDROM: 00233 AfxMessageBox(_T("You cannot create this folder\n") 00234 _T("as the CD ROM medium is read-only.")); 00235 break; 00236 case DRIVE_REMOVABLE: 00237 AfxMessageBox(_T("You cannot create this folder.\n") 00238 _T("The medium may be write-protected.")); 00239 break; 00240 case DRIVE_REMOTE: 00241 AfxMessageBox(_T("You do not have permission to create\n") 00242 _T("this folder on the network.")); 00243 break; 00244 default: 00245 AfxMessageBox(_T("You do not have permission\n") 00246 _T("to create this folder.")); 00247 break; 00248 } 00249 pEdit->SetFocus(); 00250 return; // Directory could not be created 00251 } 00252 // directory was created, so continue 00253 } 00254 else 00255 { 00256 pEdit->SetFocus(); 00257 return; // User did not want to create directory 00258 } 00259 } 00260 } 00261 else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) 00262 { 00263 AfxMessageBox(ss + _T("\nThis is a file not a directory.")); 00264 pEdit->SetFocus(); 00265 return; 00266 } 00267 } 00268 00269 // We have now selected a directory and will return from the dialog 00270 CheckDir(ss); 00271 00272 ::EndDialog(m_hWnd, IDOK); 00273 } 00274 00275 // This routine updates the directory/file list display using the directory 00276 // name given. It does this by putting the name in the (hidden) edit control 00277 // and simulating a press of the (hidden) IDOK button. If the directory is 00278 // invalid in some way the currently displayed list will not be changed and 00279 // some sort of error message may be displayed. 00280 void CDlgWnd::CheckDir(const CString &ss) 00281 { 00282 // Put the new directory into the old (hidden) edit box 00283 CEdit *pOld = (CEdit *)GetDlgItem(edt1); 00284 ASSERT(pOld != NULL); 00285 pOld->SetWindowText(ss); 00286 00287 // Save the current text/selection in the edit control 00288 CString strSaved; // Current text in edit box 00289 int start, end; // Current selection in edit box 00290 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_DIR); 00291 ASSERT(pEdit != NULL); 00292 pEdit->GetWindowText(strSaved); 00293 pEdit->GetSel(start, end); 00294 00295 CWnd *pOK = GetDlgItem(IDOK); 00296 pOK->SendMessage(WM_LBUTTONDOWN); 00297 pOK->SendMessage(WM_LBUTTONUP); 00298 00299 CString strNew; 00300 pEdit->GetWindowText(strNew); 00301 00302 // Usually we want to keep what the user has typed (strSaved) rather than what has been 00303 // put in the edit control due to OnFolderChange. One exception is if the user has 00304 // used "..", "..." etc to change to an ancestor directory in which case we don't want to 00305 // leave this the same as it will cause repeated changes to ancestor directories whenever 00306 // the user types backslash (\). Also don;t set the edit string back to what the user 00307 // typed if it would be empty or unchanged except for case (as the case probably looks 00308 // better the way it was filled in). 00309 if (strSaved.IsEmpty() || strSaved[0] == '.' || 00310 strNew.CompareNoCase(strSaved) == 0 || strNew.CompareNoCase(strSaved + '\\') == 0) 00311 { 00312 pEdit->SetSel(strNew.GetLength(), -1); 00313 } 00314 else 00315 { 00316 // Restore the edit control the way the user typed it 00317 pEdit->SetWindowText(strSaved); 00318 pEdit->SetSel(start, end); 00319 } 00320 } 00321 // --- class CDlgWnd --- 00322 00323 // CDirEdit control class 00324 BEGIN_MESSAGE_MAP(CDirEdit, CEdit) 00325 ON_WM_CHAR() 00326 ON_WM_KEYDOWN() 00327 ON_WM_GETDLGCODE() 00328 END_MESSAGE_MAP() 00329 00330 void CDirEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 00331 { 00332 CDlgWnd *pp; // Parent = the dialog itself 00333 VERIFY(pp = (CDlgWnd *)GetParent()); 00334 00335 if (nChar == '\t') 00336 { 00337 // Because we are getting all keys (see OnGetDlgCode()) so that we can get the Return key, 00338 // we also get the tab key as a side-effect. This means that the tabbing between controls 00339 // in the dialog will stop at the edit control unless we force it to go to the next control. 00340 CWnd *pWnd = pp->GetDlgItem(IDC_OPEN); 00341 ASSERT(pWnd != NULL); 00342 pWnd->SetFocus(); // Set focus to Open button 00343 } 00344 else if (nChar == '\r' || nChar == '\n') 00345 { 00346 // If return key is pressed we change to the directory specified OR 00347 // if the directory name appears valid but does not exist we ask the 00348 // user if they want to create it. Note that the string is not 00349 // validated (although some validation may be done by Windows 00350 // via the CheckDir() call). The name is only checked to see if 00351 // it is possible that a directory needs to be created. 00352 // Full validation is deferred till the "Open" button is clicked. 00353 00354 CString ss; 00355 GetWindowText(ss); 00356 int len = ss.GetLength(); 00357 00358 // Remove trailing backslash unless root directory or network root 00359 if (_tcscmp(ss,_T("\\")) != 0 && _tcscmp(ss,_T("\\\\")) != 0 && _tcscmp((const TCHAR *)ss+1,_T(":\\")) != 0 && 00360 len > 0 && ss[len-1] == '\\' ) 00361 { 00362 ss = ss.Left(--len); 00363 } 00364 00365 if (len == 0 || 00366 len == 1 && ss[0] == '\\' || 00367 len >= 2 && ss[0] == '\\' && ss[1] == '\\' && _tcschr((const TCHAR *)ss+2, '\\') == NULL || 00368 len == 2 && ss[1] == ':' || 00369 len == 3 && ss[1] == ':' && ss[2] == '\\' ) 00370 { 00371 // Definitely not a createable directory 00372 pp->CheckDir(ss); 00373 } 00374 else 00375 { 00376 // Check if it's an existing directory 00377 CFileStatus fs; 00378 00379 DWORD attr = GetFileAttributes(ss); 00380 if (attr == 0xFFFFFFFF) 00381 { 00382 // Directory not found but maybe it's an invalid drive 00383 _TCHAR rootdir[4] = _T("?:\\"); 00384 rootdir[0] = ss[0]; 00385 00386 if (len == 1 || (len > 1 && ss[1] != ':') || 00387 GetDriveType(rootdir) > DRIVE_NO_ROOT_DIR) 00388 { 00389 // Appears to be a valid drive (or relative path) 00390 CString mess(ss); 00391 mess += _T("\nThis folder does not exist.\n\n") 00392 _T("Do you want to create it?"); 00393 if (AfxMessageBox(mess, MB_YESNO) == IDYES) 00394 { 00395 if (!::SHCreateDirectoryEx(NULL, ss + _T("\\"), NULL)) 00396 { 00397 switch (GetDriveType(rootdir)) 00398 { 00399 case DRIVE_CDROM: 00400 AfxMessageBox(_T("You cannot create this folder\n") 00401 _T("as the CD ROM medium is read-only.")); 00402 break; 00403 case DRIVE_REMOVABLE: 00404 AfxMessageBox(_T("You cannot create this folder.\n") 00405 _T("The medium may be write-protected.")); 00406 break; 00407 case DRIVE_REMOTE: 00408 AfxMessageBox(_T("You do not have permission to create\n") 00409 _T("this folder on the network.")); 00410 break; 00411 default: 00412 AfxMessageBox(_T("You do not have permission or\n") 00413 _T("otherwise cannot create this folder.")); 00414 break; 00415 } 00416 return; 00417 } 00418 } 00419 else 00420 return; 00421 } 00422 } 00423 pp->CheckDir(ss); 00424 // Make sure the directory name ends with backslash so user can type sub-drectory name 00425 GetWindowText(ss); 00426 if (ss[ss.GetLength()-1] != '\\') 00427 { 00428 ss += _T("\\"); 00429 SetWindowText(ss); 00430 } 00431 SetSel(ss.GetLength(), -1); 00432 } 00433 SetFocus(); // Make sure caret stays in this edit control 00434 } 00435 else 00436 { 00437 CEdit::OnChar(nChar, nRepCnt, nFlags); 00438 00439 // Get the text and check whether it is a valid directory 00440 CString ss; // Current text in the edit control 00441 GetWindowText(ss); 00442 00443 int len = ss.GetLength(); 00444 int start, end; // Current selection 00445 GetSel(start, end); 00446 00447 if (ss.Compare(_T("\\\\")) == 0) 00448 { 00449 // Don't check \\ else we get a message about "\\" being an invalid filename 00450 ; 00451 } 00452 else if (ss.Compare(_T("\\")) == 0) 00453 { 00454 // Show root directory 00455 pp->CheckDir(ss); 00456 } 00457 else if (len == 3 && ss[1] == ':' && ss[2] == '\\') 00458 { 00459 // Check that it's a valid drive 00460 if (GetDriveType(ss) > DRIVE_NO_ROOT_DIR) 00461 { 00462 pp->CheckDir(ss); 00463 } 00464 } 00465 else if (len > 0 && ss[len-1] == '\\') 00466 { 00467 // Check that it's a valid directory 00468 // xxx does not handle "\\anwar\" 00469 DWORD attr = GetFileAttributes(ss); 00470 if (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) 00471 { 00472 pp->CheckDir(ss); 00473 } 00474 } 00475 else if (start == len && nChar != '\b') 00476 { 00477 // Try to do completion of the directory name 00478 CFileFind ff; // Used to find directory names that start with ss 00479 int count = 0; // Number of matching directory names 00480 CString strMatch; // The last directory found that matches 00481 00482 BOOL bContinue = ff.FindFile(ss + _T("*")); 00483 00484 while (bContinue) 00485 { 00486 // At least one match - check them all 00487 bContinue = ff.FindNextFile(); 00488 00489 if (ff.IsDirectory()) 00490 { 00491 // Found a matching directory 00492 ++count; 00493 strMatch = ff.GetFileName(); 00494 } 00495 } 00496 00497 // If there was exactly one matching directory use it 00498 if (count == 1) 00499 { 00500 int ii; 00501 // The file open dialog changes all uppercase names to lower case with an initial 00502 // capital (eg WINDOWS displays as Windows). We do the same so things look nicer. 00503 for (ii = 0; ii < strMatch.GetLength(); ++ii) 00504 { 00505 // Don't change if it contains spaces or lowercase letters 00506 if (isspace(strMatch[ii]) || islower(strMatch[ii])) 00507 break; 00508 } 00509 00510 ASSERT(ii <= strMatch.GetLength()); 00511 if (!strMatch.IsEmpty() && ii == strMatch.GetLength()) 00512 { 00513 CString temp = strMatch.Mid(1); 00514 temp.MakeLower(); 00515 strMatch = strMatch.Left(1) + temp; 00516 } 00517 00518 00519 // Get the bit of the directory name that the user has not yet typed 00520 int lb_len; // Length of last bit (after \ or :) 00521 lb_len = ss.ReverseFind('\\'); 00522 if (lb_len == -1) lb_len = ss.ReverseFind('/'); 00523 if (lb_len == -1) lb_len = ss.ReverseFind(':'); 00524 if (lb_len == -1) 00525 lb_len = ss.GetLength(); 00526 else 00527 lb_len = ss.GetLength() - (lb_len+1); 00528 00529 // Check if the last char is the same case as the same char in the matched name 00530 if (!ss.IsEmpty() && lb_len > 0 && strMatch[lb_len-1] != ss[ss.GetLength()-1]) 00531 { 00532 // The user used different case to that of the corresponding character in 00533 // the matched directory so change the matched name to be the user's case. 00534 if (isupper(ss[ss.GetLength()-1])) 00535 strMatch.MakeUpper(); 00536 else 00537 strMatch.MakeLower(); 00538 } 00539 00540 #ifdef _DEBUG 00541 CString temp = strMatch.Left(lb_len); 00542 ASSERT(temp.CompareNoCase(ss.Right(lb_len)) == 0); 00543 #endif 00544 end += strMatch.GetLength() - lb_len; 00545 SetWindowText(ss + strMatch.Mid(lb_len)); 00546 SetSel(start, end); 00547 } 00548 00549 // else if (count > 1) pop-up some sort of selection list??? 00550 } 00551 SetFocus(); // Make sure caret stays in this edit control 00552 } 00553 } 00554 00555 void CDirEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 00556 { 00557 CEdit::OnKeyDown(nChar, nRepCnt, nFlags); 00558 00559 if (nChar != VK_DELETE) 00560 return; 00561 00562 CDlgWnd *pp; // Parent = the dialog itself 00563 VERIFY(pp = (CDlgWnd *)GetParent()); 00564 00565 // Get the current text and check whether it is a valid directory 00566 CString ss; 00567 GetWindowText(ss); 00568 int len = ss.GetLength(); 00569 00570 if (ss.Compare(_T("\\\\")) == 0) 00571 { 00572 // Don't check \\ else we get a message about "\\" being an invalid filename 00573 ; 00574 } 00575 else if (ss.Compare(_T("\\")) == 0) 00576 { 00577 // Show root directory 00578 pp->CheckDir(ss); 00579 } 00580 else if (len == 3 && ss[1] == ':' && ss[2] == '\\') 00581 { 00582 // Check that it's a valid drive 00583 if (GetDriveType(ss) > DRIVE_NO_ROOT_DIR) 00584 { 00585 pp->CheckDir(ss); 00586 } 00587 } 00588 else if (len > 0 && ss[len-1] == '\\') 00589 { 00590 // Check that it's a valid directory 00591 DWORD attr = GetFileAttributes(ss); 00592 if (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) 00593 { 00594 pp->CheckDir(ss); 00595 } 00596 } 00597 SetFocus(); // Make sure caret stays in this edit control 00598 } 00599 00600 UINT CDirEdit::OnGetDlgCode() 00601 { 00602 // Get all keys so that we see CR 00603 return CEdit::OnGetDlgCode() | DLGC_WANTALLKEYS; 00604 } 00605 // --- class CDirEdit --- 00606 00607 // class CDirDialog 00608 CDirDialog::CDirDialog(LPCTSTR initial, LPCTSTR filter, CWnd* pParentWnd) 00609 : CFileDialog(TRUE, NULL, NULL, 00610 /*OFN_ENABLEHOOK | OFN_EXPLORER |*/ OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST, 00611 NULL, pParentWnd) 00612 , m_strPath(initial) 00613 { 00614 // Note: m_strFilter is a member variable so it doesn't disappear because 00615 // it is used later internally by the file open dialog (via m_ofn.lpstrFilter). 00616 if (filter != NULL) 00617 m_strFilter = CString(_T("Show Folders Only|.|")) + filter; 00618 else 00619 m_strFilter = _T("Show Folders Only|.|All Files (*.*)|*.*||"); 00620 m_strFilter.Replace('|', '\0'); 00621 m_ofn.lpstrFilter = m_strFilter; 00622 00623 m_ofn.lpstrInitialDir = initial; 00624 00625 m_ofn.lpstrTitle = _T("Select Folder"); 00626 } 00627 00628 void CDirDialog::OnInitDone() 00629 { 00630 CRect rct; // Used to move/resize controls 00631 CWnd *pp; // Parent = the dialog window itself 00632 VERIFY(pp = GetParent()); 00633 00634 ASSERT(pp->GetDlgItem(stc3) != NULL); 00635 pp->GetDlgItem(stc3)->SetWindowText(_T("Folder:")); 00636 00637 // Create a new CDlgWnd so we can catch dialog control notifications 00638 ASSERT( m_DlgWnd.GetSafeHwnd() == NULL); 00639 00640 VERIFY(m_DlgWnd.SubclassWindow(pp->m_hWnd)); 00641 00642 // Create a new edit control where edt1 now is 00643 ASSERT(pp->GetDlgItem(edt1) != NULL); 00644 pp->GetDlgItem(edt1)->GetWindowRect(rct); //Get edt1 rectangle 00645 pp->ScreenToClient(rct); // crash 00646 00647 VERIFY(m_Edit.Create(WS_TABSTOP | WS_VISIBLE | WS_CHILD, 00648 rct, pp, IDC_DIR)); 00649 if (m_ofn.lpstrInitialDir != NULL) 00650 m_Edit.SetWindowText(m_ofn.lpstrInitialDir); 00651 m_Edit.SetFont(pp->GetDlgItem(edt1)->GetFont()); 00652 m_Edit.ModifyStyleEx(0, WS_EX_CLIENTEDGE, SWP_DRAWFRAME); 00653 m_Edit.SetWindowPos(pp->GetDlgItem(stc3), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 00654 // m_Edit.SetSel(0, strlen(m_ofn.lpstrInitialDir)); 00655 00656 CWnd *pCancel = pp->GetDlgItem(IDCANCEL); 00657 ASSERT(pCancel != NULL); 00658 00659 // Create a new button where the OK button now is 00660 ASSERT(pp->GetDlgItem(IDOK) != NULL); 00661 pp->GetDlgItem(IDOK)->GetWindowRect(rct); //Get OK button rectangle 00662 pp->ScreenToClient(rct); 00663 00664 m_Open.Create(_T("Open"), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 00665 rct, pp, IDC_OPEN); 00666 m_Open.SetFont(pp->GetDlgItem(IDOK)->GetFont()); 00667 m_Open.SetWindowPos(&m_Edit, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 00668 00669 pCancel->SetWindowPos(&m_Open, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 00670 00671 // Change default push button 00672 pp->GetDlgItem(IDOK)->ModifyStyle(BS_DEFPUSHBUTTON, 0); 00673 pp->SendMessage(DM_SETDEFID, IDC_OPEN); 00674 00675 #define DIRDIALOG_TESTING 00676 #ifdef DIRDIALOG_TESTING 00677 // Move controls (rather than hide them) for testing 00678 00679 // Increase size of dialog 00680 pp->GetWindowRect(rct); 00681 pp->SetWindowPos(NULL, 0, 0, rct.Width(), rct.Height() + 70, SWP_NOZORDER | SWP_NOMOVE); 00682 00683 // Move the replaced controls down 00684 ASSERT(pp->GetDlgItem(IDOK) != NULL); 00685 pp->GetDlgItem(IDOK)->GetWindowRect(rct); 00686 pp->ScreenToClient(rct); 00687 pp->GetDlgItem(IDOK)->SetWindowPos(NULL, rct.left, rct.top+70, 00688 0, 0, SWP_NOZORDER | SWP_NOSIZE); 00689 00690 ASSERT(pp->GetDlgItem(edt1) != NULL); 00691 pp->GetDlgItem(edt1)->GetWindowRect(rct); 00692 pp->ScreenToClient(rct); 00693 pp->GetDlgItem(edt1)->SetWindowPos(NULL, rct.left, rct.top+70, 00694 0, 0, SWP_NOZORDER | SWP_NOSIZE); 00695 00696 #else 00697 // Hide the controls we don't want the user to use 00698 HideControl(IDOK); 00699 HideControl(edt1); 00700 #endif 00701 00702 CFileDialog::OnInitDone(); 00703 } 00704 00705 void CDirDialog::OnFolderChange() 00706 { 00707 CWnd *pp; // Parent window = the dialog itself 00708 VERIFY(pp = GetParent()); 00709 ASSERT(::IsWindow(pp->m_hWnd)); 00710 00711 ASSERT(pp->GetDlgItem(IDC_DIR) != NULL); 00712 m_strPath = GetFolderPath(); 00713 int len = m_strPath.GetLength(); 00714 if (len > 0 && m_strPath[len-1] != '\\') 00715 { 00716 m_strPath += _T("\\"); 00717 ++len; 00718 } 00719 pp->GetDlgItem(IDC_DIR)->SetWindowText(m_strPath); 00720 m_Edit.SetSel(len, len); 00721 00722 CFileDialog::OnFolderChange(); 00723 00724 m_Edit.SetFocus(); 00725 }