mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.2 KiB
349 lines
9.2 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef AFX_CORE1_SEG
|
|
#pragma code_seg(AFX_CORE1_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
static void AbbreviateName(LPTSTR lpszCanon, int cchMax, BOOL bAtLeastName);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CRecentFileList
|
|
|
|
CRecentFileList::CRecentFileList(UINT nStart, LPCTSTR lpszSection,
|
|
LPCTSTR lpszEntryFormat, int nSize, int nMaxDispLen)
|
|
{
|
|
ASSERT(nSize != 0);
|
|
m_arrNames = new CString[nSize];
|
|
m_nSize = nSize;
|
|
|
|
m_nStart = nStart;
|
|
m_strSectionName = lpszSection;
|
|
m_strEntryFormat = lpszEntryFormat;
|
|
m_nMaxDisplayLength = nMaxDispLen;
|
|
}
|
|
|
|
CRecentFileList::~CRecentFileList()
|
|
{
|
|
delete[] m_arrNames;
|
|
}
|
|
|
|
// Operations
|
|
void CRecentFileList::Add(LPCTSTR lpszPathName)
|
|
{
|
|
ASSERT(m_arrNames != NULL);
|
|
ASSERT(lpszPathName != NULL);
|
|
ASSERT(AfxIsValidString(lpszPathName));
|
|
|
|
// fully qualify the path name
|
|
TCHAR szTemp[_MAX_PATH];
|
|
AfxFullPath(szTemp, lpszPathName);
|
|
|
|
// update the MRU list, if an existing MRU string matches file name
|
|
for (int iMRU = 0; iMRU < m_nSize-1; iMRU++)
|
|
{
|
|
if (AfxComparePath(m_arrNames[iMRU], szTemp))
|
|
break; // iMRU will point to matching entry
|
|
}
|
|
// move MRU strings before this one down
|
|
for (; iMRU > 0; iMRU--)
|
|
{
|
|
ASSERT(iMRU > 0);
|
|
ASSERT(iMRU < m_nSize);
|
|
m_arrNames[iMRU] = m_arrNames[iMRU-1];
|
|
}
|
|
// place this one at the beginning
|
|
m_arrNames[0] = lpszPathName;
|
|
}
|
|
|
|
void CRecentFileList::Remove(int nIndex)
|
|
{
|
|
ASSERT(nIndex >= 0);
|
|
ASSERT(nIndex < m_nSize);
|
|
|
|
m_arrNames[nIndex].Empty();
|
|
for (int iMRU = nIndex; iMRU < m_nSize-1; iMRU++)
|
|
m_arrNames[iMRU] = m_arrNames[iMRU+1];
|
|
|
|
ASSERT(iMRU < m_nSize);
|
|
m_arrNames[iMRU].Empty();
|
|
}
|
|
|
|
BOOL CRecentFileList::GetDisplayName(CString& strName, int nIndex,
|
|
LPCTSTR lpszCurDir, int nCurDir, BOOL bAtLeastName) const
|
|
{
|
|
UNUSED(nCurDir); // not used in release mac builds
|
|
UNUSED(lpszCurDir); // not used in release mac builds
|
|
ASSERT(lpszCurDir == NULL || AfxIsValidString(lpszCurDir, nCurDir));
|
|
|
|
ASSERT(m_arrNames != NULL);
|
|
ASSERT(nIndex < m_nSize);
|
|
if (m_arrNames[nIndex].IsEmpty())
|
|
return FALSE;
|
|
|
|
LPTSTR lpch = strName.GetBuffer(_MAX_PATH);
|
|
#ifndef _MAC
|
|
lstrcpy(lpch, m_arrNames[nIndex]);
|
|
// nLenDir is the length of the directory part of the full path
|
|
int nLenDir = lstrlen(lpch) - (AfxGetFileName(lpch, NULL, 0) - 1);
|
|
BOOL bSameDir = FALSE;
|
|
if (nLenDir == nCurDir)
|
|
{
|
|
TCHAR chSave = lpch[nLenDir];
|
|
lpch[nCurDir] = 0; // terminate at same location as current dir
|
|
bSameDir = lstrcmpi(lpszCurDir, lpch) == 0;
|
|
lpch[nLenDir] = chSave;
|
|
}
|
|
// copy the full path, otherwise abbreviate the name
|
|
if (bSameDir)
|
|
{
|
|
// copy file name only since directories are same
|
|
TCHAR szTemp[_MAX_PATH];
|
|
AfxGetFileTitle(lpch+nCurDir, szTemp, _countof(szTemp));
|
|
lstrcpyn(lpch, szTemp, _MAX_PATH);
|
|
}
|
|
else if (m_nMaxDisplayLength != -1)
|
|
{
|
|
// strip the extension if the system calls for it
|
|
TCHAR szTemp[_MAX_PATH];
|
|
AfxGetFileTitle(lpch+nLenDir, szTemp, _countof(szTemp));
|
|
lstrcpyn(lpch+nLenDir, szTemp, _MAX_PATH-nLenDir);
|
|
|
|
// abbreviate name based on what will fit in limited space
|
|
AbbreviateName(lpch, m_nMaxDisplayLength, bAtLeastName);
|
|
}
|
|
#else
|
|
UNUSED_ALWAYS(bAtLeastName);
|
|
|
|
// for Mac just show the file title name without path
|
|
AfxGetFileTitle(m_arrNames[nIndex], lpch, _MAX_PATH);
|
|
#endif
|
|
strName.ReleaseBuffer();
|
|
return TRUE;
|
|
}
|
|
|
|
void CRecentFileList::UpdateMenu(CCmdUI* pCmdUI)
|
|
{
|
|
ASSERT(m_arrNames != NULL);
|
|
|
|
CMenu* pMenu = pCmdUI->m_pMenu;
|
|
if (m_strOriginal.IsEmpty() && pMenu != NULL)
|
|
pMenu->GetMenuString(pCmdUI->m_nID, m_strOriginal, MF_BYCOMMAND);
|
|
|
|
if (m_arrNames[0].IsEmpty())
|
|
{
|
|
// no MRU files
|
|
if (!m_strOriginal.IsEmpty())
|
|
pCmdUI->SetText(m_strOriginal);
|
|
pCmdUI->Enable(FALSE);
|
|
return;
|
|
}
|
|
|
|
if (pCmdUI->m_pMenu == NULL)
|
|
return;
|
|
|
|
for (int iMRU = 0; iMRU < m_nSize; iMRU++)
|
|
pCmdUI->m_pMenu->DeleteMenu(pCmdUI->m_nID + iMRU, MF_BYCOMMAND);
|
|
|
|
#ifndef _MAC
|
|
TCHAR szCurDir[_MAX_PATH];
|
|
GetCurrentDirectory(_MAX_PATH, szCurDir);
|
|
int nCurDir = lstrlen(szCurDir);
|
|
ASSERT(nCurDir >= 0);
|
|
szCurDir[nCurDir] = '\\';
|
|
szCurDir[++nCurDir] = '\0';
|
|
#endif
|
|
|
|
CString strName;
|
|
CString strTemp;
|
|
for (iMRU = 0; iMRU < m_nSize; iMRU++)
|
|
{
|
|
#ifndef _MAC
|
|
if (!GetDisplayName(strName, iMRU, szCurDir, nCurDir))
|
|
break;
|
|
#else
|
|
if (!GetDisplayName(strName, iMRU, NULL, 0))
|
|
break;
|
|
#endif
|
|
// double up any '&' characters so they are not underlined
|
|
LPCTSTR lpszSrc = strName;
|
|
LPTSTR lpszDest = strTemp.GetBuffer(strName.GetLength()*2);
|
|
while (*lpszSrc != 0)
|
|
{
|
|
if (*lpszSrc == '&')
|
|
*lpszDest++ = '&';
|
|
if (_istlead(*lpszSrc))
|
|
*lpszDest++ = *lpszSrc++;
|
|
*lpszDest++ = *lpszSrc++;
|
|
}
|
|
*lpszDest = 0;
|
|
strTemp.ReleaseBuffer();
|
|
|
|
// insert mnemonic + the file name
|
|
TCHAR buf[10];
|
|
wsprintf(buf, _T("&%d "), (iMRU+1+m_nStart) % 10);
|
|
pCmdUI->m_pMenu->InsertMenu(pCmdUI->m_nIndex++,
|
|
MF_STRING | MF_BYPOSITION, pCmdUI->m_nID++,
|
|
CString(buf) + strTemp);
|
|
}
|
|
|
|
// update end menu count
|
|
pCmdUI->m_nIndex--; // point to last menu added
|
|
pCmdUI->m_nIndexMax = pCmdUI->m_pMenu->GetMenuItemCount();
|
|
|
|
pCmdUI->m_bEnableChanged = TRUE; // all the added items are enabled
|
|
}
|
|
|
|
void CRecentFileList::WriteList()
|
|
{
|
|
ASSERT(m_arrNames != NULL);
|
|
ASSERT(!m_strSectionName.IsEmpty());
|
|
ASSERT(!m_strEntryFormat.IsEmpty());
|
|
LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
|
|
CWinApp* pApp = AfxGetApp();
|
|
pApp->WriteProfileString(m_strSectionName, NULL, NULL);
|
|
for (int iMRU = 0; iMRU < m_nSize; iMRU++)
|
|
{
|
|
wsprintf(pszEntry, m_strEntryFormat, iMRU + 1);
|
|
if (!m_arrNames[iMRU].IsEmpty())
|
|
{
|
|
pApp->WriteProfileString(m_strSectionName, pszEntry,
|
|
m_arrNames[iMRU]);
|
|
}
|
|
}
|
|
delete[] pszEntry;
|
|
}
|
|
|
|
void CRecentFileList::ReadList()
|
|
{
|
|
ASSERT(m_arrNames != NULL);
|
|
ASSERT(!m_strSectionName.IsEmpty());
|
|
ASSERT(!m_strEntryFormat.IsEmpty());
|
|
LPTSTR pszEntry = new TCHAR[m_strEntryFormat.GetLength()+5];
|
|
CWinApp* pApp = AfxGetApp();
|
|
for (int iMRU = 0; iMRU < m_nSize; iMRU++)
|
|
{
|
|
wsprintf(pszEntry, m_strEntryFormat, iMRU + 1);
|
|
m_arrNames[iMRU] = pApp->GetProfileString(
|
|
m_strSectionName, pszEntry, &afxChNil);
|
|
}
|
|
delete[] pszEntry;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// lpszCanon = C:\MYAPP\DEBUGS\C\TESWIN.C
|
|
//
|
|
// cchMax b Result
|
|
// ------ - ---------
|
|
// 1- 7 F <empty>
|
|
// 1- 7 T TESWIN.C
|
|
// 8-14 x TESWIN.C
|
|
// 15-16 x C:\...\TESWIN.C
|
|
// 17-23 x C:\...\C\TESWIN.C
|
|
// 24-25 x C:\...\DEBUGS\C\TESWIN.C
|
|
// 26+ x C:\MYAPP\DEBUGS\C\TESWIN.C
|
|
|
|
#ifndef _MAC
|
|
static void AbbreviateName(LPTSTR lpszCanon, int cchMax, BOOL bAtLeastName)
|
|
{
|
|
int cchFullPath, cchFileName, cchVolName;
|
|
const TCHAR* lpszCur;
|
|
const TCHAR* lpszBase;
|
|
const TCHAR* lpszFileName;
|
|
|
|
lpszBase = lpszCanon;
|
|
cchFullPath = lstrlen(lpszCanon);
|
|
|
|
cchFileName = AfxGetFileName(lpszCanon, NULL, 0) - 1;
|
|
lpszFileName = lpszBase + (cchFullPath-cchFileName);
|
|
|
|
// If cchMax is more than enough to hold the full path name, we're done.
|
|
// This is probably a pretty common case, so we'll put it first.
|
|
if (cchMax >= cchFullPath)
|
|
return;
|
|
|
|
// If cchMax isn't enough to hold at least the basename, we're done
|
|
if (cchMax < cchFileName)
|
|
{
|
|
lstrcpy(lpszCanon, (bAtLeastName) ? lpszFileName : &afxChNil);
|
|
return;
|
|
}
|
|
|
|
// Calculate the length of the volume name. Normally, this is two characters
|
|
// (e.g., "C:", "D:", etc.), but for a UNC name, it could be more (e.g.,
|
|
// "\\server\share").
|
|
//
|
|
// If cchMax isn't enough to hold at least <volume_name>\...\<base_name>, the
|
|
// result is the base filename.
|
|
|
|
lpszCur = lpszBase + 2; // Skip "C:" or leading "\\"
|
|
|
|
if (lpszBase[0] == '\\' && lpszBase[1] == '\\') // UNC pathname
|
|
{
|
|
// First skip to the '\' between the server name and the share name,
|
|
while (*lpszCur != '\\')
|
|
{
|
|
lpszCur = _tcsinc(lpszCur);
|
|
ASSERT(*lpszCur != '\0');
|
|
}
|
|
}
|
|
// if a UNC get the share name, if a drive get at least one directory
|
|
ASSERT(*lpszCur == '\\');
|
|
// make sure there is another directory, not just c:\filename.ext
|
|
if (cchFullPath - cchFileName > 3)
|
|
{
|
|
lpszCur = _tcsinc(lpszCur);
|
|
while (*lpszCur != '\\')
|
|
{
|
|
lpszCur = _tcsinc(lpszCur);
|
|
ASSERT(*lpszCur != '\0');
|
|
}
|
|
}
|
|
ASSERT(*lpszCur == '\\');
|
|
|
|
cchVolName = lpszCur - lpszBase;
|
|
if (cchMax < cchVolName + 5 + cchFileName)
|
|
{
|
|
lstrcpy(lpszCanon, lpszFileName);
|
|
return;
|
|
}
|
|
|
|
// Now loop through the remaining directory components until something
|
|
// of the form <volume_name>\...\<one_or_more_dirs>\<base_name> fits.
|
|
//
|
|
// Assert that the whole filename doesn't fit -- this should have been
|
|
// handled earlier.
|
|
|
|
ASSERT(cchVolName + (int)lstrlen(lpszCur) > cchMax);
|
|
while (cchVolName + 4 + (int)lstrlen(lpszCur) > cchMax)
|
|
{
|
|
do
|
|
{
|
|
lpszCur = _tcsinc(lpszCur);
|
|
ASSERT(*lpszCur != '\0');
|
|
}
|
|
while (*lpszCur != '\\');
|
|
}
|
|
|
|
// Form the resultant string and we're done.
|
|
lpszCanon[cchVolName] = '\0';
|
|
lstrcat(lpszCanon, _T("\\..."));
|
|
lstrcat(lpszCanon, lpszCur);
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|