Source code of Windows XP (NT5)
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.

659 lines
18 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: stdbar.cpp
  7. //
  8. // Contents: Standard toolbar implementation.
  9. //
  10. // History: 10/22/1999 AnandhaG Created
  11. //____________________________________________________________________________
  12. //
  13. #include "stdafx.h"
  14. #include "stdbar.h"
  15. #include "amcview.h"
  16. #include "toolbar.h"
  17. #include "util.h" // GetTBBtnTextAndStatus()
  18. using namespace std;
  19. /*
  20. * These are used only to give the separators unique IDs, so automatic
  21. * separator handling will work (see AssertSeparatorsAreValid).
  22. */
  23. enum
  24. {
  25. ID_Separator1 = 1,
  26. ID_Separator2,
  27. ID_Separator3,
  28. ID_Separator4,
  29. ID_Separator5,
  30. ID_Separator6,
  31. ID_Separator7,
  32. ID_Separator8,
  33. ID_Separator9,
  34. // must be last
  35. ID_SeparatorFirst = ID_Separator1,
  36. ID_SeparatorLast = ID_Separator9,
  37. ID_SeparatorMax = ID_SeparatorLast,
  38. };
  39. static MMCBUTTON CommonButtons[] =
  40. {
  41. { 0, IDS_MMC_WEB_BACK , TBSTATE_ENABLED, TBSTYLE_BUTTON, NULL, NULL },
  42. { 1, IDS_MMC_WEB_FORWARD , TBSTATE_ENABLED, TBSTYLE_BUTTON, NULL, NULL },
  43. { 0, ID_Separator1 , 0, TBSTYLE_SEP , NULL, NULL },
  44. { 9, IDS_MMC_GENL_UPONELEVEL , TBSTATE_ENABLED, TBSTYLE_BUTTON, NULL, NULL },
  45. {10, IDS_MMC_GENL_SCOPE , TBSTATE_ENABLED, TBSTYLE_BUTTON, NULL, NULL },
  46. { 0, ID_Separator2 , 0, TBSTYLE_SEP , NULL, NULL },
  47. { 5, IDS_MMC_VERB_CUT , 0, TBSTYLE_BUTTON, NULL, NULL },
  48. { 6, IDS_MMC_VERB_COPY , 0, TBSTYLE_BUTTON, NULL, NULL },
  49. { 7, IDS_MMC_VERB_PASTE , 0, TBSTYLE_BUTTON, NULL, NULL },
  50. { 0, ID_Separator3 , 0, TBSTYLE_SEP , NULL, NULL },
  51. {11, IDS_MMC_VERB_DELETE , 0, TBSTYLE_BUTTON, NULL, NULL },
  52. { 8, IDS_MMC_VERB_PROPERTIES , 0, TBSTYLE_BUTTON, NULL, NULL },
  53. {12, IDS_MMC_VERB_PRINT , 0, TBSTYLE_BUTTON, NULL, NULL },
  54. {13, IDS_MMC_VERB_REFRESH , 0, TBSTYLE_BUTTON, NULL, NULL },
  55. {16, IDS_SAVE_LIST_BUTTON , 0, TBSTYLE_BUTTON, NULL, NULL },
  56. { 0, ID_Separator4 , 0, TBSTYLE_SEP , NULL, NULL },
  57. {15, IDS_MMC_GENL_CONTEXTHELP , TBSTATE_ENABLED, TBSTYLE_BUTTON, NULL, NULL },
  58. };
  59. CStandardToolbar::CStandardToolbar()
  60. :m_pToolbarUI(NULL), m_pAMCView(NULL)
  61. {
  62. /*
  63. * Map helps in determining string id from verb & vice versa.
  64. */
  65. m_MMCVerbCommandIDs[MMC_VERB_CUT] = IDS_MMC_VERB_CUT;
  66. m_MMCVerbCommandIDs[MMC_VERB_CUT] = IDS_MMC_VERB_CUT;
  67. m_MMCVerbCommandIDs[MMC_VERB_COPY] = IDS_MMC_VERB_COPY;
  68. m_MMCVerbCommandIDs[MMC_VERB_PASTE] = IDS_MMC_VERB_PASTE;
  69. m_MMCVerbCommandIDs[MMC_VERB_DELETE] = IDS_MMC_VERB_DELETE;
  70. m_MMCVerbCommandIDs[MMC_VERB_PROPERTIES] = IDS_MMC_VERB_PROPERTIES;
  71. m_MMCVerbCommandIDs[MMC_VERB_PRINT] = IDS_MMC_VERB_PRINT;
  72. m_MMCVerbCommandIDs[MMC_VERB_REFRESH] = IDS_MMC_VERB_REFRESH;
  73. }
  74. CStandardToolbar::~CStandardToolbar()
  75. {
  76. DECLARE_SC(sc, TEXT("CStandardToolbar::~CStandardToolbar"));
  77. // Ask the toolbar UI object to delete itself.
  78. if (m_pToolbarUI)
  79. {
  80. sc = m_pToolbarUI->ScDelete(this);
  81. if (sc)
  82. sc.TraceAndClear();
  83. }
  84. }
  85. //+-------------------------------------------------------------------
  86. //
  87. // Member: ScInitializeStdToolbar
  88. //
  89. // Synopsis: Initialize the standard toolbar, add bitmap & buttons.
  90. //
  91. // Arguments: [pAMCView] - The CAMCView (owner) of this stdbar.
  92. //
  93. // Returns: SC
  94. //
  95. //--------------------------------------------------------------------
  96. SC CStandardToolbar::ScInitializeStdToolbar(CAMCView* pAMCView)
  97. {
  98. DECLARE_SC (sc, _T("CStandardToolbar::ScInitializeStdToolbar"));
  99. if (NULL == pAMCView)
  100. return (sc = E_UNEXPECTED);
  101. m_pAMCView = pAMCView;
  102. SViewData* pViewData = m_pAMCView->GetViewData();
  103. if (NULL == pViewData)
  104. {
  105. sc = E_UNEXPECTED;
  106. return sc;
  107. }
  108. // Get the toolbars mgr from CAMCView and create the stdandrd toolbar.
  109. CAMCViewToolbarsMgr* pAMCViewToolbarsMgr = pViewData->GetAMCViewToolbarsMgr();
  110. if (NULL == pAMCViewToolbarsMgr)
  111. {
  112. sc = E_UNEXPECTED;
  113. return sc;
  114. }
  115. sc = pAMCViewToolbarsMgr->ScCreateToolBar(&m_pToolbarUI);
  116. if (sc)
  117. return sc;
  118. ASSERT(NULL != m_pToolbarUI);
  119. // Add the bitmap
  120. CBitmap cBmp;
  121. cBmp.LoadBitmap((pAMCView->GetExStyle() & WS_EX_LAYOUTRTL) ? IDB_COMMON_16_RTL : IDB_COMMON_16);
  122. BITMAP bm;
  123. cBmp.GetBitmap (&bm);
  124. int cBitmaps = (bm.bmWidth / BUTTON_BITMAP_SIZE) /*width*/;
  125. sc = m_pToolbarUI->ScAddBitmap(this, cBitmaps, cBmp, MMC_TOOLBTN_COLORREF);
  126. if (sc)
  127. return sc;
  128. // Add the buttons to the toolbar and then display toolbar
  129. sc = ScAddToolbarButtons(countof(CommonButtons), CommonButtons);
  130. if (sc)
  131. return sc;
  132. // See if Std bar is allowed or not.
  133. bool bShowStdbar = (pViewData->m_dwToolbarsDisplayed & STD_BUTTONS);
  134. sc = bShowStdbar ? m_pToolbarUI->ScAttach(this) : m_pToolbarUI->ScDetach(this);
  135. if (sc)
  136. return sc;
  137. return sc;
  138. }
  139. //+-------------------------------------------------------------------
  140. //
  141. // Member: ScAddToolbarButtons
  142. //
  143. // Synopsis: Add buttons to standard toolbar.
  144. //
  145. // Arguments: [nCnt] - Number of buttons to be added.
  146. // [pButtons] - Array of nCnt MMCBUTTONS.
  147. //
  148. // Returns: SC
  149. //
  150. //--------------------------------------------------------------------
  151. SC CStandardToolbar::ScAddToolbarButtons(int nCnt, MMCBUTTON* pButtons)
  152. {
  153. DECLARE_SC (sc, _T("CStandardToolbar::ScAddToolbarButtons"));
  154. // Array to store button text & tooltip text.
  155. wstring szButtonText[countof(CommonButtons)];
  156. wstring szTooltipText[countof(CommonButtons)];
  157. USES_CONVERSION;
  158. HINSTANCE hInst = GetStringModule();
  159. // get resource strings for all buttons
  160. for (int i = 0; i < nCnt; i++)
  161. {
  162. // We dont want to get text for separators.
  163. if (pButtons[i].idCommand > ID_SeparatorMax)
  164. {
  165. bool bSuccess = GetTBBtnTextAndStatus(hInst,
  166. pButtons[i].idCommand,
  167. szButtonText[i],
  168. szTooltipText[i]);
  169. if (false == bSuccess)
  170. {
  171. return (sc = E_FAIL);
  172. }
  173. pButtons[i].lpButtonText = const_cast<LPOLESTR>(szButtonText[i].data());
  174. pButtons[i].lpTooltipText = const_cast<LPOLESTR>(szTooltipText[i].data());
  175. }
  176. }
  177. // Got the strings, now add buttons.
  178. sc = m_pToolbarUI->ScAddButtons(this, nCnt, pButtons);
  179. if (sc)
  180. return sc;
  181. return sc;
  182. }
  183. //+-------------------------------------------------------------------
  184. //
  185. // Member: ScNotifyToolBarClick
  186. //
  187. // Synopsis: Button click handler.
  188. //
  189. // Arguments: [hNode] - The HNODE owner of the view.
  190. // [bScope] - Focus on scope or result.
  191. // [lParam] - if result the lParam of focused result item.
  192. // [nID] - Button ID that was clicked.
  193. //
  194. // Returns: SC
  195. //
  196. //--------------------------------------------------------------------
  197. SC CStandardToolbar::ScNotifyToolBarClick(HNODE hNode, bool bScope, LPARAM lParam, UINT nID)
  198. {
  199. DECLARE_SC (sc, _T("CStandardToolbar::ScNotifyToolBarClick"));
  200. if (NULL == m_pAMCView)
  201. return (sc = E_UNEXPECTED);
  202. switch (nID)
  203. {
  204. case IDS_MMC_VERB_CUT:
  205. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evCut);
  206. break;
  207. case IDS_MMC_VERB_COPY:
  208. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evCopy);
  209. break;
  210. case IDS_MMC_VERB_PASTE:
  211. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evPaste);
  212. break;
  213. case IDS_MMC_VERB_DELETE:
  214. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evDelete);
  215. break;
  216. case IDS_MMC_VERB_PROPERTIES:
  217. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evProperties);
  218. break;
  219. case IDS_MMC_VERB_PRINT:
  220. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evPrint);
  221. break;
  222. case IDS_MMC_VERB_REFRESH:
  223. sc = m_pAMCView->ScProcessConsoleVerb (hNode, bScope, lParam, evRefresh);
  224. break;
  225. case IDS_MMC_GENL_CONTEXTHELP:
  226. sc = m_pAMCView->ScContextHelp ();
  227. break;
  228. case IDS_MMC_GENL_UPONELEVEL:
  229. sc = m_pAMCView->ScUpOneLevel ();
  230. break;
  231. case IDS_MMC_GENL_SCOPE:
  232. sc = m_pAMCView->ScToggleScopePane ();
  233. break;
  234. case IDS_MMC_WEB_BACK:
  235. sc = m_pAMCView->ScWebCommand (CConsoleView::eWeb_Back);
  236. break;
  237. case IDS_MMC_WEB_FORWARD:
  238. sc = m_pAMCView->ScWebCommand (CConsoleView::eWeb_Forward);
  239. break;
  240. case IDS_MMC_WEB_STOP:
  241. sc = m_pAMCView->ScWebCommand (CConsoleView::eWeb_Stop);
  242. break;
  243. case IDS_MMC_WEB_REFRESH:
  244. sc = m_pAMCView->ScWebCommand (CConsoleView::eWeb_Refresh);
  245. break;
  246. case IDS_MMC_WEB_HOME:
  247. sc = m_pAMCView->ScWebCommand (CConsoleView::eWeb_Home);
  248. break;
  249. case IDS_SAVE_LIST_BUTTON:
  250. sc = m_pAMCView->ScSaveList ();
  251. break;
  252. default:
  253. sc = E_UNEXPECTED;
  254. TraceError(_T("Unknown Standard bar button ID"), sc);
  255. break;
  256. }
  257. return sc;
  258. }
  259. //+-------------------------------------------------------------------
  260. //
  261. // Member: CStandardToolbar::ScAMCViewToolbarsBeingDestroyed
  262. //
  263. // Synopsis: The CAMCViewToolbars object is going away, do not
  264. // reference that object anymore.
  265. //
  266. // Arguments:
  267. //
  268. // Returns: SC
  269. //
  270. //--------------------------------------------------------------------
  271. SC CStandardToolbar::ScAMCViewToolbarsBeingDestroyed ()
  272. {
  273. DECLARE_SC(sc, _T("CStandardToolbar::ScAMCViewToolbarsBeingDestroyed"));
  274. m_pToolbarUI = NULL;
  275. return (sc);
  276. }
  277. //+-------------------------------------------------------------------
  278. //
  279. // Member: ScEnableButton
  280. //
  281. // Synopsis: Enable/Disable given button.
  282. //
  283. // Arguments:
  284. // [nID] - Button ID that should be enabled/disabled.
  285. // [bool] - Enable or Disable.
  286. //
  287. // Returns: SC
  288. //
  289. //--------------------------------------------------------------------
  290. SC CStandardToolbar::ScEnableButton(INT nID, bool bState)
  291. {
  292. SC sc;
  293. if (NULL == m_pToolbarUI)
  294. return (sc = E_UNEXPECTED);
  295. sc = m_pToolbarUI->ScSetButtonState(this, nID, TBSTATE_ENABLED, bState);
  296. if (sc)
  297. return sc;
  298. return sc;
  299. }
  300. //+-------------------------------------------------------------------
  301. //
  302. // Member: ScEnableAndShowButton
  303. //
  304. // Synopsis: Enable (and show) or disable (and hide) the given button.
  305. //
  306. // Arguments:
  307. // [nID] - Button ID that should be enabled/disabled.
  308. // [bool] - If true enable else hide.
  309. //
  310. // Note: If the button is being disabled hide it.
  311. //
  312. // Returns: SC
  313. //
  314. //--------------------------------------------------------------------
  315. SC CStandardToolbar::ScEnableAndShowButton(INT nID, bool bEnableAndShow)
  316. {
  317. DECLARE_SC(sc, _T("CStandardToolbar::ScEnableAndShowButton"));
  318. sc = ScCheckPointers(m_pToolbarUI, E_UNEXPECTED);
  319. if (sc)
  320. return sc;
  321. // First hide or show the button.
  322. sc = m_pToolbarUI->ScSetButtonState(this, nID, TBSTATE_HIDDEN, !bEnableAndShow);
  323. if (sc)
  324. return sc;
  325. // Now enable or disable the button.
  326. sc = m_pToolbarUI->ScSetButtonState(this, nID, TBSTATE_ENABLED, bEnableAndShow);
  327. if (sc)
  328. return sc;
  329. return sc;
  330. }
  331. //+-------------------------------------------------------------------
  332. //
  333. // Member: ScEnableExportList
  334. //
  335. // Synopsis: Enable/Disable export-list button.
  336. //
  337. // Arguments: [bEnable] - enable/disable.
  338. //
  339. // Returns: SC
  340. //
  341. //--------------------------------------------------------------------
  342. SC CStandardToolbar::ScEnableExportList(bool bEnable)
  343. {
  344. // If there are ANY items on the list, enable the button.
  345. return ScEnableAndShowButton(IDS_SAVE_LIST_BUTTON, bEnable );
  346. }
  347. //+-------------------------------------------------------------------
  348. //
  349. // Member: ScEnableUpOneLevel
  350. //
  351. // Synopsis: Enable/Disable up-one-level button.
  352. //
  353. // Arguments: [bEnable] -
  354. //
  355. //--------------------------------------------------------------------
  356. SC CStandardToolbar::ScEnableUpOneLevel(bool bEnable)
  357. {
  358. return ScEnableAndShowButton(IDS_MMC_GENL_UPONELEVEL, bEnable);
  359. }
  360. //+-------------------------------------------------------------------
  361. //
  362. // Member: ScEnableContextHelpBtn
  363. //
  364. // Synopsis: Enable/Disable help button.
  365. //
  366. // Arguments: [bEnable] -
  367. //
  368. //--------------------------------------------------------------------
  369. SC CStandardToolbar::ScEnableContextHelpBtn(bool bEnable)
  370. {
  371. return ScEnableAndShowButton(IDS_MMC_GENL_CONTEXTHELP, bEnable);
  372. }
  373. //+-------------------------------------------------------------------
  374. //
  375. // Member: ScEnableScopePaneBtn
  376. //
  377. // Synopsis: Enable/Disable scope-pane button.
  378. //
  379. // Arguments: [bEnable] -
  380. //
  381. //--------------------------------------------------------------------
  382. SC CStandardToolbar::ScEnableScopePaneBtn(bool bEnable)
  383. {
  384. return ScEnableAndShowButton(IDS_MMC_GENL_SCOPE, bEnable);
  385. }
  386. //+-------------------------------------------------------------------
  387. //
  388. // Member: ScCheckScopePaneBtn
  389. //
  390. // Synopsis: Set scope button in normal or checked state.
  391. //
  392. // Arguments: [bChecked] - BOOL
  393. //
  394. //--------------------------------------------------------------------
  395. SC CStandardToolbar::ScCheckScopePaneBtn(bool bChecked)
  396. {
  397. SC sc;
  398. if (NULL == m_pToolbarUI)
  399. return (sc = E_UNEXPECTED);
  400. sc = m_pToolbarUI->ScSetButtonState(this, IDS_MMC_GENL_SCOPE, TBSTATE_CHECKED, bChecked);
  401. return sc;
  402. }
  403. //+-------------------------------------------------------------------
  404. //
  405. // Member: ScShowStdBar
  406. //
  407. // Synopsis: Show or Hide std bar.
  408. //
  409. // Arguments: [bShow] - BOOL
  410. //
  411. //--------------------------------------------------------------------
  412. SC CStandardToolbar::ScShowStdBar(bool bShow)
  413. {
  414. SC sc;
  415. if (NULL == m_pToolbarUI)
  416. return (sc = E_UNEXPECTED);
  417. sc = bShow ? m_pToolbarUI->ScAttach(this) : m_pToolbarUI->ScDetach(this);
  418. if (sc)
  419. return sc;
  420. return sc;
  421. }
  422. //+-------------------------------------------------------------------
  423. //
  424. // Member: ScUpdateStdbarVerbs
  425. //
  426. // Synopsis: Update the toolbuttons of std-verbs.
  427. //
  428. // Arguments: [pCV] - the IConsoleVerb that has state of the verb.
  429. //
  430. // Returns: SC.
  431. //
  432. //--------------------------------------------------------------------
  433. SC CStandardToolbar::ScUpdateStdbarVerbs(IConsoleVerb* pCV)
  434. {
  435. DECLARE_SC (sc, _T("CStandardToolbar::ScUpdateStdbarVerbs"));
  436. for (int verb = MMC_VERB_FIRST; verb <= MMC_VERB_LAST; verb++)
  437. {
  438. // No toolbar buttons for following verbs.
  439. if ( (MMC_VERB_OPEN == verb) ||
  440. (MMC_VERB_RENAME == verb))
  441. continue;
  442. sc = ScUpdateStdbarVerb (static_cast<MMC_CONSOLE_VERB>(verb), pCV);
  443. if (sc)
  444. return sc;
  445. }
  446. return sc;
  447. }
  448. //+-------------------------------------------------------------------
  449. //
  450. // Member: ScUpdateStdbarVerb
  451. //
  452. // Synopsis: Update the toolbutton of given std-verbs.
  453. //
  454. // Arguments: [cVerb] - the verb (ie: toolbutton) to be updated.
  455. // [pVC] - the IConsoleVerb that has state of the verb.
  456. //
  457. //--------------------------------------------------------------------
  458. SC CStandardToolbar::ScUpdateStdbarVerb(MMC_CONSOLE_VERB cVerb, IConsoleVerb* pConsoleVerb /*=NULL*/)
  459. {
  460. DECLARE_SC (sc, _T("CStandardToolbar::ScUpdateStdbarVerb"));
  461. if (NULL == m_pToolbarUI)
  462. {
  463. sc = E_UNEXPECTED;
  464. return sc;
  465. }
  466. if (pConsoleVerb == NULL)
  467. {
  468. sc = E_UNEXPECTED;
  469. return sc;
  470. }
  471. // No toolbuttons for these verbs.
  472. if ( (MMC_VERB_OPEN == cVerb) ||
  473. (MMC_VERB_RENAME == cVerb))
  474. return sc;
  475. MMCVerbCommandIDs::iterator it = m_MMCVerbCommandIDs.find(cVerb);
  476. if (m_MMCVerbCommandIDs.end() == it)
  477. {
  478. // Could not find the verb in our map.
  479. sc = E_UNEXPECTED;
  480. return sc;
  481. }
  482. INT nCommandID = it->second;
  483. BOOL bFlag = 0;
  484. pConsoleVerb->GetVerbState(cVerb, HIDDEN, &bFlag);
  485. sc = m_pToolbarUI->ScSetButtonState(this, nCommandID, TBSTATE_HIDDEN, bFlag);
  486. if (sc)
  487. return sc;
  488. if (bFlag == FALSE)
  489. {
  490. // If verb is not hidden then enable/disable it.
  491. pConsoleVerb->GetVerbState(cVerb, ENABLED, &bFlag);
  492. sc = m_pToolbarUI->ScSetButtonState(this, nCommandID, TBSTATE_ENABLED, bFlag);
  493. if (sc)
  494. return sc;
  495. }
  496. return sc;
  497. }
  498. //+-------------------------------------------------------------------
  499. //
  500. // Member: ScUpdateStdbarVerb
  501. //
  502. // Synopsis: Update the toolbutton of given std-verb.
  503. //
  504. // Arguments: [cVerb] - the verb (ie: toolbutton) to be updated.
  505. // [nState] - the button state to be updated.
  506. // [bFlag] - State
  507. //
  508. //--------------------------------------------------------------------
  509. SC CStandardToolbar::ScUpdateStdbarVerb (MMC_CONSOLE_VERB cVerb, BYTE byState, BOOL bFlag)
  510. {
  511. DECLARE_SC (sc, _T("CStandardToolbar::ScUpdateStdbarVerb"));
  512. if (NULL == m_pToolbarUI)
  513. {
  514. sc = E_UNEXPECTED;
  515. return sc;
  516. }
  517. MMCVerbCommandIDs::iterator it = m_MMCVerbCommandIDs.find(cVerb);
  518. if (m_MMCVerbCommandIDs.end() == it)
  519. {
  520. // Could not find the verb in our map.
  521. sc = E_UNEXPECTED;
  522. return sc;
  523. }
  524. INT nCommandID = it->second;
  525. sc = m_pToolbarUI->ScSetButtonState(this, nCommandID, byState, bFlag);
  526. if (sc)
  527. return sc;
  528. return sc;
  529. }
  530. //+-------------------------------------------------------------------
  531. //
  532. // Member: ScShow
  533. //
  534. // Synopsis: Show/Hide the toolbar.
  535. //
  536. // Arguments: [bShow] - show/hide.
  537. //
  538. // Returns: SC
  539. //
  540. //--------------------------------------------------------------------
  541. SC CStandardToolbar::ScShow (BOOL bShow)
  542. {
  543. DECLARE_SC (sc, _T("CStandardToolbar::ScShow"));
  544. if (NULL == m_pToolbarUI)
  545. {
  546. sc = E_UNEXPECTED;
  547. return sc;
  548. }
  549. sc = m_pToolbarUI->ScShow(this, bShow);
  550. if (sc)
  551. return sc;
  552. return sc;
  553. }