home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / filelist.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  9KB  |  331 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE1_SEG
  14. #pragma code_seg(AFX_CORE1_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // lpszCanon = C:\MYAPP\DEBUGS\C\TESWIN.C
  24. //
  25. // cchMax   b   Result
  26. // ------   -   ---------
  27. //  1- 7    F   <empty>
  28. //  1- 7    T   TESWIN.C
  29. //  8-14    x   TESWIN.C
  30. // 15-16    x   C:\...\TESWIN.C
  31. // 17-23    x   C:\...\C\TESWIN.C
  32. // 24-25    x   C:\...\DEBUGS\C\TESWIN.C
  33. // 26+      x   C:\MYAPP\DEBUGS\C\TESWIN.C
  34.  
  35. AFX_STATIC void AFXAPI _AfxAbbreviateName(LPTSTR lpszCanon, int cchMax, BOOL bAtLeastName)
  36. {
  37.     int cchFullPath, cchFileName, cchVolName;
  38.     const TCHAR* lpszCur;
  39.     const TCHAR* lpszBase;
  40.     const TCHAR* lpszFileName;
  41.  
  42.     lpszBase = lpszCanon;
  43.     cchFullPath = lstrlen(lpszCanon);
  44.  
  45.     cchFileName = AfxGetFileName(lpszCanon, NULL, 0) - 1;
  46.     lpszFileName = lpszBase + (cchFullPath-cchFileName);
  47.  
  48.     // If cchMax is more than enough to hold the full path name, we're done.
  49.     // This is probably a pretty common case, so we'll put it first.
  50.     if (cchMax >= cchFullPath)
  51.         return;
  52.  
  53.     // If cchMax isn't enough to hold at least the basename, we're done
  54.     if (cchMax < cchFileName)
  55.     {
  56.         lstrcpy(lpszCanon, (bAtLeastName) ? lpszFileName : &afxChNil);
  57.         return;
  58.     }
  59.  
  60.     // Calculate the length of the volume name.  Normally, this is two characters
  61.     // (e.g., "C:", "D:", etc.), but for a UNC name, it could be more (e.g.,
  62.     // "\\server\share").
  63.     //
  64.     // If cchMax isn't enough to hold at least <volume_name>\...\<base_name>, the
  65.     // result is the base filename.
  66.  
  67.     lpszCur = lpszBase + 2;                 // Skip "C:" or leading "\\"
  68.  
  69.     if (lpszBase[0] == '\\' && lpszBase[1] == '\\') // UNC pathname
  70.     {
  71.         // First skip to the '\' between the server name and the share name,
  72.         while (*lpszCur != '\\')
  73.         {
  74.             lpszCur = _tcsinc(lpszCur);
  75.             ASSERT(*lpszCur != '\0');
  76.         }
  77.     }
  78.     // if a UNC get the share name, if a drive get at least one directory
  79.     ASSERT(*lpszCur == '\\');
  80.     // make sure there is another directory, not just c:\filename.ext
  81.     if (cchFullPath - cchFileName > 3)
  82.     {
  83.         lpszCur = _tcsinc(lpszCur);
  84.         while (*lpszCur != '\\')
  85.         {
  86.             lpszCur = _tcsinc(lpszCur);
  87.             ASSERT(*lpszCur != '\0');
  88.         }
  89.     }
  90.     ASSERT(*lpszCur == '\\');
  91.  
  92.     cchVolName = lpszCur - lpszBase;
  93.     if (cchMax < cchVolName + 5 + cchFileName)
  94.     {
  95.         lstrcpy(lpszCanon, lpszFileName);
  96.         return;
  97.     }
  98.  
  99.     // Now loop through the remaining directory components until something
  100.     // of the form <volume_name>\...\<one_or_more_dirs>\<base_name> fits.
  101.     //
  102.     // Assert that the whole filename doesn't fit -- this should have been
  103.     // handled earlier.
  104.  
  105.     ASSERT(cchVolName + (int)lstrlen(lpszCur) > cchMax);
  106.     while (cchVolName + 4 + (int)lstrlen(lpszCur) > cchMax)
  107.     {
  108.         do
  109.         {
  110.             lpszCur = _tcsinc(lpszCur);
  111.             ASSERT(*lpszCur != '\0');
  112.         }
  113.         while (*lpszCur != '\\');
  114.     }
  115.  
  116.     // Form the resultant string and we're done.
  117.     lpszCanon[cchVolName] = '\0';
  118.     lstrcat(lpszCanon, _T("\\..."));
  119.     lstrcat(lpszCanon, lpszCur);
  120. }
  121.  
  122. /////////////////////////////////////////////////////////////////////////////
  123. // CRecentFileList
  124.  
  125. CRecentFileList::CRecentFileList(UINT nStart, LPCTSTR lpszSection,
  126.     LPCTSTR lpszEntryFormat, int nSize, int nMaxDispLen)
  127. {
  128.     ASSERT(nSize != 0);
  129.     m_arrNames = new CString[nSize];
  130.     m_nSize = nSize;
  131.  
  132.     m_nStart = nStart;
  133.     m_strSectionName = lpszSection;
  134.     m_strEntryFormat = lpszEntryFormat;
  135.     m_nMaxDisplayLength = nMaxDispLen;
  136. }
  137.  
  138. CRecentFileList::~CRecentFileList()
  139. {
  140.     delete[] m_arrNames;
  141. }
  142.  
  143. // Operations
  144. void CRecentFileList::Add(LPCTSTR lpszPathName)
  145. {
  146.     ASSERT(m_arrNames != NULL);
  147.     ASSERT(lpszPathName != NULL);
  148.     ASSERT(AfxIsValidString(lpszPathName));
  149.  
  150.     // fully qualify the path name
  151.     TCHAR szTemp[_MAX_PATH];
  152.     AfxFullPath(szTemp, lpszPathName);
  153.  
  154.     // update the MRU list, if an existing MRU string matches file name
  155.     for (int iMRU = 0; iMRU < m_nSize-1; iMRU++)
  156.     {
  157.         if (AfxComparePath(m_arrNames[iMRU], szTemp))
  158.             break;      // iMRU will point to matching entry
  159.     }
  160.     // move MRU strings before this one down
  161.     for (; iMRU > 0; iMRU--)
  162.     {
  163.         ASSERT(iMRU > 0);
  164.         ASSERT(iMRU < m_nSize);
  165.         m_arrNames[iMRU] = m_arrNames[iMRU-1];
  166.     }
  167.     // place this one at the beginning
  168.     m_arrNames[0] = szTemp;
  169. }
  170.  
  171. void CRecentFileList::Remove(int nIndex)
  172. {
  173.     ASSERT(nIndex >= 0);
  174.     ASSERT(nIndex < m_nSize);
  175.  
  176.     m_arrNames[nIndex].Empty();
  177.     for (int iMRU = nIndex; iMRU < m_nSize-1; iMRU++)
  178.         m_arrNames[iMRU] = m_arrNames[iMRU+1];
  179.  
  180.     ASSERT(iMRU < m_nSize);
  181.     m_arrNames[iMRU].Empty();
  182. }
  183.  
  184. BOOL CRecentFileList::GetDisplayName(CString& strName, int nIndex,
  185.     LPCTSTR lpszCurDir, int nCurDir, BOOL bAtLeastName) const
  186. {
  187.     ASSERT(lpszCurDir == NULL || AfxIsValidString(lpszCurDir, nCurDir));
  188.  
  189.     ASSERT(m_arrNames != NULL);
  190.     ASSERT(nIndex < m_nSize);
  191.     if (m_arrNames[nIndex].IsEmpty())
  192.         return FALSE;
  193.  
  194.     LPTSTR lpch = strName.GetBuffer(_MAX_PATH);
  195.     lstrcpy(lpch, m_arrNames[nIndex]);
  196.     // nLenDir is the length of the directory part of the full path
  197.     int nLenDir = lstrlen(lpch) - (AfxGetFileName(lpch, NULL, 0) - 1);
  198.     BOOL bSameDir = FALSE;
  199.     if (nLenDir == nCurDir)
  200.     {
  201.         TCHAR chSave = lpch[nLenDir];
  202.         lpch[nCurDir] = 0;  // terminate at same location as current dir
  203.         bSameDir = lstrcmpi(lpszCurDir, lpch) == 0;
  204.         lpch[nLenDir] = chSave;
  205.     }
  206.     // copy the full path, otherwise abbreviate the name
  207.     if (bSameDir)
  208.     {
  209.         // copy file name only since directories are same
  210.         TCHAR szTemp[_MAX_PATH];
  211.         AfxGetFileTitle(lpch+nCurDir, szTemp, _countof(szTemp));
  212.         lstrcpyn(lpch, szTemp, _MAX_PATH);
  213.     }
  214.     else if (m_nMaxDisplayLength != -1)
  215.     {
  216.         // strip the extension if the system calls for it
  217.         TCHAR szTemp[_MAX_PATH];
  218.         AfxGetFileTitle(lpch+nLenDir, szTemp, _countof(szTemp));
  219.         lstrcpyn(lpch+nLenDir, szTemp, _MAX_PATH-nLenDir);
  220.  
  221.         // abbreviate name based on what will fit in limited space
  222.         _AfxAbbreviateName(lpch, m_nMaxDisplayLength, bAtLeastName);
  223.     }
  224.     strName.ReleaseBuffer();
  225.     return TRUE;
  226. }
  227.  
  228. void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI)
  229. {
  230.     ASSERT(m_arrNames != NULL);
  231.  
  232.     CMenu* pMenu = pCmdUI->m_pMenu;
  233.     if (m_strOriginal.IsEmpty() && pMenu != NULL)
  234.         pMenu->GetMenuString(pCmdUI->m_nID, m_strOriginal, MF_BYCOMMAND);
  235.  
  236.     if (m_arrNames[0].IsEmpty())
  237.     {
  238.         // no MRU files
  239.         if (!m_strOriginal.IsEmpty())
  240.             pCmdUI->SetText(m_strOriginal);
  241.         pCmdUI->Enable(FALSE);
  242.         return;
  243.     }
  244.  
  245.     if (pCmdUI->m_pMenu == NULL)
  246.         return;
  247.  
  248.     for (int iMRU = 0; iMRU < m_nSize; iMRU++)
  249.         pCmdUI->m_pMenu->DeleteMenu(pCmdUI->m_nID + iMRU, MF_BYCOMMAND);
  250.  
  251.     TCHAR szCurDir[_MAX_PATH];
  252.     GetCurrentDirectory(_MAX_PATH, szCurDir);
  253.     int nCurDir = lstrlen(szCurDir);
  254.     ASSERT(nCurDir >= 0);
  255.     szCurDir[nCurDir] = '\\';
  256.     szCurDir[++nCurDir] = '\0';
  257.  
  258.     CString strName;
  259.     CString strTemp;
  260.     for (iMRU = 0; iMRU < m_nSize; iMRU++)
  261.     {
  262.         if (!GetDisplayName(strName, iMRU, szCurDir, nCurDir))
  263.             break;
  264.  
  265.         // double up any '&' characters so they are not underlined
  266.         LPCTSTR lpszSrc = strName;
  267.         LPTSTR lpszDest = strTemp.GetBuffer(strName.GetLength()*2);
  268.         while (*lpszSrc != 0)
  269.         {
  270.             if (*lpszSrc == '&')
  271.                 *lpszDest++ = '&';
  272.             if (_istlead(*lpszSrc))
  273.                 *lpszDest++ = *lpszSrc++;
  274.             *lpszDest++ = *lpszSrc++;
  275.         }
  276.         *lpszDest = 0;
  277.         strTemp.ReleaseBuffer();
  278.  
  279.         // insert mnemonic + the file name
  280.         TCHAR buf[10];
  281.         wsprintf(buf, _T("&%d "), (iMRU+1+m_nStart) % 10);
  282.         pCmdUI->m_pMenu->InsertMenu(pCmdUI->m_nIndex++,
  283.             MF_STRING | MF_BYPOSITION, pCmdUI->m_nID++,
  284.             CString(buf) + strTemp);
  285.     }
  286.  
  287.     // update end menu count
  288.     pCmdUI->m_nIndex--; // point to last menu added
  289.     pCmdUI->m_nIndexMax = pCmdUI->m_pMenu->GetMenuItemCount();
  290.  
  291.     pCmdUI->m_bEnableChanged = TRUE;    // all the added items are enabled
  292. }
  293.  
  294. void CRecentFileList::WriteList()
  295. {
  296.     ASSERT(m_arrNames != NULL);
  297.     ASSERT(!m_strSectionName.IsEmpty());
  298.     ASSERT(!m_strEntryFormat.IsEmpty());
  299.     LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
  300.     CWinApp* pApp = AfxGetApp();
  301.     pApp->WriteProfileString(m_strSectionName, NULL, NULL);
  302.     for (int iMRU = 0; iMRU < m_nSize; iMRU++)
  303.     {
  304.         wsprintf(pszEntry, m_strEntryFormat, iMRU + 1);
  305.         if (!m_arrNames[iMRU].IsEmpty())
  306.         {
  307.             pApp->WriteProfileString(m_strSectionName, pszEntry,
  308.                 m_arrNames[iMRU]);
  309.         }
  310.     }
  311.     delete[] pszEntry;
  312. }
  313.  
  314. void CRecentFileList::ReadList()
  315. {
  316.     ASSERT(m_arrNames != NULL);
  317.     ASSERT(!m_strSectionName.IsEmpty());
  318.     ASSERT(!m_strEntryFormat.IsEmpty());
  319.     LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
  320.     CWinApp* pApp = AfxGetApp();
  321.     for (int iMRU = 0; iMRU < m_nSize; iMRU++)
  322.     {
  323.         wsprintf(pszEntry, m_strEntryFormat, iMRU + 1);
  324.         m_arrNames[iMRU] = pApp->GetProfileString(
  325.             m_strSectionName, pszEntry, &afxChNil);
  326.     }
  327.     delete[] pszEntry;
  328. }
  329.  
  330. /////////////////////////////////////////////////////////////////////////////
  331.