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.

712 lines
20 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: dobj.c
  6. //
  7. // This file contains support routines for the reconciliation-action
  8. // control class code
  9. //
  10. //
  11. // History:
  12. // 09-13-93 ScottH Extracted from recact.c
  13. //
  14. //---------------------------------------------------------------------------
  15. ///////////////////////////////////////////////////// INCLUDES
  16. #include "brfprv.h" // common headers
  17. #include "res.h"
  18. #include "recact.h"
  19. #include "dobj.h"
  20. ///////////////////////////////////////////////////// CONTROLLING DEFINES
  21. ///////////////////////////////////////////////////// DEFINES
  22. #define DT_CALCWRAP (DT_CALCRECT | DT_CENTER | DT_WORDBREAK | DT_NOPREFIX)
  23. #define DT_CALC (DT_CALCRECT | DT_CENTER | DT_SINGLELINE | DT_NOPREFIX)
  24. /*----------------------------------------------------------
  25. Purpose: Formats the given path to the correct location format
  26. Returns: --
  27. Cond: --
  28. */
  29. void PRIVATE FormatLocationPath(
  30. LPCTSTR pszPath,
  31. LPTSTR pszBuffer,
  32. int cchMax) // Must be MAX_PATH
  33. {
  34. UINT ids;
  35. TCHAR szBrfDir[MAX_PATH];
  36. LPCTSTR psz;
  37. LPTSTR pszMsg;
  38. // The format for the directory location is:
  39. //
  40. // Inside briefcase: "In Briefcase"
  41. // Below briefcase: "In Briefcase\FolderName"
  42. // Outside briefcase: "In FullPath"
  43. //
  44. // We assume that paths outside the current briefcase
  45. // never consist of a briefcase name of another.
  46. //
  47. if (PathGetLocality(pszPath, szBrfDir, ARRAYSIZE(szBrfDir)) != PL_FALSE)
  48. {
  49. // Inside the briefcase
  50. psz = &pszPath[lstrlen(szBrfDir)];
  51. ids = IDS_InBriefcase;
  52. }
  53. else
  54. {
  55. // Outside the briefcase
  56. psz = pszPath;
  57. ids = IDS_InLocation;
  58. }
  59. if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(ids), psz))
  60. {
  61. lstrcpyn(pszBuffer, pszMsg, cchMax);
  62. GFree(pszMsg);
  63. }
  64. else
  65. *pszBuffer = 0;
  66. }
  67. /*----------------------------------------------------------
  68. Purpose: Return the string describing the status of this sideitem
  69. Returns: ptr to status string
  70. Cond: --
  71. */
  72. LPTSTR PRIVATE SideItem_GetStatus(
  73. LPSIDEITEM this,
  74. LPTSTR pszBuf,
  75. UINT cchBuf)
  76. {
  77. switch (this->uState)
  78. {
  79. case SI_CHANGED:
  80. return SzFromIDS(IDS_STATE_Changed, pszBuf, cchBuf);
  81. case SI_UNCHANGED:
  82. return SzFromIDS(IDS_STATE_Unchanged, pszBuf, cchBuf);
  83. case SI_NEW:
  84. return SzFromIDS(IDS_STATE_NewFile, pszBuf, cchBuf);
  85. case SI_UNAVAILABLE:
  86. return SzFromIDS(IDS_STATE_Unavailable, pszBuf, cchBuf);
  87. case SI_NOEXIST:
  88. return SzFromIDS(IDS_STATE_DoesNotExist, pszBuf, cchBuf);
  89. case SI_DELETED:
  90. return SzFromIDS(IDS_STATE_Deleted, pszBuf, cchBuf);
  91. default:
  92. ASSERT(0);
  93. return NULL;
  94. }
  95. }
  96. /*----------------------------------------------------------
  97. Purpose: Displays the 3-liner: location, status, and timestamp
  98. Returns: --
  99. Cond: --
  100. */
  101. void PRIVATE SideItem_Display(
  102. LPSIDEITEM this,
  103. HDC hdc,
  104. LPRECT prc,
  105. int cxEllipses,
  106. int cyText)
  107. {
  108. TCHAR sz[MAX_PATH];
  109. TCHAR szBuf[MAXBUFLEN];
  110. LPTSTR psz;
  111. RECT rc = *prc;
  112. // Directory location.
  113. FormatLocationPath(this->pszDir, sz, ARRAYSIZE(sz));
  114. MyDrawText(hdc, sz, &rc, MDT_LEFT | MDT_TRANSPARENT | MDT_ELLIPSES,
  115. cyText, cxEllipses, CLR_DEFAULT, CLR_DEFAULT);
  116. // Status string
  117. psz = SideItem_GetStatus(this, szBuf, ARRAYSIZE(szBuf));
  118. if (psz)
  119. {
  120. // Only bother with these two lines if the file actually
  121. // exists.
  122. rc.top += cyText;
  123. MyDrawText(hdc, psz, &rc, MDT_LEFT | MDT_TRANSPARENT,
  124. cyText, cxEllipses, CLR_DEFAULT, CLR_DEFAULT);
  125. // Date stamp. Skip this if this is a folder or unavailable.
  126. //
  127. if (SI_DELETED != this->uState &&
  128. SI_NOEXIST != this->uState &&
  129. SI_UNAVAILABLE != this->uState &&
  130. FS_COND_UNAVAILABLE != this->fs.fscond) // hack for folders
  131. {
  132. FileTimeToDateTimeString(&this->fs.ftMod, sz, ARRAYSIZE(sz));
  133. rc.top += cyText;
  134. MyDrawText(hdc, sz, &rc, MDT_LEFT | MDT_TRANSPARENT,
  135. cyText, cxEllipses, CLR_DEFAULT, CLR_DEFAULT);
  136. }
  137. }
  138. }
  139. /*----------------------------------------------------------
  140. Purpose: Return the bounding rect for a labelled image.
  141. Returns: --
  142. Cond: --
  143. */
  144. void PUBLIC ComputeImageRects(
  145. LPCTSTR psz,
  146. HDC hdc,
  147. LPPOINT pptInOut,
  148. LPRECT prcWhole, // May be NULL
  149. LPRECT prcLabel, // May be NULL
  150. int cxIcon,
  151. int cyIcon,
  152. int cxIconSpacing,
  153. int cyText)
  154. {
  155. RECT rc;
  156. int yLabel;
  157. int cxLabel;
  158. int cyLabel;
  159. int cchLabel;
  160. POINT pt;
  161. ASSERT(psz);
  162. // Set our minimum rect size for icon spacing
  163. if (cxIconSpacing < cxIcon)
  164. cxIconSpacing = cxIcon + g_cxIconMargin * 2;
  165. // Upon entry, *pptInOut is expected to be the upper left corner of the
  166. // icon-spacing rect. This function will set it to the upper left
  167. // corner of the icon itself.
  168. pt.x = pptInOut->x + (cxIconSpacing - cxIcon) / 2;
  169. pt.y = pptInOut->y + g_cyIconMargin;
  170. // Determine rectangle of label with wrap
  171. rc.left = rc.top = rc.bottom = 0;
  172. rc.right = cxIconSpacing - g_cxLabelMargin * 2;
  173. cchLabel = lstrlen(psz);
  174. if (0 < cchLabel)
  175. {
  176. DrawText(hdc, psz, cchLabel, &rc, DT_CALCWRAP);
  177. }
  178. else
  179. {
  180. rc.bottom = rc.top + cyText;
  181. }
  182. yLabel = pptInOut->y + g_cyIconMargin + cyIcon + g_cyLabelSpace;
  183. cxLabel = (rc.right - rc.left) + 2 * g_cxLabelMargin;
  184. cyLabel = rc.bottom - rc.top;
  185. if (prcWhole)
  186. {
  187. prcWhole->left = pptInOut->x;
  188. prcWhole->right = prcWhole->left + cxIconSpacing;
  189. prcWhole->top = pptInOut->y;
  190. prcWhole->bottom = max(prcWhole->top + g_cyIconSpacing,
  191. yLabel + cyLabel + g_cyLabelSpace);
  192. }
  193. if (prcLabel)
  194. {
  195. prcLabel->left = pptInOut->x + ((cxIconSpacing - cxLabel) / 2);
  196. prcLabel->right = prcLabel->left + cxLabel;
  197. prcLabel->top = yLabel;
  198. prcLabel->bottom = prcLabel->top + cyLabel;
  199. }
  200. *pptInOut = pt;
  201. }
  202. /*----------------------------------------------------------
  203. Purpose: Set the colors for the given HDC. The previous colors
  204. are stored in pcrText and pcrBk.
  205. Returns: uStyle to pass to ImageList_Draw (specific to images only)
  206. Cond: --
  207. */
  208. UINT PRIVATE Dobj_SetColors(
  209. LPDOBJ this,
  210. HDC hdc,
  211. UINT uState,
  212. COLORREF clrBkgnd)
  213. {
  214. COLORREF clrText;
  215. COLORREF clrBk;
  216. UINT uStyleILD = ILD_NORMAL;
  217. BOOL bSetColors = FALSE;
  218. BOOL bDiffer;
  219. BOOL bMenu;
  220. BOOL bDisabled;
  221. // Determine selection colors
  222. //
  223. bDiffer = IsFlagSet(this->uFlags, DOF_DIFFER);
  224. bMenu = IsFlagSet(this->uFlags, DOF_MENU);
  225. bDisabled = IsFlagSet(this->uFlags, DOF_DISABLED);
  226. switch (this->uKind)
  227. {
  228. case DOK_STRING:
  229. case DOK_IDS:
  230. case DOK_SIDEITEM:
  231. bSetColors = TRUE;
  232. break;
  233. }
  234. // Set the text and background colors
  235. //
  236. if (bSetColors)
  237. {
  238. if (bDiffer)
  239. {
  240. // Make the colors differ based on selection state
  241. //
  242. if (bMenu)
  243. {
  244. if (bDisabled)
  245. clrText = GetSysColor(COLOR_GRAYTEXT);
  246. else
  247. clrText = GetSysColor(ColorMenuText(uState));
  248. clrBk = GetSysColor(ColorMenuBk(uState));
  249. }
  250. else
  251. {
  252. if (bDisabled)
  253. clrText = GetSysColor(COLOR_GRAYTEXT);
  254. else
  255. clrText = GetSysColor(ColorText(uState));
  256. clrBk = GetSysColor(ColorBk(uState));
  257. }
  258. }
  259. else
  260. {
  261. // Transparent colors
  262. //
  263. if (bMenu)
  264. {
  265. if (bDisabled)
  266. clrText = GetSysColor(COLOR_GRAYTEXT);
  267. else
  268. clrText = GetSysColor(COLOR_MENUTEXT);
  269. clrBk = GetSysColor(COLOR_MENU);
  270. }
  271. else
  272. {
  273. if (bDisabled)
  274. clrText = GetSysColor(COLOR_GRAYTEXT);
  275. else
  276. clrText = GetSysColor(COLOR_WINDOWTEXT);
  277. clrBk = clrBkgnd;
  278. }
  279. }
  280. SetTextColor(hdc, clrText);
  281. SetBkColor(hdc, clrBk);
  282. }
  283. return uStyleILD;
  284. }
  285. /*----------------------------------------------------------
  286. Purpose: Draw the menu image and text
  287. Returns: --
  288. Cond: --
  289. */
  290. void PRIVATE Dobj_DrawMenuImage(
  291. LPDOBJ this,
  292. HDC hdc,
  293. UINT uState,
  294. int cyText,
  295. COLORREF clrBkgnd)
  296. {
  297. UINT uStyleILD;
  298. UINT uFlagsETO;
  299. LPCTSTR psz;
  300. TCHAR szIDS[MAXBUFLEN];
  301. int cch;
  302. HIMAGELIST himl = this->himl;
  303. COLORREF clrText;
  304. COLORREF clrBk;
  305. int x;
  306. int y;
  307. int cxIcon;
  308. RECT rc;
  309. if (IsFlagSet(this->uFlags, DOF_USEIDS))
  310. psz = SzFromIDS(PtrToUlong(this->lpvObject), szIDS, ARRAYSIZE(szIDS));
  311. else
  312. psz = (LPCTSTR)this->lpvObject;
  313. ASSERT(psz);
  314. cch = lstrlen(psz);
  315. ImageList_GetImageRect(himl, this->iImage, &rc);
  316. cxIcon = rc.right-rc.left;
  317. // Draw the text first
  318. uFlagsETO = ETO_OPAQUE | ETO_CLIPPED;
  319. x = this->rcLabel.left + g_cxMargin + cxIcon + g_cxMargin;
  320. y = this->rcLabel.top + ((this->rcLabel.bottom - this->rcLabel.top - cyText) / 2);
  321. if (IsFlagSet(this->uFlags, DOF_DISABLED) &&
  322. IsFlagClear(uState, ODS_SELECTED))
  323. {
  324. int imodeOld;
  325. COLORREF crOld;
  326. // For disabled menu strings (not selected), we draw the string
  327. // twice. The first is offset down and to the right and drawn
  328. // in the 3D hilight color. The second time is the disabled text
  329. // color in the normal offset.
  330. //
  331. crOld = SetTextColor(hdc, GetSysColor(COLOR_3DHILIGHT));
  332. imodeOld = SetBkMode(hdc, TRANSPARENT);
  333. ExtTextOut(hdc, x+1, y+1, uFlagsETO, &this->rcLabel, psz, cch, NULL);
  334. // Reset back to original color. Also, turn off the opaqueness.
  335. //
  336. SetTextColor(hdc, crOld);
  337. uFlagsETO ^= ETO_OPAQUE;
  338. }
  339. if (IsFlagSet(this->uFlags, DOF_DISABLED))
  340. clrText = GetSysColor(COLOR_GRAYTEXT);
  341. else
  342. clrText = GetSysColor(ColorMenuText(uState));
  343. clrBk = GetSysColor(ColorMenuBk(uState));
  344. SetTextColor(hdc, clrText);
  345. SetBkColor(hdc, clrBk);
  346. ExtTextOut(hdc, x, y, uFlagsETO, &this->rcLabel, psz, cch, NULL);
  347. // Draw the image
  348. if (GetBkColor(hdc) == ImageList_GetBkColor(himl))
  349. uStyleILD = ILD_NORMAL; // Paint quicker
  350. else
  351. uStyleILD = ILD_TRANSPARENT;
  352. ImageList_Draw(himl, this->iImage, hdc, this->x, this->y, uStyleILD);
  353. }
  354. /*----------------------------------------------------------
  355. Purpose: Draw the icon image and label
  356. Returns: --
  357. Cond: --
  358. */
  359. void PRIVATE Dobj_DrawIconImage(
  360. LPDOBJ this,
  361. HDC hdc,
  362. UINT uState,
  363. int cxEllipses,
  364. int cyText,
  365. COLORREF clrBkgnd)
  366. {
  367. UINT uStyleILD;
  368. UINT uFlagsMDT;
  369. LPCTSTR psz;
  370. TCHAR szIDS[MAXBUFLEN];
  371. if (IsFlagSet(this->uFlags, DOF_USEIDS))
  372. psz = SzFromIDS(PtrToUlong(this->lpvObject), szIDS, ARRAYSIZE(szIDS));
  373. else
  374. psz = (LPCTSTR)this->lpvObject;
  375. ASSERT(psz);
  376. // Draw the image
  377. //
  378. if (IsFlagClear(this->uFlags, DOF_IGNORESEL))
  379. {
  380. uStyleILD = GetImageDrawStyle(uState);
  381. uFlagsMDT = IsFlagSet(uState, ODS_SELECTED) ? MDT_SELECTED : MDT_DESELECTED;
  382. }
  383. else
  384. {
  385. uStyleILD = ILD_NORMAL;
  386. uFlagsMDT = MDT_DESELECTED;
  387. ClearFlag(uState, ODS_FOCUS);
  388. }
  389. ImageList_Draw(this->himl, this->iImage, hdc, this->x, this->y, uStyleILD);
  390. // Draw the file label. Wrap if it is long.
  391. if (this->rcLabel.bottom - this->rcLabel.top > cyText)
  392. uFlagsMDT |= MDT_DRAWTEXT;
  393. MyDrawText(hdc, psz, &this->rcLabel, MDT_CENTER | uFlagsMDT, cyText,
  394. cxEllipses, CLR_DEFAULT, clrBkgnd);
  395. // (uState may have been changed above)
  396. if (IsFlagSet(uState, ODS_FOCUS))
  397. DrawFocusRect(hdc, &this->rcLabel);
  398. }
  399. #ifdef UNUSED
  400. /*----------------------------------------------------------
  401. Purpose: Draw a picture
  402. Returns: --
  403. Cond: --
  404. */
  405. void PRIVATE Dobj_DrawPicture(
  406. LPDOBJ this,
  407. HDC hdc,
  408. UINT uState,
  409. UINT uDrawStyle)
  410. {
  411. HIMAGELIST himl;
  412. HDC hdcMem;
  413. HBITMAP hbmp;
  414. BITMAP bm;
  415. RECT rc;
  416. int iImage;
  417. int cx;
  418. int x;
  419. int y;
  420. switch (this->uKind)
  421. {
  422. case DOK_BITMAP:
  423. hbmp = (HBITMAP)this->lpvObject;
  424. GetObject(hbmp, sizeof(BITMAP), &bm);
  425. cx = this->rcSrc.right - this->rcSrc.left;
  426. break;
  427. case DOK_ICON:
  428. cx = 32;
  429. break;
  430. }
  431. // We only align horizontally
  432. //
  433. y = this->y;
  434. if (IsFlagSet(this->uFlags, DOF_CENTER))
  435. x = this->x - (cx / 2);
  436. else if (IsFlagSet(this->uFlags, DOF_RIGHT))
  437. x = this->x - cx;
  438. else
  439. x = this->x;
  440. // Draw the object
  441. //
  442. switch (this->uKind)
  443. {
  444. case DOK_ICON:
  445. // FEATURE: we don't handle DOF_DIFFER for icons
  446. DrawIcon(hdc, x, y, (HICON)this->lpvObject);
  447. break;
  448. case DOK_BITMAP:
  449. hdcMem = CreateCompatibleDC(hdc);
  450. if (hdcMem)
  451. {
  452. SIZE size;
  453. SelectBitmap(hdcMem, hbmp);
  454. size.cx = this->rcSrc.right - this->rcSrc.left;
  455. size.cy = this->rcSrc.bottom - this->rcSrc.top;
  456. if (IsFlagSet(this->uFlags, DOF_MENU) &&
  457. IsFlagSet(this->uFlags, DOF_DISABLED) &&
  458. IsFlagClear(uState, ODS_SELECTED))
  459. {
  460. COLORREF crOld;
  461. // For disabled menu strings (not selected), we draw the bitmap
  462. // twice. The first is offset down and to the right and drawn
  463. // in the 3D hilight color. The second time is the disabled
  464. // color in the normal offset.
  465. //
  466. crOld = SetTextColor(hdc, GetSysColor(COLOR_3DHILIGHT));
  467. BitBlt(hdc, x+1, y+1, size.cx, size.cy, hdcMem, this->rcSrc.left,
  468. this->rcSrc.top, SRCCOPY);
  469. // Reset back to original color. Also, turn off the opaqueness.
  470. //
  471. SetTextColor(hdc, crOld);
  472. }
  473. BitBlt(hdc, x, y, size.cx, size.cy, hdcMem, this->rcSrc.left, this->rcSrc.top, SRCCOPY);
  474. DeleteDC(hdcMem);
  475. }
  476. break;
  477. }
  478. }
  479. #endif
  480. /*----------------------------------------------------------
  481. Purpose: Draw a string
  482. Returns: --
  483. Cond: --
  484. */
  485. void PRIVATE Dobj_DrawString(
  486. LPDOBJ this,
  487. HDC hdc,
  488. UINT uState,
  489. int cxEllipses,
  490. int cyText)
  491. {
  492. UINT ufAlignSav;
  493. ASSERT(this);
  494. // Prep the alignment
  495. //
  496. if (this->uFlags & (DOF_LEFT | DOF_CENTER | DOF_RIGHT))
  497. {
  498. UINT ufMode;
  499. ufMode = IsFlagSet(this->uFlags, DOF_CENTER) ? TA_CENTER :
  500. (IsFlagSet(this->uFlags, DOF_RIGHT) ? TA_RIGHT : TA_LEFT);
  501. ufAlignSav = SetTextAlign(hdc, ufMode);
  502. }
  503. // Draw the string
  504. //
  505. switch (this->uKind)
  506. {
  507. case DOK_IDS:
  508. case DOK_STRING:
  509. {
  510. TCHAR szBuf[MAXBUFLEN];
  511. LPTSTR lpsz;
  512. UINT uflag = ETO_OPAQUE;
  513. if (this->uKind == DOK_IDS)
  514. lpsz = SzFromIDS(PtrToUlong(this->lpvObject), szBuf, ARRAYSIZE(szBuf));
  515. else
  516. lpsz = (LPTSTR)this->lpvObject;
  517. if (!IsRectEmpty(&this->rcClip))
  518. uflag |= ETO_CLIPPED;
  519. if (IsFlagSet(this->uFlags, DOF_MENU) &&
  520. IsFlagSet(this->uFlags, DOF_DISABLED) &&
  521. IsFlagClear(uState, ODS_SELECTED))
  522. {
  523. int imodeOld;
  524. COLORREF crOld;
  525. // For disabled menu strings (not selected), we draw the string
  526. // twice. The first is offset down and to the right and drawn
  527. // in the 3D hilight color. The second time is the disabled text
  528. // color in the normal offset.
  529. //
  530. crOld = SetTextColor(hdc, GetSysColor(COLOR_3DHILIGHT));
  531. imodeOld = SetBkMode(hdc, TRANSPARENT);
  532. ExtTextOut(hdc, this->x+1, this->y+1, uflag, &this->rcClip, lpsz,
  533. lstrlen(lpsz), NULL);
  534. // Reset back to original color. Also, turn off the opaqueness.
  535. //
  536. SetTextColor(hdc, crOld);
  537. uflag ^= ETO_OPAQUE;
  538. }
  539. ExtTextOut(hdc, this->x, this->y, uflag, &this->rcClip, lpsz,
  540. lstrlen(lpsz), NULL);
  541. }
  542. break;
  543. case DOK_SIDEITEM:
  544. SideItem_Display((LPSIDEITEM)this->lpvObject, hdc, &this->rcClip,
  545. cxEllipses, cyText);
  546. break;
  547. }
  548. // Clean up
  549. //
  550. if (this->uFlags & (DOF_LEFT | DOF_CENTER | DOF_RIGHT))
  551. {
  552. SetTextAlign(hdc, ufAlignSav);
  553. }
  554. }
  555. /*----------------------------------------------------------
  556. Purpose: Draw an object
  557. Returns: --
  558. Cond: --
  559. */
  560. void PUBLIC Dobj_Draw(
  561. HDC hdc,
  562. LPDOBJ rgdobj,
  563. int cItems,
  564. UINT uState, // ODS_*
  565. int cxEllipses,
  566. int cyText,
  567. COLORREF clrBkgnd)
  568. {
  569. UINT uDrawStyle;
  570. LPDOBJ pdobj;
  571. int i;
  572. ASSERT(rgdobj);
  573. //Bug 199701, 199647, 199699
  574. if (g_bMirroredOS)
  575. {
  576. SetLayout(hdc, LAYOUT_RTL);
  577. }
  578. //End bug 199701, 199647, 199699
  579. for (i = 0, pdobj = rgdobj; i < cItems; i++, pdobj++)
  580. {
  581. if (IsFlagSet(pdobj->uFlags, DOF_NODRAW))
  582. continue ;
  583. uDrawStyle = Dobj_SetColors(pdobj, hdc, uState, clrBkgnd);
  584. // Draw the object
  585. //
  586. switch (pdobj->uKind)
  587. {
  588. case DOK_IMAGE:
  589. if (IsFlagSet(pdobj->uFlags, DOF_MENU))
  590. Dobj_DrawMenuImage(pdobj, hdc, uState, cyText, clrBkgnd);
  591. else
  592. Dobj_DrawIconImage(pdobj, hdc, uState, cxEllipses, cyText, clrBkgnd);
  593. break;
  594. #ifdef UNUSED
  595. case DOK_BITMAP:
  596. case DOK_ICON:
  597. Dobj_DrawPicture(pdobj, hdc, uState, uDrawStyle);
  598. break;
  599. #endif
  600. case DOK_IDS:
  601. case DOK_STRING:
  602. case DOK_SIDEITEM:
  603. Dobj_DrawString(pdobj, hdc, uState, cxEllipses, cyText);
  604. break;
  605. }
  606. }
  607. }