SPPPropertyGridItemExt.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /********************************************
  2. ** 工作室:S&P工作室
  3. ** 作者 :张东斌
  4. ** 日期 :2007年6月
  5. *********************************************/
  6. #include "StdAfx.h"
  7. #include <math.h>
  8. #include "SPVC80Helpers.h"
  9. #include "SPPropertyGridInplaceEdit.h"
  10. #include "SPPropertyGridInplaceButton.h"
  11. #include "SPPropertyGridInplaceList.h"
  12. #include "SPPropertyGridItem.h"
  13. #include "SPPropertyGridItemExt.h"
  14. #include "SPPropertyGrid.h"
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. //////////////////////////////////////////////////////////////////////////
  21. BEGIN_MESSAGE_MAP(CSPPropertyGridInplaceMonthCal, CWnd)
  22. ON_NOTIFY_REFLECT(MCN_SELECT, OnSelect)
  23. END_MESSAGE_MAP()
  24. void CSPPropertyGridInplaceMonthCal::OnSelect( NMHDR * , LRESULT * )
  25. {
  26. OnAccept();
  27. }
  28. void CSPPropertyGridInplaceMonthCal::OnAccept()
  29. {
  30. SYSTEMTIME sysTime;
  31. ::SendMessage( m_hWnd,MCM_GETCURSEL,0,( LPARAM ) & sysTime );
  32. sysTime.wHour = sysTime.wMinute = sysTime.wSecond = sysTime.wMilliseconds = 0;
  33. COleDateTime dtSelected ( sysTime );
  34. CString str = dtSelected.Format( m_pItem->m_strFormat );
  35. CSPPropertyGridItemDate * pItem = m_pItem;
  36. DestroyWindow();
  37. pItem->OnValueChanged( str );
  38. }
  39. void CSPPropertyGridInplaceMonthCal::PostNcDestroy()
  40. {
  41. delete this;
  42. }
  43. BOOL CSPPropertyGridInplaceMonthCal::OnWndMsg( UINT message , WPARAM wParam , LPARAM lParam , LRESULT * pResult )
  44. {
  45. if ( message == WM_KILLFOCUS )
  46. {
  47. CWnd * pWnd = CWnd::FromHandle( ( HWND ) wParam );
  48. if ( pWnd && IsChild( pWnd ) )
  49. {
  50. return CWnd::OnWndMsg( message,wParam,lParam,pResult );
  51. }
  52. DestroyWindow();
  53. return TRUE;
  54. }
  55. if ( message == WM_KEYDOWN && wParam == VK_ESCAPE )
  56. {
  57. DestroyWindow();
  58. return TRUE;
  59. }
  60. if ( message == WM_KEYDOWN && wParam == VK_RETURN )
  61. {
  62. OnAccept();
  63. return TRUE;
  64. }
  65. return CWnd::OnWndMsg( message,wParam,lParam,pResult );
  66. }
  67. CSPPropertyGridItemDate::CSPPropertyGridItemDate( CString strCaption , COleDateTime & oleDate ) : CSPPropertyGridItem( strCaption )
  68. {
  69. Init( oleDate );
  70. }
  71. CSPPropertyGridItemDate::CSPPropertyGridItemDate( UINT nID , COleDateTime & oleDate ) : CSPPropertyGridItem( nID )
  72. {
  73. Init( oleDate );
  74. }
  75. void CSPPropertyGridItemDate::Init( COleDateTime & oleDate )
  76. {
  77. m_nFlags = SPGridItemHasComboButton | SPGridItemHasEdit;
  78. m_strFormat = _T( "%d/%m/%Y" );
  79. m_strValue = _T( "00/00/0000" );
  80. SetMask( _T( "00/00/0000" ),_T( "__/__/____" ) );
  81. SetDate( oleDate );
  82. EnableAutomation();
  83. }
  84. BOOL CSPPropertyGridItemDate::ParseDateTime( COleDateTime & dt , CString strValue )
  85. {
  86. SYSTEMTIME sysTime;
  87. ZeroMemory( &sysTime,sizeof( SYSTEMTIME ) );
  88. WORD * ptrDate[3] ={0, 0, 0};
  89. int nResult[3] ={0, 0, 0};
  90. CString strFormat ( m_strFormat );
  91. strFormat.MakeLower();
  92. int nIndex = -1, i = 0;
  93. for ( i = 0; i < 3; i ++ )
  94. {
  95. nIndex = strFormat.Find( _T( '%' ),nIndex + 1 );
  96. if ( nIndex == -1 || nIndex == strFormat.GetLength() - 1 )
  97. return FALSE;
  98. switch ( strFormat[nIndex + 1] )
  99. {
  100. case _T('d'):
  101. ptrDate[i] = &sysTime.wDay; break;
  102. case _T('y'):
  103. ptrDate[i] = &sysTime.wYear; break;
  104. case _T('m'):
  105. ptrDate[i] = &sysTime.wMonth; break;
  106. default:
  107. return FALSE;
  108. }
  109. strFormat.SetAt( nIndex + 1,_T( 'd' ) );
  110. }
  111. if ( SCANF_S( strValue,strFormat,&nResult[0],&nResult[1],&nResult[2] ) != 3 )
  112. {
  113. return FALSE;
  114. }
  115. for ( i = 0; i < 3; i++ )
  116. {
  117. if ( !ptrDate[i] )
  118. return FALSE;
  119. *ptrDate[i] = ( WORD ) nResult[i];
  120. }
  121. dt = sysTime;
  122. return dt.GetStatus() == COleDateTime::valid;
  123. }
  124. void CSPPropertyGridItemDate::SetValue( CString strValue )
  125. {
  126. COleDateTime dt;
  127. TRY
  128. {
  129. if ( ParseDateTime( dt,strValue ) )
  130. {
  131. SetDate( dt );
  132. }
  133. else if ( dt.ParseDateTime( strValue,VAR_DATEVALUEONLY,LANG_RUSSIAN ) )
  134. {
  135. SetDate( dt );
  136. }
  137. }
  138. CATCH( COleException,e )
  139. {
  140. }
  141. END_CATCH
  142. }
  143. void CSPPropertyGridItemDate::SetDateFormat( CString strFormat )
  144. {
  145. m_strFormat = strFormat;
  146. CString strValue = m_oleDate.Format( m_strFormat );
  147. CSPPropertyGridItem::SetValue( strValue );
  148. }
  149. void CSPPropertyGridItemDate::SetDate( const COleDateTime & oleDate )
  150. {
  151. ASSERT( oleDate.GetStatus() == COleDateTime::valid );
  152. m_oleDate = oleDate;
  153. CString strValue = oleDate.Format( m_strFormat );
  154. CSPPropertyGridItem::SetValue( strValue );
  155. }
  156. #if _MSC_VER < 1200 // MFC 5.0
  157. #define MIN_DATE (-657434L) // about year 100
  158. #define MAX_DATE 2958465L // about year 9999
  159. #define HALF_SECOND (1.0/172800.0)
  160. static int nMonthDays[13] ={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
  161. static BOOL SPPropetryGridTmFromOleDate( DATE dtSrc , struct tm & tmDest )
  162. {
  163. // The legal range does not actually span year 0 to 9999.
  164. if ( dtSrc > MAX_DATE || dtSrc < MIN_DATE ) // about year 100 to about 9999
  165. {
  166. return FALSE;
  167. }
  168. long nDays; // Number of days since Dec. 30, 1899
  169. long nDaysAbsolute; // Number of days since 1/1/0
  170. long nSecsInDay; // Time in seconds since midnight
  171. long nMinutesInDay; // Minutes in day
  172. long n400Years; // Number of 400 year increments since 1/1/0
  173. long n400Century; // Century within 400 year block (0,1,2 or 3)
  174. long n4Years; // Number of 4 year increments since 1/1/0
  175. long n4Day; // Day within 4 year block
  176. // (0 is 1/1/yr1, 1460 is 12/31/yr4)
  177. long n4Yr; // Year within 4 year block (0,1,2 or 3)
  178. BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year
  179. double dblDate = dtSrc; // temporary serial date
  180. // If a valid date, then this conversion should not overflow
  181. nDays = ( long ) dblDate;
  182. // Round to the second
  183. dblDate += ( ( dtSrc > 0.0 ) ? HALF_SECOND : -HALF_SECOND );
  184. nDaysAbsolute = ( long ) dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899
  185. dblDate = fabs( dblDate );
  186. nSecsInDay = ( long ) ( ( dblDate - floor( dblDate ) ) * 86400. );
  187. // Calculate the day of week (sun=1, mon=2...)
  188. // -1 because 1/1/0 is Sat. +1 because we want 1-based
  189. tmDest.tm_wday = ( int ) ( ( nDaysAbsolute - 1 ) % 7L ) + 1;
  190. // Leap years every 4 yrs except centuries not multiples of 400.
  191. n400Years = ( long ) ( nDaysAbsolute / 146097L );
  192. // Set nDaysAbsolute to day within 400-year block
  193. nDaysAbsolute %= 146097L;
  194. // -1 because first century has extra day
  195. n400Century = ( long ) ( ( nDaysAbsolute - 1 ) / 36524L );
  196. // Non-leap century
  197. if ( n400Century != 0 )
  198. {
  199. // Set nDaysAbsolute to day within century
  200. nDaysAbsolute = ( nDaysAbsolute - 1 ) % 36524L;
  201. // +1 because 1st 4 year increment has 1460 days
  202. n4Years = ( long ) ( ( nDaysAbsolute + 1 ) / 1461L );
  203. if ( n4Years != 0 )
  204. n4Day = ( long ) ( ( nDaysAbsolute + 1 ) % 1461L );
  205. else
  206. {
  207. bLeap4 = FALSE;
  208. n4Day = ( long ) nDaysAbsolute;
  209. }
  210. }
  211. else
  212. {
  213. // Leap century - not special case!
  214. n4Years = ( long ) ( nDaysAbsolute / 1461L );
  215. n4Day = ( long ) ( nDaysAbsolute % 1461L );
  216. }
  217. if ( bLeap4 )
  218. {
  219. // -1 because first year has 366 days
  220. n4Yr = ( n4Day - 1 ) / 365;
  221. if ( n4Yr != 0 )
  222. n4Day = ( n4Day - 1 ) % 365;
  223. }
  224. else
  225. {
  226. n4Yr = n4Day / 365;
  227. n4Day %= 365;
  228. }
  229. // n4Day is now 0-based day of year. Save 1-based day of year, year number
  230. tmDest.tm_yday = ( int ) n4Day + 1;
  231. tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;
  232. // Handle leap year: before, on, and after Feb. 29.
  233. if ( n4Yr == 0 && bLeap4 )
  234. {
  235. // Leap Year
  236. if ( n4Day == 59 )
  237. {
  238. /* Feb. 29 */
  239. tmDest.tm_mon = 2;
  240. tmDest.tm_mday = 29;
  241. goto DoTime;
  242. }
  243. // Pretend it's not a leap year for month/day comp.
  244. if ( n4Day >= 60 )
  245. --n4Day;
  246. }
  247. // Make n4DaY a 1-based day of non-leap year and compute
  248. // month/day for everything but Feb. 29.
  249. ++n4Day;
  250. // Month number always >= n/32, so save some loop time */
  251. for ( tmDest.tm_mon = ( n4Day >> 5 ) + 1; n4Day > nMonthDays[tmDest.tm_mon]; tmDest.tm_mon++ )
  252. ;
  253. tmDest.tm_mday = ( int ) ( n4Day - nMonthDays[tmDest.tm_mon - 1] );
  254. DoTime:
  255. if ( nSecsInDay == 0 )
  256. {
  257. tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
  258. }
  259. else
  260. {
  261. tmDest.tm_sec = ( int ) nSecsInDay % 60L;
  262. nMinutesInDay = nSecsInDay / 60L;
  263. tmDest.tm_min = ( int ) nMinutesInDay % 60;
  264. tmDest.tm_hour = ( int ) nMinutesInDay / 60;
  265. }
  266. return TRUE;
  267. }
  268. BOOL CSPPropertyGridItemDate::GetAsSystemTime( SYSTEMTIME & sysTime )
  269. {
  270. BOOL bRetVal = FALSE;
  271. if ( m_oleDate.GetStatus() == COleDateTime::valid )
  272. {
  273. struct tm tmTemp;
  274. if ( SPPropetryGridTmFromOleDate( m_oleDate,tmTemp ) )
  275. {
  276. sysTime.wYear = ( WORD ) tmTemp.tm_year;
  277. sysTime.wMonth = ( WORD ) tmTemp.tm_mon;
  278. sysTime.wDayOfWeek = ( WORD ) tmTemp.tm_wday;
  279. sysTime.wDay = ( WORD ) tmTemp.tm_mday;
  280. sysTime.wMinute = sysTime.wMilliseconds = sysTime.wSecond = sysTime.wHour = 0;
  281. bRetVal = TRUE;
  282. }
  283. }
  284. return bRetVal;
  285. }
  286. #else
  287. BOOL CSPPropertyGridItemDate::GetAsSystemTime( SYSTEMTIME & sysTime )
  288. {
  289. BOOL bRetVal = FALSE;
  290. if ( m_oleDate.GetStatus() == COleDateTime::valid )
  291. {
  292. bRetVal = m_oleDate.GetAsSystemTime( sysTime );
  293. sysTime.wMinute = sysTime.wMilliseconds = sysTime.wSecond = sysTime.wHour = 0;
  294. }
  295. return bRetVal;
  296. }
  297. #endif
  298. void CSPPropertyGridItemDate::OnInplaceButtonDown()
  299. {
  300. CSPPropertyGridInplaceMonthCal *pManthCtrl = new CSPPropertyGridInplaceMonthCal( this );
  301. CRect rcItem = GetItemRect();
  302. m_pGrid->ClientToScreen( &rcItem );
  303. #if _MSC_VER < 1200 // MFC 5.0
  304. INITCOMMONCONTROLSEX icex;
  305. icex.dwSize = sizeof( icex );
  306. icex.dwICC = ICC_DATE_CLASSES;
  307. VERIFY( InitCommonControlsEx( &icex ) );
  308. #else
  309. //VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_DATE_REG));
  310. #endif // _MSC_VER < 1200
  311. CRect rect ( 0,0,0,0 );
  312. pManthCtrl->CreateEx( WS_EX_TOPMOST,MONTHCAL_CLASS,NULL,WS_BORDER | WS_POPUP | WS_VISIBLE,rect,m_pGrid,0 );
  313. SYSTEMTIME sysTime;
  314. if ( GetAsSystemTime( sysTime ) )
  315. {
  316. pManthCtrl->SendMessage( MCM_SETCURSEL,0,( LPARAM ) & sysTime );
  317. }
  318. if ( pManthCtrl->GetMinReqRect( rect ) )
  319. {
  320. rect.SetRect( rcItem.right - rect.Width(),rcItem.bottom,rcItem.right,rcItem.bottom + rect.Height() );
  321. CRect rcWork = CSPDrawHelpers::GetWorkArea( rcItem );
  322. if ( rect.bottom > rcWork.bottom && rect.top > rcWork.CenterPoint().y )
  323. {
  324. rect.OffsetRect( 0,-rect.Height() - rcItem.Height() - 1 );
  325. }
  326. if ( rect.left < rcWork.left )
  327. rect.OffsetRect( rcWork.left - rect.left,0 );
  328. if ( rect.right > rcWork.right )
  329. rect.OffsetRect( rcWork.right - rect.right,0 );
  330. pManthCtrl->SetWindowPos( NULL,rect.left,rect.top,rect.Width(),rect.Height(),SWP_NOZORDER | SWP_NOACTIVATE );
  331. }
  332. pManthCtrl->SetOwner( m_pGrid );
  333. pManthCtrl->SetFocus();
  334. }
  335. long CSPPropertyGridItemDate::GetDay()
  336. {
  337. return m_oleDate.GetDay();
  338. }
  339. void CSPPropertyGridItemDate::SetDay( long nDay )
  340. {
  341. COleDateTime oleDate ( GetYear(),GetMonth(),nDay,0,0,0 );
  342. SetDate( oleDate );
  343. }
  344. long CSPPropertyGridItemDate::GetMonth()
  345. {
  346. return m_oleDate.GetMonth();
  347. }
  348. void CSPPropertyGridItemDate::SetMonth( long nMonth )
  349. {
  350. COleDateTime oleDate ( GetYear(),nMonth,GetDay(),0,0,0 );
  351. SetDate( oleDate );
  352. }
  353. long CSPPropertyGridItemDate::GetYear()
  354. {
  355. return m_oleDate.GetYear();
  356. }
  357. void CSPPropertyGridItemDate::SetYear( long nYear )
  358. {
  359. COleDateTime oleDate ( nYear,GetMonth(),GetDay(),0,0,0 );
  360. SetDate( oleDate );
  361. }
  362. #ifdef __AFXCTL_H__
  363. //////////////////////////////////////////////////////////////////////////
  364. // CSPPropertyGridItemPicture
  365. CSPPropertyGridItemPicture::CSPPropertyGridItemPicture( CString strCaption ) : CSPPropertyGridItem( strCaption )
  366. {
  367. m_nFlags = SPGridItemHasExpandButton;
  368. }
  369. BOOL CSPPropertyGridItemPicture::OnDrawItemValue( CDC & dc , CRect rcValue )
  370. {
  371. COLORREF clr = dc.GetTextColor();
  372. CRect rcSample ( rcValue.left - 2,rcValue.top + 1,rcValue.left + 18,rcValue.bottom - 1 );
  373. m_olePicture.Render( &dc,rcSample,rcSample );
  374. dc.Draw3dRect( rcSample,clr,clr );
  375. CRect rcText ( rcValue );
  376. rcText.left += 25;
  377. short type = m_olePicture.GetType();
  378. CString str = type == PICTYPE_ICON ? _T( "(Icon)" ) : type == PICTYPE_BITMAP ? _T( "(Bitmap)" ) : _T( "None" );
  379. dc.DrawText( str,rcText,DT_SINGLELINE | DT_VCENTER );
  380. return TRUE;
  381. }
  382. void CSPPropertyGridItemPicture::OnInplaceButtonDown()
  383. {
  384. CString strFilter = _T( "All Picture Types|*.bmp;*.cur;*.dib;*.emf;*.ico;*.wmf;*.gif;*.jpg|Bitmaps (*.bmp;*.dib;*.gif;*.jpg)|*.bmp;*.dib;*.gif;*.jpg|Icons/Cursors (*.ico;*.cur)|*.ico;*.cur|Metafiles (*.wmf;*.emf)|*.wmf;*.emf|All files (*.*)|*.*||" );
  385. CFileDialog dlg ( TRUE,NULL,NULL,OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,strFilter );
  386. if ( dlg.DoModal() == IDOK )
  387. {
  388. SetPicturePath( dlg.GetPathName() );
  389. }
  390. }
  391. void CSPPropertyGridItemPicture::SetPicturePath( LPCTSTR lpszPath )
  392. {
  393. USES_CONVERSION;
  394. m_strPicturePath = lpszPath;
  395. LPPICTUREDISP pPict = NULL;
  396. if ( OleLoadPicturePath( T2OLE( ( LPTSTR ) ( LPCTSTR ) m_strPicturePath ),NULL,0,0,IID_IPictureDisp,( LPVOID * ) &pPict ) == S_OK )
  397. {
  398. m_olePicture.SetPictureDispatch( pPict );
  399. pPict->Release();
  400. OnValueChanged( _T( "" ) );
  401. ( ( CWnd * ) m_pGrid )->Invalidate( FALSE );
  402. }
  403. }
  404. #endif