home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / FILELIST.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  9.6 KB  |  350 lines

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