filelist.cpp 9.1 KB

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