windows-nt/Source/XPSP1/NT/base/fs/hsm/gui/inc/rsutil.cpp

443 lines
11 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
<EFBFBD> 1998 Seagate Software, Inc. All rights reserved.
Module Name:
RsUtil.cpp
Abstract:
Utility functions for GUI
NOTENOTENOTENOTE:
Do not use any WSB functions in this file, as it is included in
recall notify which must run without WSB. It must also be able to
build as UNICODE or non-UNICODE
Author:
Art Bragg [abragg] 08-Aug-1997
Revision History:
--*/
#include "shlwapi.h"
#define HIDWORD(_qw) (DWORD)((_qw)>>32)
#define LODWORD(_qw) (DWORD)(_qw)
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
#define HINST_THISDLL AfxGetInstanceHandle()
// Local function prototypes
HRESULT ShortSizeFormat64(__int64 dw64, LPTSTR szBuf);
LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen);
HRESULT RsGuiFormatLongLong (
IN LONGLONG number,
IN BOOL bIncludeUnits,
OUT CString& sFormattedNumber)
/*++
Routine Description:
Formats a LONGLONG number into a locale-sensitive string with no decimal
fraction. Option is given for adding units at the end.
Arguments:
number I: Number to format
bIncludeUnits I: TRUE - add "bytes" at the end
sFormattedNumber O: Formatted number
Return Value:
S_OK - Success.
E_* - Failure occured
--*/
{
HRESULT hr = S_OK;
TCHAR sBuf [256];
TCHAR lpLCData [256];
TCHAR lpLCDataDecimal[256];
TCHAR lpLCDataThousand[256];
LPTSTR pBuffer;
int bufSize;
NUMBERFMT format;
try {
// Set up the parameters for the conversion function.
// Don't show fractions
format.NumDigits = 0;
// Get current setting for the rest of the parameters
WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_ILZERO, lpLCData, 256 ));
format.LeadingZero = _ttoi(lpLCData);
WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_SGROUPING, lpLCData, 256 ));
lpLCData[1] = 0;
format.Grouping = _ttoi(lpLCData);
WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_SDECIMAL, lpLCDataDecimal, 256 ));
format.lpDecimalSep = lpLCDataDecimal;
WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, lpLCDataThousand, 256 ));
format.lpThousandSep = lpLCDataThousand;
WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_INEGNUMBER, lpLCData, 256 ));
format.NegativeOrder = _ttoi(lpLCData);
// Convert the number to a non-localized string
_i64tot( number, sBuf, 10 );
// Get the size of the localized converted number
bufSize = GetNumberFormat (LOCALE_SYSTEM_DEFAULT, 0, sBuf, &format, NULL, 0);
WsbAffirmStatus (bufSize);
// Allocate the buffer in the CString
pBuffer = sFormattedNumber.GetBufferSetLength( bufSize );
// Convert non-localized string to a localized string
WsbAffirmStatus (GetNumberFormat (LOCALE_SYSTEM_DEFAULT, 0, sBuf, &format, pBuffer, bufSize));
// Release the CString buffer
sFormattedNumber.ReleaseBuffer (-1);
// If caller requested, append units
if (bIncludeUnits) {
sFormattedNumber = sFormattedNumber + L" bytes";
}
} WsbCatch (hr);
return hr;
}
HRESULT RsGuiFormatLongLong4Char (
IN LONGLONG number, // in bytes
OUT CString& sFormattedNumber)
/*++
Routine Description:
Formats a LONGLONG number into a locale-sensitive string that can be
displayed in 4 chars. Option is given for adding units at the end.
Arguments:
number I: Number to format
sFormattedNumber O: Formatted number
Return Value:
S_OK - Success.
E_* - Failure occured
--*/
{
// We call a function cloned from MS code
LPTSTR p;
p = sFormattedNumber.GetBuffer( 30 );
HRESULT hr = ShortSizeFormat64(number, p);
sFormattedNumber.ReleaseBuffer();
return hr;
}
const int pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
/* converts numbers into sort formats
* 532 -> 523 bytes
* 1340 -> 1.3KB
* 23506 -> 23.5KB
* -> 2.4MB
* -> 5.2GB
*/
// NOTE: This code is cloned from MS source /shell/shelldll/util.c - AHB
HRESULT ShortSizeFormat64(__int64 dw64, LPTSTR szBuf)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
int i;
UINT wInt, wLen, wDec;
TCHAR szTemp[10], szOrder[20], szFormat[5];
if (dw64 < 1000) {
wsprintf(szTemp, TEXT("%d"), LODWORD(dw64));
i = 0;
goto AddOrder;
}
for (i = 1; i<ARRAYSIZE(pwOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
/* do nothing */
wInt = LODWORD(dw64 >> 10);
AddCommas(wInt, szTemp, 10);
wLen = lstrlen(szTemp);
if (wLen < 3)
{
wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
// At this point, wDec should be between 0 and 1000
// we want get the top one (or two) digits.
wDec /= 10;
if (wLen == 2)
wDec /= 10;
// Note that we need to set the format before getting the
// intl char.
lstrcpy(szFormat, TEXT("%02d"));
szFormat[2] = (TCHAR)( TEXT('0') + 3 - wLen );
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
wLen = lstrlen(szTemp);
wLen += wsprintf(szTemp+wLen, szFormat, wDec);
}
AddOrder:
LoadString(HINST_THISDLL, pwOrders[i], szOrder, ARRAYSIZE(szOrder));
wsprintf(szBuf, szOrder, (LPTSTR)szTemp);
return S_OK;
}
void RsGuiMakeVolumeName (CString szName, CString szLabel, CString& szDisplayName)
/*++
Routine Description:
Formats a string showing the drive letter and volume label for a volume.
Arguments:
szName I: Name of volume i.e. "E:"
szLabel I: Volume label i.i "Art's Volume"
szDisplayName O: "Art's Volume (E:)"
Return Value: None
_* - Failure occured
--*/
{
szDisplayName.Format( TEXT ("%ls (%.1ls:)"), szLabel, szName );
}
// NOTE: This code is cloned from MS source /shell/shelldll/util.c - AHB
// takes a DWORD add commas etc to it and puts the result in the buffer
LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen)
{
TCHAR szTemp[20]; // more than enough for a DWORD
TCHAR szSep[5];
NUMBERFMT nfmt;
nfmt.NumDigits=0;
nfmt.LeadingZero=0;
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
nfmt.Grouping = _tcstol(szSep, NULL, 10);
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
nfmt.NegativeOrder= 0;
wsprintf(szTemp, TEXT("%lu"), dw);
if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, nResLen) == 0)
lstrcpy(pszResult, szTemp);
return pszResult;
}
CString RsGuiMakeShortString(
IN CDC* pDC,
IN const CString& StrLong,
IN int Width
)
/*++
Routine Description:
Determines if the supplied string fits in it's column. If not truncates
it and adds "...". From MS sample code.
Arguments:
pDC - Device context
str - Original String
width - Width of column
Return Value:
Shortened string
--*/
{
CString strShort = StrLong;
int stringLen = strShort.GetLength( );
//
// See if we need to shorten the string
//
if( ( stringLen > 0 ) &&
( pDC->GetTextExtent( strShort, stringLen ).cx > Width ) ) {
CString threeDots = _T("...");
int addLen = pDC->GetTextExtent( threeDots, threeDots.GetLength( ) ).cx;
for( int i = stringLen - 1; i > 0; i-- ) {
if( ( pDC->GetTextExtent( strShort, i ).cx + addLen ) <= Width ) {
break;
}
}
strShort = strShort.Left( i ) + threeDots;
}
return( strShort );
}
/////////////////////////////////////////////////////////////////////////////
// CRsGuiOneLiner
CRsGuiOneLiner::CRsGuiOneLiner()
{
m_pToolTip = 0;
}
CRsGuiOneLiner::~CRsGuiOneLiner()
{
EnableToolTip( FALSE );
}
BEGIN_MESSAGE_MAP(CRsGuiOneLiner, CStatic)
//{{AFX_MSG_MAP(CRsGuiOneLiner)
//}}AFX_MSG_MAP
ON_MESSAGE( WM_SETTEXT, OnSetText )
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRsGuiOneLiner message handlers
LRESULT
CRsGuiOneLiner::OnSetText(
WPARAM /*wParam*/,
LPARAM lParam
)
{
LRESULT lResult = 0;
ASSERT(lParam == 0 || AfxIsValidString((LPCTSTR)lParam));
m_LongTitle = (LPCTSTR)lParam;
m_Title = m_LongTitle;
//
// See if this is too long to show, and shorten if so
//
CRect rect;
GetClientRect( &rect );
CDC* pDc = GetDC( );
if( pDc ) {
CFont* pFont = GetFont( );
CFont* pSaveFont = pDc->SelectObject( pFont );
if( pSaveFont ) {
m_Title = RsGuiMakeShortString( pDc, m_LongTitle, rect.right );
pDc->SelectObject( pSaveFont );
}
ReleaseDC( pDc );
}
if( m_hWnd ) {
lResult = DefWindowProc( WM_SETTEXT, 0, (LPARAM)(LPCTSTR)m_Title );
}
//
// Enable the tooltip if the titles are not the same
//
EnableToolTip( m_Title != m_LongTitle, m_LongTitle );
return( lResult );
}
void CRsGuiOneLiner::EnableToolTip( BOOL Enable, const TCHAR* pTipText )
{
if( Enable ) {
//
// Make sure the tooltip does not exist before creating new one
//
EnableToolTip( FALSE );
m_pToolTip = new CToolTipCtrl;
if( m_pToolTip ) {
m_pToolTip->Create( this );
//
// Can't use the CToolTipCtrl methods for adding tool
// since these tie the control into sending messages
// to the parent, and don't allow subclassing option
//
// BTW, the subclassing option allows the control to
// automatically see our messages. Otherwise, we have
// to go through complicated message interception and
// relaying these to the tooltip (which doesn't work
// anyway)
//
TOOLINFO ti;
ZeroMemory( &ti, sizeof( ti ) );
ti.cbSize = sizeof( ti );
ti.uFlags = TTF_IDISHWND|TTF_CENTERTIP|TTF_SUBCLASS;
ti.hwnd = GetSafeHwnd( );
ti.uId = (WPARAM)GetSafeHwnd( );
ti.lpszText = (LPTSTR)(LPCTSTR)pTipText;
m_pToolTip->SendMessage( TTM_ADDTOOL, 0, (LPARAM)&ti );
//
// Set delays so that the tooltip comes up right away
// and doesn't go away until 15 seconds.
//
m_pToolTip->SendMessage( TTM_SETDELAYTIME, TTDT_AUTOPOP, 15000 );
m_pToolTip->SendMessage( TTM_SETDELAYTIME, TTDT_INITIAL, 0 );
//
// And activate and top the tooltip
//
m_pToolTip->Activate( TRUE );
m_pToolTip->SetWindowPos( &wndTop, 0, 0, 0, 0,
SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER );
}
} else if( !Enable && m_pToolTip ) {
m_pToolTip->Activate( FALSE );
delete m_pToolTip;
m_pToolTip = 0;
}
}