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.

2088 lines
52 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: recact.c
  6. //
  7. // This file contains the reconciliation-action control class code
  8. //
  9. //
  10. // History:
  11. // 08-12-93 ScottH Created.
  12. //
  13. //---------------------------------------------------------------------------
  14. ///////////////////////////////////////////////////// INCLUDES
  15. #include "pch.h"
  16. #include "reintinc.h"
  17. #include "extra.h"
  18. #include "resource.h"
  19. #include "recact.h"
  20. #include "dobj.h"
  21. ///////////////////////////////////////////////////// Globals
  22. int g_cxIconSpacing = 0;
  23. int g_cyIconSpacing = 0;
  24. int g_cxBorder = 0;
  25. int g_cyBorder = 0;
  26. int g_cxMargin = 0;
  27. int g_cxIcon = 0;
  28. int g_cyIcon = 0;
  29. int g_cxIconMargin = 0;
  30. int g_cyIconMargin = 0;
  31. int g_cxLabelMargin = 0;
  32. int g_cyLabelSpace = 0;
  33. //char const FAR c_szWinHelpFile[] = "windows.hlp";
  34. ///////////////////////////////////////////////////// CONTROLLING DEFINES
  35. ///////////////////////////////////////////////////// DEFINES
  36. // Manifest constants
  37. #define SIDE_INSIDE 0
  38. #define SIDE_OUTSIDE 1
  39. // These should be changed if the bitmap sizes change!!
  40. #define CX_ACTIONBMP 26
  41. #define CY_ACTIONBMP 26
  42. #define RECOMPUTE (-1)
  43. #define X_INCOLUMN (g_cxIcon*2)
  44. // Image indexes
  45. #define II_RIGHT 0
  46. #define II_LEFT 1
  47. #define II_CONFLICT 2
  48. #define II_SKIP 3
  49. #define II_MERGE 4
  50. #define II_SOMETHING 5
  51. #define II_UPTODATE 6
  52. // Menu items
  53. //
  54. #define IDM_ACTIONFIRST 100
  55. #define IDM_TOOUT 100
  56. #define IDM_TOIN 101
  57. #define IDM_SKIP 102
  58. #define IDM_MERGE 103
  59. #define IDM_ACTIONLAST 103
  60. #define IDM_WHATSTHIS 104
  61. ///////////////////////////////////////////////////// TYPEDEFS
  62. typedef struct tagRECACT
  63. {
  64. HWND hwnd;
  65. HWND hwndLB;
  66. HDC hdcOwn; // Own DC
  67. HMENU hmenu; // Action and help context menu
  68. HFONT hfont;
  69. WNDPROC lpfnLBProc; // Default LB proc
  70. HIMAGELIST himlAction; // imagelist for actions
  71. HIMAGELIST himlCache; // control imagelist cache
  72. HBITMAP hbmpBullet;
  73. HBRUSH hbrBkgnd;
  74. COLORREF clrBkgnd;
  75. LONG lStyle; // Window style flags
  76. // Metrics
  77. int xAction;
  78. int cxAction;
  79. int cxItem; // Generic width of an item
  80. int cxMenuCheck;
  81. int cyMenuCheck;
  82. int cyText;
  83. int cxSideItem;
  84. int cxEllipses;
  85. } RECACT, FAR * LPRECACT;
  86. #define RecAct_IsNoIcon(this) IsFlagSet((this)->lStyle, RAS_SINGLEITEM)
  87. // Internal item data struct
  88. //
  89. typedef struct tagRA_PRIV
  90. {
  91. UINT uStyle; // One of RAIS_
  92. UINT uAction; // One of RAIA_
  93. FileInfo * pfi;
  94. SIDEITEM siInside;
  95. SIDEITEM siOutside;
  96. LPARAM lParam;
  97. DOBJ rgdobj[4]; // Array of Draw object info
  98. int cx; // Bounding width and height
  99. int cy;
  100. } RA_PRIV, FAR * LPRA_PRIV;
  101. #define IDOBJ_ACTION 3
  102. // RecAction menu item definition structure. Used to define the
  103. // context menu brought up in this control.
  104. //
  105. typedef struct tagRAMID
  106. {
  107. UINT idm; // Menu ID (for MENUITEMINFO struct)
  108. UINT uAction; // One of RAIA_* flags
  109. UINT ids; // Resource string ID
  110. int iImage; // Index into himlAction
  111. RECT rcExtent; // Extent rect of string
  112. } RAMID, FAR * LPRAMID; // RecAction Menu Item Definition
  113. // Help menu item definition structure. Used to define the help
  114. // items in the context menu.
  115. //
  116. typedef struct tagHMID
  117. {
  118. UINT idm;
  119. UINT ids;
  120. } HMID;
  121. ///////////////////////////////////////////////////// MACROS
  122. #define RecAct_DefProc DefWindowProc
  123. #define RecActLB_DefProc CallWindowProc
  124. // Instance data pointer macros
  125. //
  126. #define RecAct_GetPtr(hwnd) (LPRECACT)GetWindowLong(hwnd, 0)
  127. #define RecAct_SetPtr(hwnd, lp) (LPRECACT)SetWindowLong(hwnd, 0, (LONG)(lp))
  128. #define RecAct_GetCount(this) ListBox_GetCount((this)->hwndLB)
  129. ///////////////////////////////////////////////////// MODULE DATA
  130. static char const c_szEllipses[] = "...";
  131. static char const c_szDateDummy[] = "99/99/99 99:99PM";
  132. // Map RAIA_* values to image indexes
  133. //
  134. static UINT const c_mpraiaiImage[] =
  135. { II_RIGHT, II_LEFT, II_SKIP, II_CONFLICT, II_MERGE, II_SOMETHING, II_UPTODATE };
  136. // Map RAIA_* values to menu command positions
  137. //
  138. static UINT const c_mpraiaidmMenu[] =
  139. {IDM_TOOUT, IDM_TOIN, IDM_SKIP, IDM_SKIP, IDM_MERGE, 0, 0 };
  140. // Define the context menu layout
  141. //
  142. static RAMID const c_rgramid[] = {
  143. { IDM_TOOUT, RAIA_TOOUT, IDS_MENU_REPLACE, II_RIGHT, 0 },
  144. { IDM_TOIN, RAIA_TOIN, IDS_MENU_REPLACE, II_LEFT, 0 },
  145. { IDM_SKIP, RAIA_SKIP, IDS_MENU_SKIP, II_SKIP, 0 },
  146. // Merge must be the last item!
  147. { IDM_MERGE, RAIA_MERGE, IDS_MENU_MERGE, II_MERGE, 0 },
  148. };
  149. static RAMID const c_rgramidCreates[] = {
  150. { IDM_TOOUT, RAIA_TOOUT, IDS_MENU_CREATE, II_RIGHT, 0 },
  151. { IDM_TOIN, RAIA_TOIN, IDS_MENU_CREATE, II_LEFT, 0 },
  152. };
  153. // Indexes into c_rgramidCreates
  154. //
  155. #define IRAMID_CREATEOUT 0
  156. #define IRAMID_CREATEIN 1
  157. static HMID const c_rghmid[] = {
  158. { IDM_WHATSTHIS, IDS_MENU_WHATSTHIS },
  159. };
  160. ///////////////////////////////////////////////////// LOCAL PROCEDURES
  161. LRESULT _export CALLBACK RecActLB_LBProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
  162. ///////////////////////////////////////////////////// PRIVATE FUNCTIONS
  163. #ifdef DEBUG
  164. LPCSTR PRIVATE DumpRecAction(
  165. UINT uAction) // RAIA_
  166. {
  167. switch (uAction)
  168. {
  169. DEBUG_CASE_STRING( RAIA_TOOUT );
  170. DEBUG_CASE_STRING( RAIA_TOIN );
  171. DEBUG_CASE_STRING( RAIA_SKIP );
  172. DEBUG_CASE_STRING( RAIA_CONFLICT );
  173. DEBUG_CASE_STRING( RAIA_MERGE );
  174. DEBUG_CASE_STRING( RAIA_SOMETHING );
  175. DEBUG_CASE_STRING( RAIA_NOTHING );
  176. DEBUG_CASE_STRING( RAIA_ORPHAN );
  177. default: return "Unknown";
  178. }
  179. }
  180. LPCSTR PRIVATE DumpSideItemState(
  181. UINT uState) // SI_
  182. {
  183. switch (uState)
  184. {
  185. DEBUG_CASE_STRING( SI_UNCHANGED );
  186. DEBUG_CASE_STRING( SI_CHANGED );
  187. DEBUG_CASE_STRING( SI_NEW );
  188. DEBUG_CASE_STRING( SI_NOEXIST );
  189. DEBUG_CASE_STRING( SI_UNAVAILABLE );
  190. DEBUG_CASE_STRING( SI_DELETED );
  191. default: return "Unknown";
  192. }
  193. }
  194. /*----------------------------------------------------------
  195. Purpose:
  196. Returns:
  197. Cond: --
  198. */
  199. void PUBLIC DumpTwinPair(
  200. LPRA_ITEM pitem)
  201. {
  202. if (pitem)
  203. {
  204. char szBuf[MAXMSGLEN];
  205. #define szDump "Dump TWINPAIR: "
  206. #define szBlank " "
  207. if (IsFlagClear(g_uDumpFlags, DF_TWINPAIR))
  208. {
  209. return;
  210. }
  211. wsprintf(szBuf, "%s.pszName = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->pszName));
  212. OutputDebugString(szBuf);
  213. wsprintf(szBuf, "%s.uStyle = %lx\r\n", (LPSTR)szBlank, pitem->uStyle);
  214. OutputDebugString(szBuf);
  215. wsprintf(szBuf, "%s.uAction = %s\r\n", (LPSTR)szBlank, DumpRecAction(pitem->uAction));
  216. OutputDebugString(szBuf);
  217. #undef szDump
  218. #define szDump " Inside: "
  219. wsprintf(szBuf, "%s.pszDir = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->siInside.pszDir));
  220. OutputDebugString(szBuf);
  221. wsprintf(szBuf, "%s.uState = %s\r\n", (LPSTR)szBlank, DumpSideItemState(pitem->siInside.uState));
  222. OutputDebugString(szBuf);
  223. #undef szDump
  224. #define szDump " Outside: "
  225. wsprintf(szBuf, "%s.pszDir = %s\r\n", (LPSTR)szDump, Dbg_SafeStr(pitem->siOutside.pszDir));
  226. OutputDebugString(szBuf);
  227. wsprintf(szBuf, "%s.uState = %s\r\n", (LPSTR)szBlank, DumpSideItemState(pitem->siOutside.uState));
  228. OutputDebugString(szBuf);
  229. #undef szDump
  230. #undef szBlank
  231. }
  232. }
  233. #endif
  234. /*----------------------------------------------------------
  235. Purpose: Create a monochrome bitmap of the bullet, so we can
  236. play with the colors later.
  237. Returns: handle to bitmap
  238. Cond: Caller must delete bitmap
  239. */
  240. HBITMAP PRIVATE CreateBulletBitmap(
  241. LPSIZE psize)
  242. {
  243. HDC hdcMem;
  244. HBITMAP hbmp = NULL;
  245. hdcMem = CreateCompatibleDC(NULL);
  246. if (hdcMem)
  247. {
  248. hbmp = CreateCompatibleBitmap(hdcMem, psize->cx, psize->cy);
  249. if (hbmp)
  250. {
  251. HBITMAP hbmpOld;
  252. RECT rc;
  253. // hbmp is monochrome
  254. hbmpOld = SelectBitmap(hdcMem, hbmp);
  255. rc.left = 0;
  256. rc.top = 0;
  257. rc.right = psize->cx;
  258. rc.bottom = psize->cy;
  259. DrawFrameControl(hdcMem, &rc, DFC_MENU, DFCS_MENUBULLET);
  260. SelectBitmap(hdcMem, hbmpOld);
  261. }
  262. DeleteDC(hdcMem);
  263. }
  264. return hbmp;
  265. }
  266. /*----------------------------------------------------------
  267. Purpose: Returns the resource ID string given the action
  268. flag.
  269. Returns: IDS_ value
  270. Cond: --
  271. */
  272. UINT PRIVATE GetActionText(
  273. LPRA_PRIV ppriv)
  274. {
  275. UINT ids;
  276. ASSERT(ppriv);
  277. switch (ppriv->uAction)
  278. {
  279. case RAIA_TOOUT:
  280. if (SI_NEW == ppriv->siInside.uState)
  281. {
  282. ids = IDS_STATE_Creates;
  283. }
  284. else
  285. {
  286. ids = IDS_STATE_Replaces;
  287. }
  288. break;
  289. case RAIA_TOIN:
  290. if (SI_NEW == ppriv->siOutside.uState)
  291. {
  292. ids = IDS_STATE_Creates;
  293. }
  294. else
  295. {
  296. ids = IDS_STATE_Replaces;
  297. }
  298. break;
  299. case RAIA_SKIP:
  300. // Can occur if the user explicitly wants to skip, or if
  301. // one side is unavailable.
  302. ids = IDS_STATE_Skip;
  303. break;
  304. case RAIA_CONFLICT: ids = IDS_STATE_Conflict; break;
  305. case RAIA_MERGE: ids = IDS_STATE_Merge; break;
  306. case RAIA_NOTHING: ids = IDS_STATE_Uptodate; break;
  307. case RAIA_SOMETHING: ids = IDS_STATE_NeedToUpdate; break;
  308. default: ids = 0; break;
  309. }
  310. return ids;
  311. }
  312. /*----------------------------------------------------------
  313. Purpose: Repaint an item in the listbox
  314. Returns: --
  315. Cond: --
  316. */
  317. void PRIVATE ListBox_RepaintItemNow(
  318. HWND hwnd,
  319. int iItem,
  320. LPRECT prc, // Relative to individual entry rect. May be NULL
  321. BOOL bEraseBk)
  322. {
  323. RECT rc;
  324. RECT rcItem;
  325. ListBox_GetItemRect(hwnd, iItem, &rcItem);
  326. if (prc)
  327. {
  328. OffsetRect(prc, rcItem.left, rcItem.top);
  329. IntersectRect(&rc, &rcItem, prc);
  330. }
  331. else
  332. rc = rcItem;
  333. InvalidateRect(hwnd, &rc, bEraseBk);
  334. UpdateWindow(hwnd);
  335. }
  336. /*----------------------------------------------------------
  337. Purpose: Send selection change notification
  338. Returns:
  339. Cond: --
  340. */
  341. BOOL PRIVATE RecAct_SendSelChange(
  342. LPRECACT this,
  343. int isel)
  344. {
  345. NM_RECACT nm;
  346. nm.iItem = isel;
  347. nm.mask = 0;
  348. if (isel != -1)
  349. {
  350. LPRA_ITEM pitem;
  351. ListBox_GetText(this->hwndLB, isel, &pitem);
  352. if (!pitem)
  353. return FALSE;
  354. nm.lParam = pitem->lParam;
  355. nm.mask |= RAIF_LPARAM;
  356. }
  357. return !(BOOL)SendNotify(GetParent(this->hwnd), this->hwnd, RN_SELCHANGED, &nm.hdr);
  358. }
  359. /*----------------------------------------------------------
  360. Purpose: Send an action change notification
  361. Returns:
  362. Cond: --
  363. */
  364. BOOL PRIVATE RecAct_SendItemChange(
  365. LPRECACT this,
  366. int iEntry,
  367. UINT uActionOld)
  368. {
  369. NM_RECACT nm;
  370. nm.iItem = iEntry;
  371. nm.mask = 0;
  372. if (iEntry != -1)
  373. {
  374. LPRA_PRIV ppriv;
  375. ListBox_GetText(this->hwndLB, iEntry, &ppriv);
  376. if (!ppriv)
  377. return FALSE;
  378. nm.mask |= RAIF_LPARAM | RAIF_ACTION;
  379. nm.lParam = ppriv->lParam;
  380. nm.uAction = ppriv->uAction;
  381. nm.uActionOld = uActionOld;
  382. }
  383. return !(BOOL)SendNotify(GetParent(this->hwnd), this->hwnd, RN_ITEMCHANGED, &nm.hdr);
  384. }
  385. /*----------------------------------------------------------
  386. Purpose: Calculate the important coordinates that we want to save.
  387. Returns: --
  388. Cond: --
  389. */
  390. void PRIVATE RecAct_CalcCoords(
  391. LPRECACT this)
  392. {
  393. int xOutColumn;
  394. ASSERT(this->cxSideItem != 0);
  395. xOutColumn = this->cxItem - this->cxSideItem - g_cxMargin;
  396. this->xAction = (RecAct_IsNoIcon(this) ? 0 : X_INCOLUMN) + this->cxSideItem;
  397. this->cxAction = xOutColumn - this->xAction;
  398. }
  399. /*----------------------------------------------------------
  400. Purpose: Create the action context menu
  401. Returns: TRUE on success
  402. Cond: --
  403. */
  404. BOOL PRIVATE RecAct_CreateMenu(
  405. LPRECACT this)
  406. {
  407. HMENU hmenu;
  408. hmenu = CreatePopupMenu();
  409. if (hmenu)
  410. {
  411. char sz[MAXSHORTLEN];
  412. MENUITEMINFO mii;
  413. int i;
  414. // Add the help menu items now, since these will be standard
  415. //
  416. mii.cbSize = sizeof(MENUITEMINFO);
  417. mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  418. mii.fType = MFT_STRING;
  419. mii.fState = MFS_ENABLED;
  420. for (i = 0; i < ARRAYSIZE(c_rghmid); i++)
  421. {
  422. mii.wID = c_rghmid[i].idm;
  423. mii.dwTypeData = SzFromIDS(c_rghmid[i].ids, sz, sizeof(sz));
  424. InsertMenuItem(hmenu, i, TRUE, &mii);
  425. }
  426. this->hmenu = hmenu;
  427. }
  428. return hmenu != NULL;
  429. }
  430. /*----------------------------------------------------------
  431. Purpose: Add the action menu items to the context menu
  432. Returns: --
  433. Cond: --
  434. */
  435. void PRIVATE AddActionsToContextMenu(
  436. HMENU hmenu,
  437. UINT idmCheck, // menu item to checkmark
  438. LPRA_PRIV ppriv)
  439. {
  440. MENUITEMINFO mii;
  441. int i;
  442. int cItems = ARRAYSIZE(c_rgramid);
  443. mii.cbSize = sizeof(MENUITEMINFO);
  444. mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
  445. mii.fType = MFT_OWNERDRAW;
  446. mii.fState = MFS_ENABLED;
  447. // Is merge supported?
  448. if (IsFlagClear(ppriv->uStyle, RAIS_CANMERGE))
  449. {
  450. // No
  451. --cItems;
  452. }
  453. for (i = 0; i < cItems; i++)
  454. {
  455. mii.wID = c_rgramid[i].idm;
  456. mii.dwItemData = (DWORD)&c_rgramid[i];
  457. InsertMenuItem(hmenu, i, TRUE, &mii);
  458. }
  459. // Add the separator
  460. mii.fMask = MIIM_TYPE;
  461. mii.fType = MFT_SEPARATOR;
  462. InsertMenuItem(hmenu, i, TRUE, &mii);
  463. // Set the initial checkmark.
  464. CheckMenuRadioItem(hmenu, IDM_ACTIONFIRST, IDM_ACTIONLAST, idmCheck,
  465. MF_BYCOMMAND | MF_CHECKED);
  466. #if 0
  467. // Is merge supported?
  468. if (IsFlagClear(ppriv->uStyle, RAIS_CANMERGE))
  469. {
  470. // No
  471. mii.fMask = MIIM_STATE;
  472. mii.fState = MFS_GRAYED | MFS_DISABLED;
  473. SetMenuItemInfo(hmenu, IDM_MERGE, FALSE, &mii);
  474. }
  475. #endif
  476. //tHACK
  477. mii.fMask = MIIM_STATE;
  478. mii.fState = MFS_GRAYED | MFS_DISABLED;
  479. SetMenuItemInfo(hmenu, IDM_SKIP, FALSE, &mii);
  480. // Is the file or its sync copy unavailable?
  481. if (SI_UNAVAILABLE == ppriv->siInside.uState ||
  482. SI_UNAVAILABLE == ppriv->siOutside.uState)
  483. {
  484. // Yes
  485. mii.fMask = MIIM_STATE;
  486. mii.fState = MFS_GRAYED | MFS_DISABLED;
  487. SetMenuItemInfo(hmenu, IDM_TOIN, FALSE, &mii);
  488. SetMenuItemInfo(hmenu, IDM_TOOUT, FALSE, &mii);
  489. SetMenuItemInfo(hmenu, IDM_MERGE, FALSE, &mii);
  490. }
  491. // Is the file being created?
  492. else if (ppriv->siInside.uState == SI_NEW ||
  493. ppriv->siOutside.uState == SI_NEW)
  494. {
  495. // Yes; disable the replace-in-opposite direction
  496. UINT idmDisable;
  497. UINT idmChangeVerb;
  498. if (ppriv->siInside.uState == SI_NEW)
  499. {
  500. idmDisable = IDM_TOIN;
  501. idmChangeVerb = IDM_TOOUT;
  502. i = IRAMID_CREATEOUT;
  503. }
  504. else
  505. {
  506. idmDisable = IDM_TOOUT;
  507. idmChangeVerb = IDM_TOIN;
  508. i = IRAMID_CREATEIN;
  509. }
  510. // Disable one of the directions
  511. mii.fMask = MIIM_STATE;
  512. mii.fState = MFS_GRAYED | MFS_DISABLED;
  513. SetMenuItemInfo(hmenu, idmDisable, FALSE, &mii);
  514. // Change the verb of the other direction
  515. mii.fMask = MIIM_DATA;
  516. mii.dwItemData = (DWORD)&c_rgramidCreates[i];
  517. SetMenuItemInfo(hmenu, idmChangeVerb, FALSE, &mii);
  518. }
  519. }
  520. /*----------------------------------------------------------
  521. Purpose: Clear out the context menu
  522. Returns: --
  523. Cond: --
  524. */
  525. void PRIVATE ResetContextMenu(
  526. HMENU hmenu)
  527. {
  528. int cnt;
  529. // If there is more than just the help items, remove them
  530. // (but leave the help items)
  531. //
  532. cnt = GetMenuItemCount(hmenu);
  533. if (cnt > ARRAYSIZE(c_rghmid))
  534. {
  535. int i;
  536. cnt -= ARRAYSIZE(c_rghmid);
  537. for (i = 0; i < cnt; i++)
  538. {
  539. DeleteMenu(hmenu, 0, MF_BYPOSITION);
  540. }
  541. }
  542. }
  543. /*----------------------------------------------------------
  544. Purpose: Do the context menu
  545. Returns: --
  546. Cond: --
  547. */
  548. void PRIVATE RecAct_DoContextMenu(
  549. LPRECACT this,
  550. int x, // in screen coords
  551. int y,
  552. int iEntry,
  553. BOOL bHelpOnly) // TRUE: only show the help items
  554. {
  555. UINT idCmd;
  556. if (this->hmenu)
  557. {
  558. LPRA_PRIV ppriv;
  559. RECT rc;
  560. int idmCheck;
  561. UINT uActionOld;
  562. // Only show help-portion of context menu?
  563. if (bHelpOnly)
  564. {
  565. // Yes
  566. ppriv = NULL;
  567. }
  568. else
  569. {
  570. // No
  571. ListBox_GetText(this->hwndLB, iEntry, &ppriv);
  572. // Determine if this is a help-context menu only.
  573. // It is if this is a folder-item or if there is no action
  574. // to take.
  575. //
  576. ASSERT(ppriv->uAction < ARRAYSIZE(c_mpraiaidmMenu));
  577. idmCheck = c_mpraiaidmMenu[ppriv->uAction];
  578. // Build the context menu
  579. //
  580. if (IsFlagClear(ppriv->uStyle, RAIS_FOLDER) && idmCheck != 0)
  581. {
  582. AddActionsToContextMenu(this->hmenu, idmCheck, ppriv);
  583. }
  584. }
  585. // Show context menu
  586. //
  587. idCmd = TrackPopupMenu(this->hmenu,
  588. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  589. x, y, 0, this->hwnd, NULL);
  590. // Clear menu
  591. //
  592. ResetContextMenu(this->hmenu);
  593. if (ppriv)
  594. {
  595. // Save the old action
  596. uActionOld = ppriv->uAction;
  597. }
  598. // Act on whatever the user chose
  599. switch (idCmd)
  600. {
  601. case IDM_TOOUT:
  602. ppriv->uAction = RAIA_TOOUT;
  603. break;
  604. case IDM_TOIN:
  605. ppriv->uAction = RAIA_TOIN;
  606. break;
  607. case IDM_SKIP:
  608. ppriv->uAction = RAIA_SKIP;
  609. break;
  610. case IDM_MERGE:
  611. ppriv->uAction = RAIA_MERGE;
  612. break;
  613. // tHACK case IDM_WHATSTHIS:
  614. // WinHelp(this->hwnd, c_szWinHelpFile, HELP_CONTEXTPOPUP, IDH_BFC_UPDATE_SCREEN);
  615. // return; // Return now
  616. default:
  617. return; // Return now
  618. }
  619. // Repaint action portion of entry
  620. ppriv->cx = RECOMPUTE;
  621. rc = ppriv->rgdobj[IDOBJ_ACTION].rcBounding;
  622. ListBox_RepaintItemNow(this->hwndLB, iEntry, &rc, TRUE);
  623. // Send a notify message
  624. ASSERT(NULL != ppriv); // uActionOld should be valid
  625. RecAct_SendItemChange(this, iEntry, uActionOld);
  626. }
  627. }
  628. /*----------------------------------------------------------
  629. Purpose: Create the windows for this control
  630. Returns: TRUE on success
  631. Cond: --
  632. */
  633. BOOL PRIVATE RecAct_CreateWindows(
  634. LPRECACT this,
  635. CREATESTRUCT FAR * lpcs)
  636. {
  637. HWND hwnd = this->hwnd;
  638. HWND hwndLB = NULL;
  639. RECT rc;
  640. int cxEdge = GetSystemMetrics(SM_CXEDGE);
  641. int cyEdge = GetSystemMetrics(SM_CYEDGE);
  642. // Create listbox
  643. hwndLB = CreateWindowEx(
  644. 0,
  645. "listbox",
  646. "",
  647. WS_CHILD | WS_CLIPSIBLINGS | LBS_SORT | LBS_OWNERDRAWVARIABLE |
  648. WS_VSCROLL | WS_TABSTOP | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
  649. LBS_NOTIFY,
  650. 0, 0, lpcs->cx, lpcs->cy,
  651. hwnd,
  652. NULL,
  653. lpcs->hInstance,
  654. 0L);
  655. if (!hwndLB)
  656. return FALSE;
  657. SetWindowFont(hwndLB, this->hfont, FALSE);
  658. this->hwndLB = hwndLB;
  659. // Determine layout of window
  660. GetClientRect(hwnd, &rc);
  661. InflateRect(&rc, -cxEdge, -cyEdge);
  662. SetWindowPos(hwndLB, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
  663. SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOZORDER);
  664. GetClientRect(hwndLB, &rc);
  665. this->cxItem = rc.right - rc.left;
  666. return TRUE;
  667. }
  668. /*----------------------------------------------------------
  669. Purpose: Set the colors of the control
  670. Returns: --
  671. Cond: --
  672. */
  673. void PRIVATE RecAct_SetColors(
  674. LPRECACT this)
  675. {
  676. int cr;
  677. if (IsFlagClear(this->lStyle, RAS_SINGLEITEM))
  678. {
  679. cr = COLOR_WINDOW;
  680. }
  681. else
  682. {
  683. cr = COLOR_3DFACE;
  684. }
  685. this->clrBkgnd = GetSysColor(cr);
  686. if (this->hbrBkgnd)
  687. DeleteBrush(this->hbrBkgnd);
  688. this->hbrBkgnd = CreateSolidBrush(this->clrBkgnd);
  689. }
  690. /*----------------------------------------------------------
  691. Purpose: Creates an imagelist of the action images
  692. Returns: TRUE on success
  693. Cond: --
  694. */
  695. BOOL PRIVATE CreateImageList(
  696. HIMAGELIST * phiml,
  697. HDC hdc,
  698. UINT idb,
  699. int cxBmp,
  700. int cyBmp,
  701. int cImage)
  702. {
  703. BOOL bRet;
  704. HIMAGELIST himl;
  705. himl = ImageList_Create(cxBmp, cyBmp, TRUE, cImage, 1);
  706. if (himl)
  707. {
  708. COLORREF clrMask;
  709. HBITMAP hbm;
  710. hbm = LoadBitmap(vhinstCur, MAKEINTRESOURCE(idb));
  711. ASSERT(hbm);
  712. if (hbm)
  713. {
  714. HDC hdcMem = CreateCompatibleDC(hdc);
  715. if (hdcMem)
  716. {
  717. HBITMAP hbmSav = SelectBitmap(hdcMem, hbm);
  718. clrMask = GetPixel(hdcMem, 0, 0);
  719. SelectBitmap(hdcMem, hbmSav);
  720. bRet = (0 == ImageList_AddMasked(himl, hbm, clrMask));
  721. DeleteDC(hdcMem);
  722. }
  723. else
  724. bRet = FALSE;
  725. DeleteBitmap(hbm);
  726. }
  727. else
  728. bRet = FALSE;
  729. }
  730. else
  731. bRet = FALSE;
  732. *phiml = himl;
  733. return bRet;
  734. }
  735. /*----------------------------------------------------------
  736. Purpose: WM_CREATE handler
  737. Returns: TRUE on success
  738. Cond: --
  739. */
  740. BOOL PRIVATE RecAct_OnCreate(
  741. LPRECACT this,
  742. CREATESTRUCT FAR * lpcs)
  743. {
  744. BOOL bRet = FALSE;
  745. HWND hwnd = this->hwnd;
  746. HDC hdc;
  747. TEXTMETRIC tm;
  748. RECT rcT;
  749. LOGFONT lf;
  750. this->lStyle = GetWindowLong(hwnd, GWL_STYLE);
  751. RecAct_SetColors(this);
  752. // Determine some font things
  753. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
  754. this->hfont = CreateFontIndirect(&lf);
  755. // This window is registered with the CS_OWNDC flag
  756. this->hdcOwn = GetDC(hwnd);
  757. ASSERT(this->hdcOwn);
  758. hdc = this->hdcOwn;
  759. SelectFont(hdc, this->hfont);
  760. GetTextMetrics(hdc, &tm);
  761. this->cyText = tm.tmHeight;
  762. // Calculate text extent for sideitems (use the listbox font)
  763. //
  764. SetRectFromExtent(hdc, &rcT, c_szEllipses);
  765. this->cxEllipses = rcT.right - rcT.left;
  766. SetRectFromExtent(hdc, &rcT, c_szDateDummy);
  767. this->cxSideItem = (rcT.right - rcT.left) + 2*g_cxMargin;
  768. // Create windows used by control
  769. if (RecAct_CreateWindows(this, lpcs))
  770. {
  771. RecAct_CalcCoords(this);
  772. this->lpfnLBProc = SubclassWindow(this->hwndLB, RecActLB_LBProc);
  773. // Get the system imagelist cache
  774. //
  775. this->himlCache = ImageList_Create(g_cxIcon, g_cyIcon, TRUE, 8, 8);
  776. if (this->himlCache)
  777. {
  778. if (CreateImageList(&this->himlAction, hdc, IDB_ACTIONS,
  779. CX_ACTIONBMP, CY_ACTIONBMP, 8))
  780. {
  781. SIZE size;
  782. // Get some metrics
  783. this->cxMenuCheck = GetSystemMetrics(SM_CXMENUCHECK);
  784. this->cyMenuCheck = GetSystemMetrics(SM_CYMENUCHECK);
  785. size.cx = this->cxMenuCheck;
  786. size.cy = this->cyMenuCheck;
  787. this->hbmpBullet = CreateBulletBitmap(&size);
  788. if (this->hbmpBullet)
  789. {
  790. bRet = RecAct_CreateMenu(this);
  791. }
  792. }
  793. }
  794. }
  795. return bRet;
  796. }
  797. /*----------------------------------------------------------
  798. Purpose: WM_DESTROY Handler
  799. Returns: --
  800. Cond: --
  801. */
  802. void PRIVATE RecAct_OnDestroy(
  803. LPRECACT this)
  804. {
  805. if (this->himlCache)
  806. {
  807. ImageList_Destroy(this->himlCache);
  808. this->himlCache = NULL;
  809. }
  810. if (this->himlAction)
  811. {
  812. ImageList_Destroy(this->himlAction);
  813. this->himlAction = NULL;
  814. }
  815. if (this->hbmpBullet)
  816. {
  817. DeleteBitmap(this->hbmpBullet);
  818. this->hbmpBullet = NULL;
  819. }
  820. if (this->hmenu)
  821. {
  822. DestroyMenu(this->hmenu);
  823. this->hmenu = NULL;
  824. }
  825. if (this->hbrBkgnd)
  826. DeleteBrush(this->hbrBkgnd);
  827. if (this->hfont)
  828. DeleteFont(this->hfont);
  829. }
  830. /*----------------------------------------------------------
  831. Purpose: WM_COMMAND Handler
  832. Returns: --
  833. Cond: --
  834. */
  835. VOID PRIVATE RecAct_OnCommand(
  836. LPRECACT this,
  837. int id,
  838. HWND hwndCtl,
  839. UINT uNotifyCode)
  840. {
  841. if (hwndCtl == this->hwndLB)
  842. {
  843. switch (uNotifyCode)
  844. {
  845. case LBN_SELCHANGE:
  846. break;
  847. }
  848. }
  849. }
  850. /*----------------------------------------------------------
  851. Purpose: WM_NOTIFY handler
  852. Returns: varies
  853. Cond: --
  854. */
  855. LRESULT PRIVATE RecAct_OnNotify(
  856. LPRECACT this,
  857. int idFrom,
  858. NMHDR FAR * lpnmhdr)
  859. {
  860. LRESULT lRet = 0;
  861. switch (lpnmhdr->code)
  862. {
  863. case HDN_BEGINTRACK:
  864. lRet = TRUE; // prevent tracking
  865. break;
  866. default:
  867. break;
  868. }
  869. return lRet;
  870. }
  871. /*----------------------------------------------------------
  872. Purpose: WM_CONTEXTMENU handler
  873. Returns: --
  874. Cond: --
  875. */
  876. void PRIVATE RecAct_OnContextMenu(
  877. LPRECACT this,
  878. HWND hwnd,
  879. int x,
  880. int y)
  881. {
  882. if (hwnd == this->hwndLB)
  883. {
  884. POINT pt;
  885. int iHitEntry;
  886. BOOL bHelpOnly = TRUE;
  887. pt.x = x;
  888. pt.y = y;
  889. ScreenToClient(hwnd, &pt);
  890. iHitEntry = (pt.y / ListBox_GetItemHeight(hwnd, 0)) + ListBox_GetTopIndex(hwnd);
  891. ASSERT(iHitEntry >= 0);
  892. if (iHitEntry < ListBox_GetCount(hwnd))
  893. {
  894. ListBox_SetCurSel(hwnd, iHitEntry);
  895. ListBox_RepaintItemNow(hwnd, iHitEntry, NULL, FALSE);
  896. bHelpOnly = FALSE;
  897. }
  898. // Bring up the context menu for the listbox
  899. RecAct_DoContextMenu(this, x, y, iHitEntry, bHelpOnly);
  900. }
  901. }
  902. /*----------------------------------------------------------
  903. Purpose: Calculate the rectangle boundary of a sideitem
  904. Returns: calculated rect
  905. Cond: --
  906. */
  907. void PRIVATE RecAct_CalcSideItemRect(
  908. LPRECACT this,
  909. int nSide, // SIDE_INSIDE or SIDE_OUTSIDE
  910. LPRECT prcOut)
  911. {
  912. int x;
  913. int y = g_cyIconMargin*2;
  914. if (SIDE_INSIDE == nSide)
  915. {
  916. x = g_cxMargin;
  917. if ( !RecAct_IsNoIcon(this) )
  918. x += X_INCOLUMN;
  919. }
  920. else
  921. {
  922. ASSERT(SIDE_OUTSIDE == nSide);
  923. x = this->cxItem - this->cxSideItem - g_cxMargin;
  924. }
  925. prcOut->left = x;
  926. prcOut->top = y;
  927. prcOut->right = x + this->cxSideItem;
  928. prcOut->bottom = y + (this->cyText * 3);
  929. }
  930. /*----------------------------------------------------------
  931. Purpose: Draw a reconciliation listbox entry
  932. Returns: --
  933. Cond: --
  934. */
  935. void PRIVATE RecAct_RecomputeItemMetrics(
  936. LPRECACT this,
  937. LPRA_PRIV ppriv)
  938. {
  939. HDC hdc = this->hdcOwn;
  940. LPDOBJ pdobj = ppriv->rgdobj;
  941. RECT rcT;
  942. RECT rcUnion;
  943. char szIDS[MAXBUFLEN];
  944. UINT ids;
  945. int cyText = this->cyText;
  946. POINT pt;
  947. // Compute the metrics and dimensions of each of the draw objects
  948. // and store back into the item.
  949. // File icon and label
  950. pt.x = 0;
  951. pt.y = 0;
  952. ComputeImageRects(FIGetDisplayName(ppriv->pfi), hdc, &pt,
  953. &pdobj->rcBounding, &pdobj->rcLabel, g_cxIcon, g_cyIcon,
  954. g_cxIconSpacing, cyText);
  955. pdobj->uKind = DOK_IMAGE;
  956. pdobj->lpvObject = FIGetDisplayName(ppriv->pfi);
  957. pdobj->uFlags = DOF_DIFFER | DOF_CENTER;
  958. if (RecAct_IsNoIcon(this))
  959. SetFlag(pdobj->uFlags, DOF_NODRAW);
  960. pdobj->x = pt.x;
  961. pdobj->y = pt.y;
  962. pdobj->himl = this->himlCache;
  963. pdobj->iImage = (UINT)ppriv->pfi->lParam;
  964. rcUnion = pdobj->rcBounding;
  965. // Sideitem Info (Inside Briefcase)
  966. RecAct_CalcSideItemRect(this, SIDE_INSIDE, &rcT);
  967. pdobj++;
  968. pdobj->uKind = DOK_SIDEITEM;
  969. pdobj->lpvObject = &ppriv->siInside;
  970. pdobj->uFlags = DOF_LEFT;
  971. pdobj->x = rcT.left;
  972. pdobj->y = rcT.top;
  973. pdobj->rcClip = rcT;
  974. pdobj->rcBounding = rcT;
  975. // Sideitem Info (Outside Briefcase)
  976. RecAct_CalcSideItemRect(this, SIDE_OUTSIDE, &rcT);
  977. pdobj++;
  978. pdobj->uKind = DOK_SIDEITEM;
  979. pdobj->lpvObject = &ppriv->siOutside;
  980. pdobj->uFlags = DOF_LEFT;
  981. pdobj->x = rcT.left;
  982. pdobj->y = rcT.top;
  983. pdobj->rcClip = rcT;
  984. pdobj->rcBounding = rcT;
  985. UnionRect(&rcUnion, &rcUnion, &rcT);
  986. // Action image
  987. ASSERT(ppriv->uAction <= ARRAYSIZE(c_mpraiaiImage));
  988. pdobj++;
  989. ids = GetActionText(ppriv);
  990. pt.x = this->xAction;
  991. pt.y = 0;
  992. ComputeImageRects(SzFromIDS(ids, szIDS, sizeof(szIDS)), hdc, &pt,
  993. &pdobj->rcBounding, &pdobj->rcLabel, CX_ACTIONBMP, CY_ACTIONBMP,
  994. this->cxAction, cyText);
  995. pdobj->uKind = DOK_IMAGE;
  996. pdobj->lpvObject = (LPVOID)ids;
  997. pdobj->uFlags = DOF_CENTER | DOF_USEIDS;
  998. if (!RecAct_IsNoIcon(this))
  999. SetFlag(pdobj->uFlags, DOF_IGNORESEL);
  1000. pdobj->x = pt.x;
  1001. pdobj->y = pt.y;
  1002. pdobj->himl = this->himlAction;
  1003. pdobj->iImage = c_mpraiaiImage[ppriv->uAction];
  1004. UnionRect(&rcUnion, &rcUnion, &pdobj->rcBounding);
  1005. // Set the bounding rect of this item.
  1006. ppriv->cx = rcUnion.right - rcUnion.left;
  1007. ppriv->cy = max((rcUnion.bottom - rcUnion.top), g_cyIconSpacing);
  1008. }
  1009. /*----------------------------------------------------------
  1010. Purpose: WM_MEASUREITEM handler
  1011. Returns: --
  1012. Cond: --
  1013. */
  1014. void PRIVATE RecAct_OnMeasureItem(
  1015. LPRECACT this,
  1016. LPMEASUREITEMSTRUCT lpmis)
  1017. {
  1018. HDC hdc = this->hdcOwn;
  1019. switch (lpmis->CtlType)
  1020. {
  1021. case ODT_LISTBOX: {
  1022. LPRA_PRIV ppriv = (LPRA_PRIV)lpmis->itemData;
  1023. // Recompute item metrics?
  1024. if (RECOMPUTE == ppriv->cx)
  1025. {
  1026. RecAct_RecomputeItemMetrics(this, ppriv); // Yes
  1027. }
  1028. lpmis->itemHeight = ppriv->cy;
  1029. }
  1030. break;
  1031. case ODT_MENU:
  1032. {
  1033. int i;
  1034. int cxMac = 0;
  1035. RECT rc;
  1036. char sz[MAXBUFLEN];
  1037. // Calculate based on font and image dimensions.
  1038. //
  1039. SelectFont(hdc, this->hfont);
  1040. cxMac = 0;
  1041. for (i = 0; i < ARRAYSIZE(c_rgramid); i++)
  1042. {
  1043. SzFromIDS(c_rgramid[i].ids, sz, sizeof(sz));
  1044. SetRectFromExtent(hdc, &rc, sz);
  1045. cxMac = max(cxMac,
  1046. g_cxMargin + CX_ACTIONBMP + g_cxMargin +
  1047. (rc.right-rc.left) + g_cxMargin);
  1048. }
  1049. lpmis->itemHeight = max(this->cyText, CY_ACTIONBMP);
  1050. lpmis->itemWidth = cxMac;
  1051. }
  1052. break;
  1053. }
  1054. }
  1055. /*----------------------------------------------------------
  1056. Purpose: Draw a reconciliation listbox entry
  1057. Returns: --
  1058. Cond: --
  1059. */
  1060. void PRIVATE RecAct_DrawLBItem(
  1061. LPRECACT this,
  1062. const DRAWITEMSTRUCT FAR * lpcdis)
  1063. {
  1064. LPRA_PRIV ppriv = (LPRA_PRIV)lpcdis->itemData;
  1065. HDC hdc = lpcdis->hDC;
  1066. RECT rc = lpcdis->rcItem;
  1067. POINT ptSav;
  1068. LPDOBJ pdobj;
  1069. UINT cdobjs;
  1070. if (!ppriv)
  1071. {
  1072. // Empty listbox and we're getting the focus
  1073. return;
  1074. }
  1075. SetBkMode(hdc, TRANSPARENT); // required for Shell_DrawText
  1076. SetViewportOrgEx(hdc, rc.left, rc.top, &ptSav);
  1077. // The Chicago-look mandates that icon and filename are selected,
  1078. // the rest of the entry is normal. Yuk.
  1079. // Recompute item metrics?
  1080. if (RECOMPUTE == ppriv->cx)
  1081. {
  1082. RecAct_RecomputeItemMetrics(this, ppriv); // Yes
  1083. }
  1084. // Do we need to redraw everything?
  1085. if (IsFlagSet(lpcdis->itemAction, ODA_DRAWENTIRE))
  1086. {
  1087. // Yes
  1088. cdobjs = ARRAYSIZE(ppriv->rgdobj);
  1089. pdobj = ppriv->rgdobj;
  1090. }
  1091. else
  1092. {
  1093. // No; should we even draw the file icon or action icon?
  1094. if (lpcdis->itemAction & (ODA_FOCUS | ODA_SELECT))
  1095. {
  1096. cdobjs = 1; // Yes
  1097. // Focus rect on file icon?
  1098. if (!RecAct_IsNoIcon(this))
  1099. pdobj = ppriv->rgdobj;
  1100. else
  1101. pdobj = &ppriv->rgdobj[IDOBJ_ACTION];
  1102. }
  1103. else
  1104. {
  1105. cdobjs = 0; // No
  1106. pdobj = ppriv->rgdobj;
  1107. }
  1108. }
  1109. Dobj_Draw(hdc, pdobj, cdobjs, lpcdis->itemState, this->cxEllipses, this->cyText,
  1110. this->clrBkgnd);
  1111. // Clean up
  1112. //
  1113. SetViewportOrgEx(hdc, ptSav.x, ptSav.y, NULL);
  1114. }
  1115. /*----------------------------------------------------------
  1116. Purpose: Draw an action menu item
  1117. Returns: --
  1118. Cond: --
  1119. */
  1120. void PRIVATE RecAct_DrawMenuItem(
  1121. LPRECACT this,
  1122. const DRAWITEMSTRUCT FAR * lpcdis)
  1123. {
  1124. LPRAMID pramid = (LPRAMID)lpcdis->itemData;
  1125. HDC hdc = lpcdis->hDC;
  1126. RECT rc = lpcdis->rcItem;
  1127. DOBJ dobj;
  1128. LPDOBJ pdobj;
  1129. POINT ptSav;
  1130. MENUITEMINFO mii;
  1131. int cx;
  1132. int cy;
  1133. UINT uFlags;
  1134. UINT uFlagsChecked;
  1135. ASSERT(pramid);
  1136. if (lpcdis->itemID == -1)
  1137. return;
  1138. SetViewportOrgEx(hdc, rc.left, rc.top, &ptSav);
  1139. OffsetRect(&rc, -rc.left, -rc.top);
  1140. cx = rc.right - rc.left;
  1141. cy = rc.bottom - rc.top;
  1142. // Get the menu state
  1143. mii.cbSize = sizeof(mii);
  1144. mii.fMask = MIIM_STATE | MIIM_CHECKMARKS;
  1145. GetMenuItemInfo(this->hmenu, lpcdis->itemID, FALSE, &mii);
  1146. uFlagsChecked = IsFlagClear(mii.fState, MFS_CHECKED) ? DOF_NODRAW : 0;
  1147. uFlags = DOF_DIFFER | DOF_MENU | DOF_USEIDS;
  1148. if (IsFlagSet(mii.fState, MFS_GRAYED))
  1149. SetFlag(uFlags, DOF_DISABLED);
  1150. // Build the array of DObjs that we want to draw.
  1151. // Action image
  1152. pdobj = &dobj;
  1153. pdobj->uKind = DOK_IMAGE;
  1154. pdobj->lpvObject = (LPVOID)pramid->ids;
  1155. pdobj->himl = this->himlAction;
  1156. pdobj->iImage = pramid->iImage;
  1157. pdobj->uFlags = uFlags;
  1158. pdobj->x = g_cxMargin;
  1159. pdobj->y = (cy - CY_ACTIONBMP) / 2;
  1160. pdobj->rcLabel.left = 0;
  1161. pdobj->rcLabel.right = cx;
  1162. pdobj->rcLabel.top = 0;
  1163. pdobj->rcLabel.bottom = cy;
  1164. // Draw the entry...
  1165. //
  1166. Dobj_Draw(hdc, &dobj, 1, lpcdis->itemState, 0, this->cyText, this->clrBkgnd);
  1167. // Clean up
  1168. //
  1169. SetViewportOrgEx(hdc, ptSav.x, ptSav.y, NULL);
  1170. }
  1171. /*----------------------------------------------------------
  1172. Purpose: WM_DRAWITEM handler
  1173. Returns: --
  1174. Cond: --
  1175. */
  1176. void PRIVATE RecAct_OnDrawItem(
  1177. LPRECACT this,
  1178. const DRAWITEMSTRUCT FAR * lpcdis)
  1179. {
  1180. switch (lpcdis->CtlType)
  1181. {
  1182. case ODT_LISTBOX:
  1183. RecAct_DrawLBItem(this, lpcdis);
  1184. break;
  1185. case ODT_MENU:
  1186. RecAct_DrawMenuItem(this, lpcdis);
  1187. break;
  1188. }
  1189. }
  1190. /*----------------------------------------------------------
  1191. Purpose: WM_COMPAREITEM handler
  1192. Returns: -1 (item 1 precedes item 2), 0 (equal), 1 (item 2 precedes item 1)
  1193. Cond: --
  1194. */
  1195. int PRIVATE RecAct_OnCompareItem(
  1196. LPRECACT this,
  1197. const COMPAREITEMSTRUCT FAR * lpcis)
  1198. {
  1199. LPRA_PRIV ppriv1 = (LPRA_PRIV)lpcis->itemData1;
  1200. LPRA_PRIV ppriv2 = (LPRA_PRIV)lpcis->itemData2;
  1201. // We sort based on name of file
  1202. //
  1203. return lstrcmpi(FIGetPath(ppriv1->pfi), FIGetPath(ppriv2->pfi));
  1204. }
  1205. /*----------------------------------------------------------
  1206. Purpose: WM_DELETEITEM handler
  1207. Returns: --
  1208. Cond: --
  1209. */
  1210. void RecAct_OnDeleteLBItem(
  1211. LPRECACT this,
  1212. const DELETEITEMSTRUCT FAR * lpcdis)
  1213. {
  1214. switch (lpcdis->CtlType)
  1215. {
  1216. case ODT_LISTBOX:
  1217. {
  1218. LPRA_PRIV ppriv = (LPRA_PRIV)lpcdis->itemData;
  1219. ASSERT(ppriv);
  1220. if (ppriv)
  1221. {
  1222. FIFree(ppriv->pfi);
  1223. GFree(ppriv->siInside.pszDir);
  1224. GFree(ppriv->siOutside.pszDir);
  1225. GFree(ppriv);
  1226. }
  1227. }
  1228. break;
  1229. }
  1230. }
  1231. /*----------------------------------------------------------
  1232. Purpose: WM_CTLCOLORLISTBOX handler
  1233. Returns: --
  1234. Cond: --
  1235. */
  1236. HBRUSH PRIVATE RecAct_OnCtlColorListBox(
  1237. LPRECACT this,
  1238. HDC hdc,
  1239. HWND hwndLB,
  1240. int nType)
  1241. {
  1242. return this->hbrBkgnd;
  1243. }
  1244. /*----------------------------------------------------------
  1245. Purpose: WM_PAINT handler
  1246. Returns: --
  1247. Cond: --
  1248. */
  1249. void RecAct_OnPaint(
  1250. LPRECACT this)
  1251. {
  1252. HWND hwnd = this->hwnd;
  1253. PAINTSTRUCT ps;
  1254. RECT rc;
  1255. HDC hdc;
  1256. hdc = BeginPaint(hwnd, &ps);
  1257. GetClientRect(hwnd, &rc);
  1258. if (IsFlagSet(this->lStyle, RAS_SINGLEITEM))
  1259. {
  1260. DrawEdge(hdc, &rc, BDR_SUNKENINNER, BF_TOPLEFT);
  1261. DrawEdge(hdc, &rc, BDR_SUNKENOUTER, BF_BOTTOMRIGHT);
  1262. }
  1263. else
  1264. {
  1265. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
  1266. }
  1267. EndPaint(hwnd, &ps);
  1268. }
  1269. /*----------------------------------------------------------
  1270. Purpose: WM_SETFONT handler
  1271. Returns: --
  1272. Cond: --
  1273. */
  1274. void RecAct_OnSetFont(
  1275. LPRECACT this,
  1276. HFONT hfont,
  1277. BOOL bRedraw)
  1278. {
  1279. this->hfont = hfont;
  1280. FORWARD_WM_SETFONT(this->hwnd, hfont, bRedraw, RecAct_DefProc);
  1281. }
  1282. /*----------------------------------------------------------
  1283. Purpose: WM_SETFOCUS handler
  1284. Returns: --
  1285. Cond: --
  1286. */
  1287. void RecAct_OnSetFocus(
  1288. LPRECACT this,
  1289. HWND hwndOldFocus)
  1290. {
  1291. SetFocus(this->hwndLB);
  1292. }
  1293. /*----------------------------------------------------------
  1294. Purpose: WM_SYSCOLORCHANGE handler
  1295. Returns: --
  1296. Cond: --
  1297. */
  1298. void RecAct_OnSysColorChange(
  1299. LPRECACT this)
  1300. {
  1301. RecAct_SetColors(this);
  1302. InvalidateRect(this->hwnd, NULL, TRUE);
  1303. }
  1304. /*----------------------------------------------------------
  1305. Purpose: Insert item
  1306. Returns: index
  1307. Cond: --
  1308. */
  1309. int PRIVATE RecAct_OnInsertItem(
  1310. LPRECACT this,
  1311. const LPRA_ITEM pitem)
  1312. {
  1313. HWND hwndLB = this->hwndLB;
  1314. LPRA_PRIV pprivNew;
  1315. char szPath[MAXPATHLEN];
  1316. int iRet = -1;
  1317. int iItem = LB_ERR;
  1318. ASSERT(pitem);
  1319. ASSERT(pitem->siInside.pszDir);
  1320. ASSERT(pitem->siOutside.pszDir);
  1321. ASSERT(pitem->pszName);
  1322. pprivNew = GAlloc(sizeof(*pprivNew));
  1323. if (pprivNew)
  1324. {
  1325. SetWindowRedraw(hwndLB, FALSE);
  1326. // Fill the prerequisite fields first
  1327. //
  1328. pprivNew->uStyle = pitem->uStyle;
  1329. pprivNew->uAction = pitem->uAction;
  1330. // Set the fileinfo stuff and large icon system-cache index.
  1331. // If we can't get the fileinfo of the inside file, get the outside
  1332. // file. If neither can be found, then we fail
  1333. //
  1334. lstrcpy(szPath, pitem->siInside.pszDir);
  1335. if (IsFlagClear(pitem->uStyle, RAIS_FOLDER))
  1336. PathAppend(szPath, pitem->pszName);
  1337. PathMakePresentable(szPath);
  1338. if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON)))
  1339. {
  1340. // Try the outside file
  1341. //
  1342. lstrcpy(szPath, pitem->siOutside.pszDir);
  1343. if (IsFlagClear(pitem->uStyle, RAIS_FOLDER))
  1344. PathAppend(szPath, pitem->pszName);
  1345. PathMakePresentable(szPath);
  1346. if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON)))
  1347. {
  1348. // Don't try to touch the file
  1349. if (FAILED(FICreate(szPath, &pprivNew->pfi, FIF_ICON | FIF_DONTTOUCH)))
  1350. goto Insert_Cleanup;
  1351. }
  1352. }
  1353. ASSERT(pprivNew->pfi);
  1354. pprivNew->pfi->lParam = (LPARAM)ImageList_AddIcon(this->himlCache, pprivNew->pfi->hicon);
  1355. // Fill in the rest of the fields
  1356. //
  1357. lstrcpy(szPath, pitem->siInside.pszDir);
  1358. if (IsFlagSet(pitem->uStyle, RAIS_FOLDER))
  1359. PathRemoveFileSpec(szPath);
  1360. PathMakePresentable(szPath);
  1361. if (!GSetString(&pprivNew->siInside.pszDir, szPath))
  1362. goto Insert_Cleanup;
  1363. pprivNew->siInside.uState = pitem->siInside.uState;
  1364. pprivNew->siInside.fs = pitem->siInside.fs;
  1365. lstrcpy(szPath, pitem->siOutside.pszDir);
  1366. if (IsFlagSet(pitem->uStyle, RAIS_FOLDER))
  1367. PathRemoveFileSpec(szPath);
  1368. PathMakePresentable(szPath);
  1369. if (!GSetString(&pprivNew->siOutside.pszDir, szPath))
  1370. goto Insert_Cleanup;
  1371. pprivNew->siOutside.uState = pitem->siOutside.uState;
  1372. pprivNew->siOutside.fs = pitem->siOutside.fs;
  1373. pprivNew->lParam = pitem->lParam;
  1374. pprivNew->cx = RECOMPUTE;
  1375. // We know we're doing a redundant sorted add if the element
  1376. // needs to be inserted at the end of the list, but who cares.
  1377. //
  1378. if (pitem->iItem >= RecAct_GetCount(this))
  1379. iItem = ListBox_AddString(hwndLB, pprivNew);
  1380. else
  1381. iItem = ListBox_InsertString(hwndLB, pitem->iItem, pprivNew);
  1382. if (iItem == LB_ERR)
  1383. goto Insert_Cleanup;
  1384. SetWindowRedraw(hwndLB, TRUE);
  1385. iRet = iItem;
  1386. }
  1387. goto Insert_End;
  1388. Insert_Cleanup:
  1389. // Have DeleteString handler clean up field allocations
  1390. // of pitem.
  1391. //
  1392. if (iItem != LB_ERR)
  1393. ListBox_DeleteString(hwndLB, iItem);
  1394. else
  1395. {
  1396. FIFree(pprivNew->pfi);
  1397. GFree(pprivNew);
  1398. }
  1399. SetWindowRedraw(hwndLB, TRUE);
  1400. Insert_End:
  1401. return iRet;
  1402. }
  1403. /*----------------------------------------------------------
  1404. Purpose: Delete item
  1405. Returns: count of items left
  1406. Cond: --
  1407. */
  1408. int PRIVATE RecAct_OnDeleteItem(
  1409. LPRECACT this,
  1410. int i)
  1411. {
  1412. HWND hwndLB = this->hwndLB;
  1413. return ListBox_DeleteString(hwndLB, i);
  1414. }
  1415. /*----------------------------------------------------------
  1416. Purpose: Delete all items
  1417. Returns: TRUE
  1418. Cond: --
  1419. */
  1420. BOOL PRIVATE RecAct_OnDeleteAllItems(
  1421. LPRECACT this)
  1422. {
  1423. ListBox_ResetContent(this->hwndLB);
  1424. return TRUE;
  1425. }
  1426. /*----------------------------------------------------------
  1427. Purpose: Get item
  1428. Returns: TRUE on success
  1429. Cond: --
  1430. */
  1431. BOOL PRIVATE RecAct_OnGetItem(
  1432. LPRECACT this,
  1433. LPRA_ITEM pitem)
  1434. {
  1435. LPRA_PRIV ppriv;
  1436. HWND hwndLB = this->hwndLB;
  1437. UINT uMask;
  1438. int iItem;
  1439. if (!pitem)
  1440. return FALSE;
  1441. iItem = pitem->iItem;
  1442. uMask = pitem->mask;
  1443. ListBox_GetText(hwndLB, iItem, &ppriv);
  1444. if (uMask & RAIF_ACTION)
  1445. pitem->uAction = ppriv->uAction;
  1446. if (uMask & RAIF_NAME)
  1447. pitem->pszName = FIGetPath(ppriv->pfi);
  1448. if (uMask & RAIF_STYLE)
  1449. pitem->uStyle = ppriv->uStyle;
  1450. if (uMask & RAIF_INSIDE)
  1451. pitem->siInside = ppriv->siInside;
  1452. if (uMask & RAIF_OUTSIDE)
  1453. pitem->siOutside = ppriv->siOutside;
  1454. if (uMask & RAIF_LPARAM)
  1455. pitem->lParam = ppriv->lParam;
  1456. return TRUE;
  1457. }
  1458. /*----------------------------------------------------------
  1459. Purpose: Set item
  1460. Returns: TRUE on success
  1461. Cond: --
  1462. */
  1463. BOOL PRIVATE RecAct_OnSetItem(
  1464. LPRECACT this,
  1465. LPRA_ITEM pitem)
  1466. {
  1467. LPRA_PRIV ppriv;
  1468. HWND hwndLB = this->hwndLB;
  1469. UINT uMask;
  1470. int iItem;
  1471. if (!pitem)
  1472. return FALSE;
  1473. uMask = pitem->mask;
  1474. iItem = pitem->iItem;
  1475. ListBox_GetText(hwndLB, iItem, &ppriv);
  1476. if (uMask & RAIF_ACTION)
  1477. ppriv->uAction = pitem->uAction;
  1478. if (uMask & RAIF_STYLE)
  1479. ppriv->uStyle = pitem->uStyle;
  1480. if (uMask & RAIF_NAME)
  1481. {
  1482. if (!FISetPath(&ppriv->pfi, pitem->pszName, FIF_ICON))
  1483. return FALSE;
  1484. ppriv->pfi->lParam = (LPARAM)ImageList_AddIcon(this->himlCache, ppriv->pfi->hicon);
  1485. }
  1486. if (uMask & RAIF_INSIDE)
  1487. {
  1488. if (!GSetString(&ppriv->siInside.pszDir, pitem->siInside.pszDir))
  1489. return FALSE;
  1490. ppriv->siInside.uState = pitem->siInside.uState;
  1491. ppriv->siInside.fs = pitem->siInside.fs;
  1492. }
  1493. if (uMask & RAIF_OUTSIDE)
  1494. {
  1495. if (!GSetString(&ppriv->siOutside.pszDir, pitem->siOutside.pszDir))
  1496. return FALSE;
  1497. ppriv->siOutside.uState = pitem->siOutside.uState;
  1498. ppriv->siOutside.fs = pitem->siOutside.fs;
  1499. }
  1500. if (uMask & RAIF_LPARAM)
  1501. ppriv->lParam = pitem->lParam;
  1502. return TRUE;
  1503. }
  1504. /*----------------------------------------------------------
  1505. Purpose: Get the current selection
  1506. Returns: index
  1507. Cond: --
  1508. */
  1509. int PRIVATE RecAct_OnGetCurSel(
  1510. LPRECACT this)
  1511. {
  1512. return ListBox_GetCurSel(this->hwndLB);
  1513. }
  1514. /*----------------------------------------------------------
  1515. Purpose: Set the current selection
  1516. Returns: --
  1517. Cond: --
  1518. */
  1519. int PRIVATE RecAct_OnSetCurSel(
  1520. LPRECACT this,
  1521. int i)
  1522. {
  1523. int iRet = ListBox_SetCurSel(this->hwndLB, i);
  1524. if (iRet != LB_ERR)
  1525. RecAct_SendSelChange(this, i);
  1526. return iRet;
  1527. }
  1528. /*----------------------------------------------------------
  1529. Purpose: Find an item
  1530. Returns: TRUE on success
  1531. Cond: --
  1532. */
  1533. int PRIVATE RecAct_OnFindItem(
  1534. LPRECACT this,
  1535. int iStart,
  1536. const RA_FINDITEM FAR * prafi)
  1537. {
  1538. HWND hwndLB = this->hwndLB;
  1539. UINT uMask = prafi->flags;
  1540. LPRA_PRIV ppriv;
  1541. BOOL bPass;
  1542. int i;
  1543. int cItems = ListBox_GetCount(hwndLB);
  1544. for (i = iStart+1; i < cItems; i++)
  1545. {
  1546. bPass = TRUE; // assume we pass
  1547. ListBox_GetText(hwndLB, i, &ppriv);
  1548. if (uMask & RAFI_NAME &&
  1549. !IsSzEqual(FIGetPath(ppriv->pfi), prafi->psz))
  1550. bPass = FALSE;
  1551. if (uMask & RAFI_ACTION && ppriv->uAction != prafi->uAction)
  1552. bPass = FALSE;
  1553. if (uMask & RAFI_LPARAM && ppriv->lParam != prafi->lParam)
  1554. bPass = FALSE;
  1555. if (bPass)
  1556. break; // found it
  1557. }
  1558. return i == cItems ? -1 : i;
  1559. }
  1560. ///////////////////////////////////////////////////// EXPORTED FUNCTIONS
  1561. /*----------------------------------------------------------
  1562. Purpose: RecAct window proc
  1563. Returns: varies
  1564. Cond: --
  1565. */
  1566. LRESULT CALLBACK RecAct_WndProc(
  1567. HWND hwnd,
  1568. UINT msg,
  1569. WPARAM wParam,
  1570. LPARAM lParam)
  1571. {
  1572. LPRECACT this = RecAct_GetPtr(hwnd);
  1573. if (this == NULL)
  1574. {
  1575. if (msg == WM_NCCREATE)
  1576. {
  1577. this = GAlloc(sizeof(*this));
  1578. ASSERT(this);
  1579. if (!this)
  1580. return 0L; // OOM failure
  1581. this->hwnd = hwnd;
  1582. RecAct_SetPtr(hwnd, this);
  1583. }
  1584. else
  1585. {
  1586. return RecAct_DefProc(hwnd, msg, wParam, lParam);
  1587. }
  1588. }
  1589. if (msg == WM_NCDESTROY)
  1590. {
  1591. GFree(this);
  1592. RecAct_SetPtr(hwnd, NULL);
  1593. }
  1594. switch (msg)
  1595. {
  1596. HANDLE_MSG(this, WM_CREATE, RecAct_OnCreate);
  1597. HANDLE_MSG(this, WM_DESTROY, RecAct_OnDestroy);
  1598. HANDLE_MSG(this, WM_SETFONT, RecAct_OnSetFont);
  1599. HANDLE_MSG(this, WM_COMMAND, RecAct_OnCommand);
  1600. HANDLE_MSG(this, WM_NOTIFY, RecAct_OnNotify);
  1601. HANDLE_MSG(this, WM_MEASUREITEM, RecAct_OnMeasureItem);
  1602. HANDLE_MSG(this, WM_DRAWITEM, RecAct_OnDrawItem);
  1603. HANDLE_MSG(this, WM_COMPAREITEM, RecAct_OnCompareItem);
  1604. HANDLE_MSG(this, WM_DELETEITEM, RecAct_OnDeleteLBItem);
  1605. HANDLE_MSG(this, WM_CONTEXTMENU, RecAct_OnContextMenu);
  1606. HANDLE_MSG(this, WM_SETFOCUS, RecAct_OnSetFocus);
  1607. HANDLE_MSG(this, WM_CTLCOLORLISTBOX, RecAct_OnCtlColorListBox);
  1608. HANDLE_MSG(this, WM_PAINT, RecAct_OnPaint);
  1609. HANDLE_MSG(this, WM_SYSCOLORCHANGE, RecAct_OnSysColorChange);
  1610. case RAM_GETITEMCOUNT:
  1611. return (LRESULT)RecAct_GetCount(this);
  1612. case RAM_GETITEM:
  1613. return (LRESULT)RecAct_OnGetItem(this, (LPRA_ITEM)lParam);
  1614. case RAM_SETITEM:
  1615. return (LRESULT)RecAct_OnSetItem(this, (const LPRA_ITEM)lParam);
  1616. case RAM_INSERTITEM:
  1617. return (LRESULT)RecAct_OnInsertItem(this, (const LPRA_ITEM)lParam);
  1618. case RAM_DELETEITEM:
  1619. return (LRESULT)RecAct_OnDeleteItem(this, (int)wParam);
  1620. case RAM_DELETEALLITEMS:
  1621. return (LRESULT)RecAct_OnDeleteAllItems(this);
  1622. case RAM_GETCURSEL:
  1623. return (LRESULT)RecAct_OnGetCurSel(this);
  1624. case RAM_SETCURSEL:
  1625. return (LRESULT)RecAct_OnSetCurSel(this, (int)wParam);
  1626. case RAM_FINDITEM:
  1627. return (LRESULT)RecAct_OnFindItem(this, (int)wParam, (const RA_FINDITEM FAR *)lParam);
  1628. case RAM_REFRESH:
  1629. RedrawWindow(this->hwndLB, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  1630. default:
  1631. return RecAct_DefProc(hwnd, msg, wParam, lParam);
  1632. }
  1633. }
  1634. ///////////////////////////////////////////////////// PUBLIC FUNCTIONS
  1635. /*----------------------------------------------------------
  1636. Purpose: Initialize the reconciliation-action window class
  1637. Returns: TRUE on success
  1638. Cond: --
  1639. */
  1640. BOOL PUBLIC RecAct_Init(HINSTANCE hinst)
  1641. {
  1642. WNDCLASSEX wc;
  1643. wc.cbSize = sizeof(WNDCLASSEX);
  1644. wc.style = CS_DBLCLKS | CS_OWNDC;
  1645. wc.lpfnWndProc = RecAct_WndProc;
  1646. wc.cbClsExtra = 0;
  1647. wc.cbWndExtra = sizeof(LPRECACT);
  1648. wc.hInstance = hinst;
  1649. wc.hIcon = NULL;
  1650. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  1651. wc.hbrBackground= NULL;
  1652. wc.lpszMenuName = NULL;
  1653. wc.lpszClassName= WC_RECACT;
  1654. wc.hIconSm = NULL;
  1655. return (RegisterClassEx(&wc) != 0);
  1656. }
  1657. /*----------------------------------------------------------
  1658. Purpose: Clean up RecAct window class
  1659. Returns: --
  1660. Cond: --
  1661. */
  1662. void PUBLIC RecAct_Term(
  1663. HINSTANCE hinst)
  1664. {
  1665. UnregisterClass(WC_RECACT, hinst);
  1666. }
  1667. /*----------------------------------------------------------
  1668. Purpose: Special sub-class listbox proc
  1669. Returns: varies
  1670. Cond: --
  1671. */
  1672. LRESULT _export CALLBACK RecActLB_LBProc(
  1673. HWND hwnd, // window handle
  1674. UINT msg, // window message
  1675. WPARAM wparam, // varies
  1676. LPARAM lparam) // varies
  1677. {
  1678. LRESULT lRet;
  1679. LPRECACT lpra = NULL;
  1680. // Get the instance data for the control
  1681. lpra = RecAct_GetPtr(GetParent(hwnd));
  1682. ASSERT(lpra);
  1683. switch (msg)
  1684. {
  1685. default:
  1686. lRet = RecActLB_DefProc(lpra->lpfnLBProc, hwnd, msg, wparam, lparam);
  1687. break;
  1688. }
  1689. return lRet;
  1690. }