Leaked source code of windows server 2003
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.

442 lines
12 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. RsUtil.cpp
  5. Abstract:
  6. Utility functions for GUI
  7. NOTENOTENOTENOTE:
  8. Do not use any WSB functions in this file, as it is included in
  9. recall notify which must run without WSB. It must also be able to
  10. build as UNICODE or non-UNICODE
  11. Author:
  12. Art Bragg [abragg] 08-Aug-1997
  13. Revision History:
  14. --*/
  15. #include "shlwapi.h"
  16. #define HIDWORD(_qw) (DWORD)((_qw)>>32)
  17. #define LODWORD(_qw) (DWORD)(_qw)
  18. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  19. #define HINST_THISDLL AfxGetInstanceHandle()
  20. // Local function prototypes
  21. HRESULT ShortSizeFormat64(__int64 dw64, LPTSTR szBuf);
  22. LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen);
  23. HRESULT RsGuiFormatLongLong (
  24. IN LONGLONG number,
  25. IN BOOL bIncludeUnits,
  26. OUT CString& sFormattedNumber)
  27. /*++
  28. Routine Description:
  29. Formats a LONGLONG number into a locale-sensitive string with no decimal
  30. fraction. Option is given for adding units at the end.
  31. Arguments:
  32. number I: Number to format
  33. bIncludeUnits I: TRUE - add "bytes" at the end
  34. sFormattedNumber O: Formatted number
  35. Return Value:
  36. S_OK - Success.
  37. E_* - Failure occured
  38. --*/
  39. {
  40. HRESULT hr = S_OK;
  41. TCHAR sBuf [256];
  42. TCHAR lpLCData [256];
  43. TCHAR lpLCDataDecimal[256];
  44. TCHAR lpLCDataThousand[256];
  45. LPTSTR pBuffer;
  46. int bufSize;
  47. NUMBERFMT format;
  48. try {
  49. // Set up the parameters for the conversion function.
  50. // Don't show fractions
  51. format.NumDigits = 0;
  52. // Get current setting for the rest of the parameters
  53. WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_ILZERO, lpLCData, 256 ));
  54. format.LeadingZero = _ttoi(lpLCData);
  55. WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_SGROUPING, lpLCData, 256 ));
  56. lpLCData[1] = 0;
  57. format.Grouping = _ttoi(lpLCData);
  58. WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_SDECIMAL, lpLCDataDecimal, 256 ));
  59. format.lpDecimalSep = lpLCDataDecimal;
  60. WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, lpLCDataThousand, 256 ));
  61. format.lpThousandSep = lpLCDataThousand;
  62. WsbAffirmStatus (GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_INEGNUMBER, lpLCData, 256 ));
  63. format.NegativeOrder = _ttoi(lpLCData);
  64. // Convert the number to a non-localized string
  65. _i64tot( number, sBuf, 10 );
  66. // Get the size of the localized converted number
  67. bufSize = GetNumberFormat (LOCALE_SYSTEM_DEFAULT, 0, sBuf, &format, NULL, 0);
  68. WsbAffirmStatus (bufSize);
  69. // Allocate the buffer in the CString
  70. pBuffer = sFormattedNumber.GetBufferSetLength( bufSize );
  71. // Convert non-localized string to a localized string
  72. WsbAffirmStatus (GetNumberFormat (LOCALE_SYSTEM_DEFAULT, 0, sBuf, &format, pBuffer, bufSize));
  73. // Release the CString buffer
  74. sFormattedNumber.ReleaseBuffer (-1);
  75. // If caller requested, append units
  76. if (bIncludeUnits) {
  77. sFormattedNumber = sFormattedNumber + L" bytes";
  78. }
  79. } WsbCatch (hr);
  80. return hr;
  81. }
  82. HRESULT RsGuiFormatLongLong4Char (
  83. IN LONGLONG number, // in bytes
  84. OUT CString& sFormattedNumber)
  85. /*++
  86. Routine Description:
  87. Formats a LONGLONG number into a locale-sensitive string that can be
  88. displayed in 4 chars. Option is given for adding units at the end.
  89. Arguments:
  90. number I: Number to format
  91. sFormattedNumber O: Formatted number
  92. Return Value:
  93. S_OK - Success.
  94. E_* - Failure occured
  95. --*/
  96. {
  97. // We call a function cloned from MS code
  98. LPTSTR p;
  99. p = sFormattedNumber.GetBuffer( 30 );
  100. HRESULT hr = ShortSizeFormat64(number, p);
  101. sFormattedNumber.ReleaseBuffer();
  102. return hr;
  103. }
  104. const int pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
  105. IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
  106. /* converts numbers into sort formats
  107. * 532 -> 523 bytes
  108. * 1340 -> 1.3KB
  109. * 23506 -> 23.5KB
  110. * -> 2.4MB
  111. * -> 5.2GB
  112. */
  113. // NOTE: This code is cloned from MS source /shell/shelldll/util.c - AHB
  114. HRESULT ShortSizeFormat64(__int64 dw64, LPTSTR szBuf)
  115. {
  116. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  117. int i;
  118. UINT wInt, wLen, wDec;
  119. TCHAR szTemp[10], szOrder[20], szFormat[5];
  120. if (dw64 < 1000) {
  121. wsprintf(szTemp, TEXT("%d"), LODWORD(dw64));
  122. i = 0;
  123. goto AddOrder;
  124. }
  125. for (i = 1; i<ARRAYSIZE(pwOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
  126. /* do nothing */
  127. wInt = LODWORD(dw64 >> 10);
  128. AddCommas(wInt, szTemp, 10);
  129. wLen = lstrlen(szTemp);
  130. if (wLen < 3)
  131. {
  132. wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
  133. // At this point, wDec should be between 0 and 1000
  134. // we want get the top one (or two) digits.
  135. wDec /= 10;
  136. if (wLen == 2)
  137. wDec /= 10;
  138. // Note that we need to set the format before getting the
  139. // intl char.
  140. lstrcpy(szFormat, TEXT("%02d"));
  141. szFormat[2] = (TCHAR)( TEXT('0') + 3 - wLen );
  142. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  143. szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
  144. wLen = lstrlen(szTemp);
  145. wLen += wsprintf(szTemp+wLen, szFormat, wDec);
  146. }
  147. AddOrder:
  148. LoadString(HINST_THISDLL, pwOrders[i], szOrder, ARRAYSIZE(szOrder));
  149. wsprintf(szBuf, szOrder, (LPTSTR)szTemp);
  150. return S_OK;
  151. }
  152. void RsGuiMakeVolumeName (CString szName, CString szLabel, CString& szDisplayName)
  153. /*++
  154. Routine Description:
  155. Formats a string showing the drive letter and volume label for a volume.
  156. Arguments:
  157. szName I: Name of volume i.e. "E:"
  158. szLabel I: Volume label i.i "Art's Volume"
  159. szDisplayName O: "Art's Volume (E:)"
  160. Return Value: None
  161. _* - Failure occured
  162. --*/
  163. {
  164. szDisplayName.Format( TEXT ("%ls (%.1ls:)"), szLabel, szName );
  165. }
  166. // NOTE: This code is cloned from MS source /shell/shelldll/util.c - AHB
  167. // takes a DWORD add commas etc to it and puts the result in the buffer
  168. LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen)
  169. {
  170. TCHAR szTemp[20]; // more than enough for a DWORD
  171. TCHAR szSep[5];
  172. NUMBERFMT nfmt;
  173. nfmt.NumDigits=0;
  174. nfmt.LeadingZero=0;
  175. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
  176. nfmt.Grouping = _tcstol(szSep, NULL, 10);
  177. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  178. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  179. nfmt.NegativeOrder= 0;
  180. wsprintf(szTemp, TEXT("%lu"), dw);
  181. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, nResLen) == 0)
  182. lstrcpy(pszResult, szTemp);
  183. return pszResult;
  184. }
  185. CString RsGuiMakeShortString(
  186. IN CDC* pDC,
  187. IN const CString& StrLong,
  188. IN int Width
  189. )
  190. /*++
  191. Routine Description:
  192. Determines if the supplied string fits in it's column. If not truncates
  193. it and adds "...". From MS sample code.
  194. Arguments:
  195. pDC - Device context
  196. str - Original String
  197. width - Width of column
  198. Return Value:
  199. Shortened string
  200. --*/
  201. {
  202. CString strShort = StrLong;
  203. int stringLen = strShort.GetLength( );
  204. //
  205. // See if we need to shorten the string
  206. //
  207. if( ( stringLen > 0 ) &&
  208. ( pDC->GetTextExtent( strShort, stringLen ).cx > Width ) ) {
  209. CString threeDots = _T("...");
  210. int addLen = pDC->GetTextExtent( threeDots, threeDots.GetLength( ) ).cx;
  211. for( int i = stringLen - 1; i > 0; i-- ) {
  212. if( ( pDC->GetTextExtent( strShort, i ).cx + addLen ) <= Width ) {
  213. break;
  214. }
  215. }
  216. strShort = strShort.Left( i ) + threeDots;
  217. }
  218. return( strShort );
  219. }
  220. /////////////////////////////////////////////////////////////////////////////
  221. // CRsGuiOneLiner
  222. CRsGuiOneLiner::CRsGuiOneLiner()
  223. {
  224. m_pToolTip = 0;
  225. }
  226. CRsGuiOneLiner::~CRsGuiOneLiner()
  227. {
  228. EnableToolTip( FALSE );
  229. }
  230. BEGIN_MESSAGE_MAP(CRsGuiOneLiner, CStatic)
  231. //{{AFX_MSG_MAP(CRsGuiOneLiner)
  232. //}}AFX_MSG_MAP
  233. ON_MESSAGE( WM_SETTEXT, OnSetText )
  234. END_MESSAGE_MAP()
  235. /////////////////////////////////////////////////////////////////////////////
  236. // CRsGuiOneLiner message handlers
  237. LRESULT
  238. CRsGuiOneLiner::OnSetText(
  239. WPARAM /*wParam*/,
  240. LPARAM lParam
  241. )
  242. {
  243. LRESULT lResult = 0;
  244. ASSERT(lParam == 0 || AfxIsValidString((LPCTSTR)lParam));
  245. m_LongTitle = (LPCTSTR)lParam;
  246. m_Title = m_LongTitle;
  247. //
  248. // See if this is too long to show, and shorten if so
  249. //
  250. CRect rect;
  251. GetClientRect( &rect );
  252. CDC* pDc = GetDC( );
  253. if( pDc ) {
  254. CFont* pFont = GetFont( );
  255. CFont* pSaveFont = pDc->SelectObject( pFont );
  256. if( pSaveFont ) {
  257. m_Title = RsGuiMakeShortString( pDc, m_LongTitle, rect.right );
  258. pDc->SelectObject( pSaveFont );
  259. }
  260. ReleaseDC( pDc );
  261. }
  262. if( m_hWnd ) {
  263. lResult = DefWindowProc( WM_SETTEXT, 0, (LPARAM)(LPCTSTR)m_Title );
  264. }
  265. //
  266. // Enable the tooltip if the titles are not the same
  267. //
  268. EnableToolTip( m_Title != m_LongTitle, m_LongTitle );
  269. return( lResult );
  270. }
  271. void CRsGuiOneLiner::EnableToolTip( BOOL Enable, const TCHAR* pTipText )
  272. {
  273. if( Enable ) {
  274. //
  275. // Make sure the tooltip does not exist before creating new one
  276. //
  277. EnableToolTip( FALSE );
  278. m_pToolTip = new CToolTipCtrl;
  279. if( m_pToolTip ) {
  280. m_pToolTip->Create( this );
  281. //
  282. // Can't use the CToolTipCtrl methods for adding tool
  283. // since these tie the control into sending messages
  284. // to the parent, and don't allow subclassing option
  285. //
  286. // BTW, the subclassing option allows the control to
  287. // automatically see our messages. Otherwise, we have
  288. // to go through complicated message interception and
  289. // relaying these to the tooltip (which doesn't work
  290. // anyway)
  291. //
  292. TOOLINFO ti;
  293. ZeroMemory( &ti, sizeof( ti ) );
  294. ti.cbSize = sizeof( ti );
  295. ti.uFlags = TTF_IDISHWND|TTF_CENTERTIP|TTF_SUBCLASS;
  296. ti.hwnd = GetSafeHwnd( );
  297. ti.uId = (WPARAM)GetSafeHwnd( );
  298. ti.lpszText = (LPTSTR)(LPCTSTR)pTipText;
  299. m_pToolTip->SendMessage( TTM_ADDTOOL, 0, (LPARAM)&ti );
  300. //
  301. // Set delays so that the tooltip comes up right away
  302. // and doesn't go away until 15 seconds.
  303. //
  304. m_pToolTip->SendMessage( TTM_SETDELAYTIME, TTDT_AUTOPOP, 15000 );
  305. m_pToolTip->SendMessage( TTM_SETDELAYTIME, TTDT_INITIAL, 0 );
  306. //
  307. // And activate and top the tooltip
  308. //
  309. m_pToolTip->Activate( TRUE );
  310. m_pToolTip->SetWindowPos( &wndTop, 0, 0, 0, 0,
  311. SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER );
  312. }
  313. } else if( !Enable && m_pToolTip ) {
  314. m_pToolTip->Activate( FALSE );
  315. delete m_pToolTip;
  316. m_pToolTip = 0;
  317. }
  318. }