core/vgui/impl/mfc/vgui_dir_dialog.cxx

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

Generated on Mon Mar 8 05:12:25 2010 for core/vgui by  doxygen 1.5.1