XTTabBase.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:39k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTTabBase.cpp : implementation file
  2. //
  3. // This file is a part of the XTREME CONTROLS MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Common/XTPVC80Helpers.h"  // Visual Studio 2005 helper functions
  22. #include "Common/XTPSystemHelpers.h"
  23. #include "XTDefines.h"
  24. #include "XTGlobal.h"
  25. #include "XTVC50Helpers.h"
  26. #include "XTTabCtrlButtons.h"
  27. #include "XTTabBase.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. const int TABVIEW_BORDER = 4;
  34. IMPLEMENT_THEME_HOST(CXTTabBase)
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CXTTabBase
  37. CXTTabBase::CXTTabBase()
  38. : CXTThemeManagerStyleHost(GetThemeFactoryClass())
  39. , m_pTabCtrl(NULL)
  40. , m_bPreSubclassInit(true)
  41. , m_bAutoCondensing(FALSE)
  42. , m_bXPBorder(false)
  43. , m_bBoldFont(true)
  44. {
  45. }
  46. CXTTabBase::~CXTTabBase()
  47. {
  48. SAFE_DELETE(m_pNavBtns);
  49. }
  50. void CXTTabBase::OnPaint()
  51. {
  52. CPaintDC dc(m_pTabCtrl); // device context for painting
  53. CXTPClientRect rcClient(m_pTabCtrl);
  54. CXTPBufferDC memDC(dc, rcClient);
  55. GetPaintManager()->DrawTabCtrl(&memDC, this);
  56. }
  57. BOOL CXTTabBase::OnEraseBkgnd(CDC* /*pDC*/)
  58. {
  59. return TRUE;
  60. }
  61. void CXTTabBase::OnSettingChange(UINT /*uFlags*/, LPCTSTR /*lpszSection*/)
  62. {
  63. GetPaintManager()->RefreshMetrics();
  64. }
  65. void CXTTabBase::OnSysColorChange()
  66. {
  67. GetPaintManager()->RefreshMetrics();
  68. }
  69. bool CXTTabBase::Init()
  70. {
  71. if (!::IsWindow(m_pTabCtrl->GetSafeHwnd()))
  72. return false;
  73. return true;
  74. }
  75. void CXTTabBase::PreSubclassWindow()
  76. {
  77. if (m_bPreSubclassInit)
  78. {
  79. // Initialize the control.
  80. Init();
  81. }
  82. }
  83. BOOL CXTTabBase::PreCreateWindow(CREATESTRUCT& /*cs*/)
  84. {
  85. // When creating controls dynamically Init() must
  86. // be called from OnCreate() and not from
  87. // PreSubclassWindow().
  88. m_bPreSubclassInit = false;
  89. return TRUE;
  90. }
  91. int CXTTabBase::OnCreate(LPCREATESTRUCT /*lpCreateStruct*/)
  92. {
  93. // Initialize the control.
  94. Init();
  95. return 0;
  96. }
  97. void CXTTabBase::ImplAttach(CTabCtrl* pTabCtrl)
  98. {
  99. ASSERT_VALID(pTabCtrl); // must be valid
  100. if (pTabCtrl != NULL)
  101. {
  102. m_pTabCtrl = pTabCtrl;
  103. m_pNavBtns = new CXTTabCtrlButtons;
  104. m_pNavBtns->Create(this);
  105. }
  106. }
  107. CXTTabBaseTheme* CXTTabBase::GetPaintManager()
  108. {
  109. return (CXTTabBaseTheme*)GetSafeTheme();
  110. }
  111. void CXTTabBase::ShowNavButtons(DWORD dwFlags)
  112. {
  113. if (!m_pNavBtns)
  114. return;
  115. m_pNavBtns->m_dwFlags = dwFlags;
  116. if (::IsWindow(m_pNavBtns->GetSafeHwnd()))
  117. {
  118. if (m_pNavBtns->ShowButtons())
  119. {
  120. m_pNavBtns->Refresh();
  121. }
  122. }
  123. }
  124. void CXTTabBase::OnAddPadding(CXTStringHelper& strLabelText)
  125. {
  126. if (!strLabelText.IsEmpty())
  127. {
  128. CClientDC dc(NULL);
  129. int iSaveDC = dc.SaveDC();
  130. CFont* pfontNormal = NULL;
  131. CFont* pfontSelect = NULL;
  132. if (m_pTabCtrl->GetStyle() & TCS_VERTICAL)
  133. {
  134. pfontNormal = &XTAuxData().fontVert;
  135. pfontSelect = &XTAuxData().fontVertBold;
  136. }
  137. else
  138. {
  139. pfontNormal = &XTAuxData().font;
  140. pfontSelect = &XTAuxData().fontBold;
  141. }
  142. dc.SelectObject(pfontSelect);
  143. CSize sizeSelect = dc.GetTextExtent(strLabelText);
  144. dc.SelectObject(pfontNormal);
  145. CSize sizeNormal = dc.GetTextExtent(strLabelText);
  146. bool bFront = true;
  147. while (sizeNormal.cx < sizeSelect.cx)
  148. {
  149. if (bFront)
  150. {
  151. strLabelText.Insert(0, _T(' '));
  152. bFront = false;
  153. }
  154. else
  155. {
  156. strLabelText += _T(' ');
  157. bFront = true;
  158. }
  159. sizeNormal = dc.GetTextExtent(strLabelText);
  160. }
  161. dc.RestoreDC(iSaveDC);
  162. }
  163. }
  164. void CXTTabBase::GetChildRect(CRect& rcChild) const
  165. {
  166. ASSERT_VALID(m_pTabCtrl);
  167. // Get the selected tab index.
  168. int nCurSel = m_pTabCtrl->GetCurSel();
  169. if (nCurSel == -1)
  170. {
  171. rcChild.SetRectEmpty();
  172. return;
  173. }
  174. DWORD dwStyle = m_pTabCtrl->GetStyle();
  175. m_pTabCtrl->GetClientRect(&rcChild);
  176. CRect rcTab;
  177. m_pTabCtrl->GetItemRect(nCurSel, &rcTab);
  178. rcTab.InflateRect(1, 1);
  179. int cy = rcTab.Height() * m_pTabCtrl->GetRowCount();
  180. int cx = rcTab.Width () * m_pTabCtrl->GetRowCount();
  181. // vertical tabs
  182. if (dwStyle & TCS_VERTICAL)
  183. {
  184. // Right
  185. if (dwStyle & TCS_RIGHT)
  186. {
  187. rcChild.top += TABVIEW_BORDER;
  188. rcChild.left += TABVIEW_BORDER;
  189. rcChild.right -= TABVIEW_BORDER + cx;
  190. rcChild.bottom -= TABVIEW_BORDER;
  191. }
  192. // Left
  193. else
  194. {
  195. rcChild.top += TABVIEW_BORDER;
  196. rcChild.left += TABVIEW_BORDER + cx;
  197. rcChild.right -= TABVIEW_BORDER;
  198. rcChild.bottom -= TABVIEW_BORDER;
  199. }
  200. }
  201. // horizontal tabs
  202. else
  203. {
  204. // Bottom
  205. if (dwStyle & TCS_BOTTOM)
  206. {
  207. rcChild.top += TABVIEW_BORDER;
  208. rcChild.left += TABVIEW_BORDER;
  209. rcChild.right -= TABVIEW_BORDER;
  210. rcChild.bottom -= TABVIEW_BORDER + cy;
  211. }
  212. // Top
  213. else
  214. {
  215. rcChild.top += TABVIEW_BORDER + cy;
  216. rcChild.left += TABVIEW_BORDER;
  217. rcChild.right -= TABVIEW_BORDER;
  218. rcChild.bottom -= TABVIEW_BORDER;
  219. }
  220. }
  221. }
  222. /////////////////////////////////////////////////////////////////////////////
  223. // CXTTabExBase
  224. CXTTabExBase::CXTTabExBase()
  225. : m_bInitialUpdate(FALSE)
  226. , m_pParentWnd(NULL)
  227. , m_pParentFrame(NULL)
  228. , m_popupMenuID(0)
  229. , m_nPos(0)
  230. , m_pLastActiveView(NULL)
  231. , m_nOldIndex(-1)
  232. {
  233. m_bBoldFont = false;
  234. // force VC++ to generate the following template functions:
  235. if (GetAutoCondense()) // should always be false!
  236. {
  237. // this block will never be executed, but the compiler can't know that
  238. SetAutoCondense(FALSE);
  239. CXTTabBase::OnPaint();
  240. CreateTabView(NULL, NULL, NULL);
  241. }
  242. }
  243. CXTTabExBase::~CXTTabExBase()
  244. {
  245. }
  246. void CXTTabExBase::OnThemeChanged()
  247. {
  248. POSITION pos;
  249. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  250. {
  251. CXTTcbItem* pMember = m_tcbItems.GetAt(pos);
  252. GetTheme()->AdjustBorders(this, pMember);
  253. }
  254. }
  255. bool CXTTabExBase::Init()
  256. {
  257. if (!CXTTabBase::Init())
  258. return false;
  259. if (m_bInitialUpdate)
  260. {
  261. // fire off initial updates
  262. // NB: this works only if WM_INITIALUPDATE has not been sent to us
  263. //     since its handler invalidates the signature
  264. m_pTabCtrl->SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
  265. }
  266. // Set the font for the tab control.
  267. InitializeFont();
  268. // Get the pointer to the parent window.
  269. m_pParentWnd = m_pTabCtrl->GetParent();
  270. ASSERT_VALID(m_pParentWnd);
  271. // Get the pointer to the parent frame window.
  272. m_pParentFrame = m_pTabCtrl->GetParentFrame();
  273. if (::IsWindow(m_pParentFrame->GetSafeHwnd()))
  274. {
  275. // If floating, get parent frame of the floating frame window.
  276. if (m_pParentFrame->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)))
  277. {
  278. m_pParentFrame = m_pParentFrame->GetParentFrame();
  279. }
  280. }
  281. // Resize all views.
  282. RecalcLayout();
  283. if (m_bAutoCondensing)
  284. {
  285. Condense();
  286. }
  287. // make sure children are clipped.
  288. m_pTabCtrl->ModifyStyle(NULL, WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  289. return true;
  290. }
  291. BOOL CXTTabExBase::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
  292. {
  293. if (nCode < 1)
  294. {
  295. CWnd* pView = GetActiveView();
  296. if (pView && ::IsWindow(pView->m_hWnd))
  297. {
  298. if (pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  299. return TRUE;
  300. }
  301. }
  302. return FALSE;
  303. }
  304. BOOL CXTTabExBase::PreTranslateMessage(MSG* pMsg)
  305. {
  306. if (pMsg->message == WM_KEYDOWN)
  307. {
  308. bool bShift = (::GetKeyState(VK_SHIFT) < 0);
  309. bool bCtrl = (::GetKeyState(VK_CONTROL) < 0);
  310. if (bCtrl && (pMsg->wParam == VK_TAB) || (pMsg->wParam == VK_F6))
  311. {
  312. if (bShift)
  313. {
  314. PrevView();
  315. m_pTabCtrl->SetFocus();
  316. }
  317. else
  318. {
  319. NextView();
  320. m_pTabCtrl->SetFocus();
  321. }
  322. return TRUE;
  323. }
  324. }
  325. return FALSE; // Allow messages to be passed to base class
  326. }
  327. void CXTTabExBase::OnRButtonDown(UINT /*nFlags*/, CPoint point)
  328. {
  329. if (m_popupMenuID)
  330. {
  331. CPoint pt = point;
  332. m_pTabCtrl->ClientToScreen(&pt);
  333. CMenu menu;
  334. VERIFY(menu.LoadMenu(m_popupMenuID));
  335. CMenu* pPopup = menu.GetSubMenu(m_nPos);
  336. ASSERT(pPopup != NULL);
  337. if (!pPopup)
  338. return;
  339. pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y,
  340. m_pParentFrame);
  341. }
  342. }
  343. void CXTTabExBase::OnDestroy()
  344. {
  345. // Cleanup
  346. RemoveAllTabs();
  347. }
  348. void CXTTabExBase::EnableRedraw(BOOL bRedraw)
  349. {
  350. m_pTabCtrl->SetRedraw(bRedraw);
  351. if (bRedraw)
  352. {
  353. m_pTabCtrl->Invalidate();
  354. m_pTabCtrl->UpdateWindow();
  355. }
  356. }
  357. BOOL CXTTabExBase::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
  358. {
  359. *pResult = 0;
  360. // This is here for backward compatibility, TCN_XT_SELCHANGE
  361. // message has been deprecated, please use TCN_SELCHANGE instead.
  362. CWnd* pOwner = m_pTabCtrl->GetOwner();
  363. if (::IsWindow(pOwner->GetSafeHwnd()))
  364. {
  365. *pResult = pOwner->SendMessage(TCN_XT_SELCHANGE,
  366. pNMHDR->idFrom, (LPARAM)m_pTabCtrl);
  367. }
  368. if (*pResult == 0)
  369. {
  370. OnSelChange();
  371. }
  372. return FALSE;
  373. }
  374. void CXTTabExBase::OnSelChange()
  375. {
  376. // Get the index to the newly selected tab.
  377. int nIndex = m_pTabCtrl->GetCurSel();
  378. if (nIndex == -1)
  379. return;
  380. // Get a pointer to the selected view.
  381. if (m_nOldIndex != -1)
  382. {
  383. CWnd* pOldView = GetView(m_nOldIndex);
  384. if (pOldView != NULL)
  385. {
  386. pOldView->ShowWindow(SW_HIDE);
  387. pOldView->EnableWindow(FALSE);
  388. if (m_pParentFrame && pOldView == m_pParentFrame->GetActiveView())
  389. {
  390. if (m_pLastActiveView && ::IsWindow(m_pLastActiveView->m_hWnd))
  391. {
  392. m_pParentFrame->SetActiveView(m_pLastActiveView);
  393. }
  394. else
  395. {
  396. m_pParentFrame->SetActiveView(NULL, FALSE);
  397. m_pLastActiveView = NULL;
  398. }
  399. }
  400. }
  401. }
  402. // Get a pointer to the selected view.
  403. CWnd* pView = GetView(nIndex);
  404. if (pView != NULL)
  405. {
  406. // If this is a CView object then set the active view
  407. // the parent frame.
  408. if (pView->IsKindOf(RUNTIME_CLASS(CView)))
  409. {
  410. if (m_pParentFrame && m_pParentFrame->IsChild(pView))
  411. {
  412. // Save a pointer to the view if it is not a child of the
  413. // tab control, we will use this rather than setting the view
  414. // to NULL for the frame window.
  415. CView* pActiveView = m_pParentFrame->GetActiveView();
  416. if (pActiveView && pActiveView->GetParent() != m_pTabCtrl)
  417. {
  418. m_pLastActiveView = pActiveView;
  419. }
  420. m_pParentFrame->SetActiveView((CView*)pView);
  421. }
  422. }
  423. ActivateView(pView);
  424. }
  425. }
  426. BOOL CXTTabExBase::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult)
  427. {
  428. *pResult = 0;
  429. // This is here for backward compatibility, TCN_XT_SELCHANGING
  430. // message has been deprecated, please use TCN_SELCHANGING instead.
  431. CWnd* pOwner = m_pTabCtrl->GetOwner();
  432. if (::IsWindow(pOwner->GetSafeHwnd()))
  433. {
  434. *pResult = pOwner->SendMessage(TCN_XT_SELCHANGING,
  435. pNMHDR->idFrom, (LPARAM)m_pTabCtrl);
  436. }
  437. if (*pResult == 0)
  438. {
  439. OnSelChanging();
  440. }
  441. return FALSE;
  442. }
  443. void CXTTabExBase::OnSelChanging()
  444. {
  445. // Get the index to the selected tab, we will
  446. // need this later to hide old view.
  447. m_nOldIndex = m_pTabCtrl->GetCurSel();
  448. }
  449. void CXTTabExBase::OnPreWindowPosChanged(WINDOWPOS FAR* lpwndpos)
  450. {
  451. if (lpwndpos->flags & SWP_HIDEWINDOW)
  452. {
  453. POSITION pos;
  454. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  455. {
  456. CWnd* pView = m_tcbItems.GetAt(pos)->pWnd;
  457. ASSERT_VALID(pView);
  458. if (m_pParentFrame && m_pParentFrame->GetActiveView() == pView)
  459. {
  460. // To avoid main window freezing, we must deactivate the view,
  461. // because it's not visible now.
  462. if (m_pLastActiveView && ::IsWindow(m_pLastActiveView->m_hWnd))
  463. {
  464. m_pParentFrame->SetActiveView(m_pLastActiveView);
  465. }
  466. else
  467. {
  468. m_pParentFrame->SetActiveView(NULL, FALSE);
  469. m_pLastActiveView = NULL;
  470. }
  471. }
  472. }
  473. }
  474. else
  475. {
  476. // resize all child views.
  477. RecalcLayout();
  478. }
  479. }
  480. void CXTTabExBase::OnPostWindowPosChanged()
  481. {
  482. if (m_bAutoCondensing)
  483. {
  484. Condense();
  485. }
  486. }
  487. BOOL CXTTabExBase::ModifyTabStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  488. {
  489. if (!m_pTabCtrl->ModifyStyle(dwRemove, dwAdd, nFlags))
  490. return FALSE;
  491. // Set the font for the tab control.
  492. InitializeFont();
  493. return TRUE;
  494. }
  495. /////////////////////////////////////////////////////////////////////////////
  496. // CXTTabExBase tooltip related functions
  497. #if (_MSC_VER <= 1100) // Using Visual C++ 5.0
  498. CToolTipCtrl* CXTTabExBase::GetTips()
  499. {
  500. return m_pTabCtrl->GetTooltips();
  501. }
  502. void CXTTabExBase::SetTips(CToolTipCtrl* pWndTip)
  503. {
  504. m_pTabCtrl->SetTooltips(pWndTip);
  505. }
  506. #else
  507. CToolTipCtrl* CXTTabExBase::GetTips()
  508. {
  509. return m_pTabCtrl->GetToolTips();
  510. }
  511. void CXTTabExBase::SetTips(CToolTipCtrl* pWndTip)
  512. {
  513. m_pTabCtrl->SetToolTips(pWndTip);
  514. }
  515. #endif//#if (_MSC_VER <= 1100)
  516. void CXTTabExBase::AddToolTip(UINT nIDTab, LPCTSTR lpszText)
  517. {
  518. // Get the tool tips for the tab control.
  519. CToolTipCtrl* pToolTips = GetTips();
  520. if (pToolTips != NULL)
  521. {
  522. // Add the tool tip.
  523. if (nIDTab == 0)
  524. {
  525. pToolTips->AddTool(m_pTabCtrl, lpszText, NULL, nIDTab);
  526. }
  527. else
  528. {
  529. pToolTips->AddTool(m_pTabCtrl, lpszText, CRect(0, 0, 0, 0), nIDTab);
  530. }
  531. }
  532. }
  533. void CXTTabExBase::UpdateToolTip(int nIDTab, LPCTSTR lpszText)
  534. {
  535. ASSERT_VALID(m_pTabCtrl);
  536. ASSERT((nIDTab >= 0) && (m_pTabCtrl->GetItemCount() > nIDTab));
  537. // Find the view we want to change the tooltip for and
  538. // reset its tooltip text
  539. POSITION pos = m_tcbItems.FindIndex(nIDTab);
  540. if (pos != NULL)
  541. {
  542. // Get the private data for the view
  543. CXTTcbItem *pMember = m_tcbItems.GetAt(pos);
  544. ASSERT(pMember);
  545. if (!pMember)
  546. return;
  547. // Reset the tooltip text to the new value
  548. pMember->szToolTipLabel = lpszText;
  549. // Get the tool tips for the tab control.
  550. CToolTipCtrl* pToolTips = GetTips();
  551. if (pToolTips != NULL)
  552. {
  553. // Update the tooltip for the view
  554. pToolTips->UpdateTipText(pMember->szToolTipLabel,
  555. m_pTabCtrl, pMember->uiToolTipId);
  556. }
  557. }
  558. }
  559. void CXTTabExBase::UpdateToolTip(CRuntimeClass* pViewClass, LPCTSTR lpszText)
  560. {
  561. ASSERT_VALID(m_pTabCtrl);
  562. ASSERT(pViewClass != NULL);
  563. if (!pViewClass)
  564. return;
  565. ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  566. ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  567. int nIndex = 0;
  568. POSITION pos;
  569. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  570. {
  571. // Get the private data for the view
  572. CXTTcbItem *pMember = m_tcbItems.GetAt(pos);
  573. ASSERT(pMember);
  574. if (!pMember)
  575. continue;
  576. if (pMember->pWnd->IsKindOf(pViewClass))
  577. {
  578. UpdateToolTip(nIndex, lpszText);
  579. return;
  580. }
  581. nIndex++;
  582. }
  583. }
  584. void CXTTabExBase::ResetToolTips()
  585. {
  586. // Get the tool tips for the tab control.
  587. CToolTipCtrl* pToolTips = GetTips();
  588. if (pToolTips != NULL)
  589. {
  590. int nIndex = 0;
  591. POSITION pos;
  592. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  593. {
  594. // Get the next item in the list.
  595. CXTTcbItem* pMember = m_tcbItems.GetAt(pos);
  596. // Update the tooltip for the view
  597. pMember->uiToolTipId = nIndex;
  598. pToolTips->UpdateTipText(pMember->szToolTipLabel,
  599. m_pTabCtrl, nIndex);
  600. ++nIndex;
  601. }
  602. }
  603. }
  604. BOOL CXTTabExBase::EnableToolTipsEx(BOOL bEnable)
  605. {
  606. // Get the tool tips for the tab control.
  607. CToolTipCtrl* pToolTips = GetTips();
  608. if (pToolTips != NULL)
  609. {
  610. pToolTips->Activate(bEnable);
  611. return TRUE;
  612. }
  613. return FALSE;
  614. }
  615. /////////////////////////////////////////////////////////////////////////////
  616. // CXTTabExBase tab view methods.
  617. CWnd* CXTTabExBase::CreateTabView(CRuntimeClass* pViewClass, CDocument* pDocument, CCreateContext* pContext)
  618. {
  619. if (!pContext && !pViewClass)
  620. return NULL;
  621. ASSERT_VALID(m_pTabCtrl);
  622. ASSERT(pContext || pViewClass != NULL);
  623. ASSERT(pContext || pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  624. ASSERT(pContext || AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  625. CCreateContext contextT;
  626. if (pContext == NULL)
  627. {
  628. // if no context specified, generate one from the currently selected
  629. // client if possible.
  630. contextT.m_pCurrentDoc = pDocument;
  631. contextT.m_pNewViewClass = pViewClass;
  632. contextT.m_pLastView = NULL;
  633. contextT.m_pCurrentFrame = NULL;
  634. contextT.m_pNewDocTemplate = NULL;
  635. if (pDocument)
  636. {
  637. contextT.m_pNewDocTemplate = pDocument->GetDocTemplate();
  638. }
  639. pContext = &contextT;
  640. }
  641. if (!pContext->m_pNewViewClass)
  642. return NULL;
  643. CWnd* pWnd = NULL;
  644. TRY
  645. {
  646. pWnd = (CWnd*)pContext->m_pNewViewClass->CreateObject();
  647. if (pWnd == NULL)
  648. {
  649. AfxThrowMemoryException();
  650. }
  651. }
  652. CATCH_ALL(e)
  653. {
  654. TRACE0("Out of memory creating a view.n");
  655. // Note: DELETE_EXCEPTION(e) not required
  656. return NULL;
  657. }
  658. END_CATCH_ALL
  659. ASSERT_KINDOF(CWnd, pWnd);
  660. if (!pWnd)
  661. return NULL;
  662. ASSERT(pWnd->m_hWnd == NULL); // not yet created.
  663. DWORD dwStyle = AFX_WS_DEFAULT_VIEW;
  664. if (GetSafeTheme()->GetTheme() != xtThemeDefault)
  665. {
  666. dwStyle &= ~WS_BORDER;
  667. }
  668. int nTab = (int)m_tcbItems.GetCount();
  669. // Create with the right size (wrong position)
  670. CRect rect(0, 0, 0, 0);
  671. if (!pWnd->Create(NULL, NULL, dwStyle,
  672. rect, m_pTabCtrl, (AFX_IDW_PANE_FIRST + nTab), pContext))
  673. {
  674. TRACE0("Warning: couldn't create client tab for view.n");
  675. // pWnd will be cleaned up by PostNcDestroy
  676. return NULL;
  677. }
  678. if (pWnd->m_hWnd == NULL)
  679. return NULL;
  680. ASSERT((int)_AfxGetDlgCtrlID(pWnd->m_hWnd) == (AFX_IDW_PANE_FIRST + nTab));
  681. // send initial notification message for the window just created
  682. // only if our initialization has been completed
  683. if (m_bInitialUpdate)
  684. {
  685. pWnd->SendMessage(WM_INITIALUPDATE);
  686. }
  687. pWnd->SetOwner(m_pParentWnd);
  688. return pWnd;
  689. }
  690. BOOL CXTTabExBase::AddView(LPCTSTR lpszLabel, CRuntimeClass* pViewClass, CDocument* pDoc/*= NULL*/,
  691. CCreateContext *pContext/*= NULL*/, int iIndex/*= -1*/, int iIconIndex/*= -1*/)
  692. {
  693. if (!pContext && !pViewClass)
  694. return NULL;
  695. ASSERT_VALID(m_pTabCtrl);
  696. ASSERT(pContext || pViewClass);
  697. ASSERT(pContext || pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  698. ASSERT(pContext || AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  699. // Create the view to be associate with tab.
  700. CWnd* pWnd = CreateTabView(pViewClass, pDoc, pContext);
  701. if (pWnd == NULL) // tabs can be a CWnd, but are usually CViews
  702. return FALSE;
  703. return AddControl(lpszLabel, (CView *)pWnd, iIndex, iIconIndex);
  704. }
  705. BOOL CXTTabExBase::AddView(LPCTSTR lpszLabel, CView* pView, int iIndex/*= -1*/, int iIconIndex/*= -1*/)
  706. {
  707. ASSERT(pView != NULL);
  708. if (!pView)
  709. return FALSE;
  710. ASSERT(pView->GetRuntimeClass()->IsDerivedFrom(RUNTIME_CLASS(CView)));
  711. return AddControl(lpszLabel, pView, iIndex, iIconIndex);
  712. }
  713. BOOL CXTTabExBase::AddControl(LPCTSTR lpszLabel, CWnd* pWnd, int iIndex/*= -1*/, int iIconIndex/*= -1*/)
  714. {
  715. ASSERT_VALID(m_pTabCtrl);
  716. ASSERT_VALID(pWnd);
  717. ASSERT(pWnd != NULL);
  718. ASSERT(lpszLabel != NULL);
  719. ASSERT(iIndex >= -1);
  720. ASSERT(iIndex <= m_pTabCtrl->GetItemCount());
  721. if (!pWnd)
  722. return FALSE;
  723. pWnd->SetParent(m_pTabCtrl);
  724. // Allocate a new CXTTcbItem object.
  725. CXTTcbItem* pMember = new CXTTcbItem;
  726. if (pMember == NULL)
  727. return FALSE;
  728. pMember->pWnd = pWnd;
  729. pMember->szTabLabel = lpszLabel;
  730. pMember->szToolTipLabel = lpszLabel;
  731. pMember->uiToolTipId = m_pTabCtrl->GetItemCount();
  732. pMember->dwStyle = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_STYLE);
  733. pMember->dwExStyle = ::GetWindowLong(pWnd->GetSafeHwnd(), GWL_EXSTYLE);
  734. // If no index was specified add the view tab
  735. // to the end.
  736. if (iIndex == -1)
  737. {
  738. iIndex = (int)m_tcbItems.GetCount();
  739. }
  740. // Add the new CXTTcbItem to the tab item list.
  741. const POSITION pos = m_tcbItems.FindIndex(iIndex);
  742. if (pos != NULL)
  743. {
  744. m_tcbItems.InsertBefore(pos, pMember);
  745. }
  746. else
  747. {
  748. ASSERT(iIndex == m_pTabCtrl->GetItemCount());
  749. m_tcbItems.AddTail(pMember);
  750. }
  751. // Insert the new tab item.
  752. TC_ITEM tci;
  753. tci.mask = TCIF_TEXT | TCIF_IMAGE;
  754. tci.pszText = (LPTSTR)lpszLabel;
  755. if (iIconIndex != -1)
  756. {
  757. tci.iImage = iIconIndex;
  758. }
  759. else
  760. {
  761. tci.iImage = iIndex;
  762. }
  763. // set window borders based on current theme.
  764. GetTheme()->AdjustBorders(this, pMember);
  765. m_pTabCtrl->InsertItem(iIndex, &tci);
  766. // Create the ToolTip for the tab.
  767. AddToolTip(pMember->uiToolTipId, lpszLabel);
  768. // Since the tool tip count has changed,
  769. // re-initialize the tooltips.
  770. ResetToolTips();
  771. // hide/show views after insertion
  772. SetActiveView(iIndex);
  773. return TRUE;
  774. }
  775. BOOL CXTTabExBase::UpdateTabLabel(int iTab, CXTTcbItem* pMember, LPCTSTR lpszLabel)
  776. {
  777. // Text length cannot be longer than 255 characters.
  778. ASSERT(_tcslen(lpszLabel) < 255);
  779. CString strLabel = lpszLabel;
  780. if (strLabel.GetLength() > 255)
  781. {
  782. strLabel = strLabel.Left(255);
  783. }
  784. // if the string is empty return FALSE.
  785. else if (strLabel.IsEmpty())
  786. {
  787. return FALSE;
  788. }
  789. // if CXTTcbItem pointer is NULL, return FALSE.
  790. if (pMember == NULL)
  791. return FALSE;
  792. TCHAR szText[256];
  793. TC_ITEM tci;
  794. tci.mask = TCIF_TEXT;
  795. tci.cchTextMax = _countof(szText);
  796. tci.pszText = szText;
  797. // get the tab control item and update the text.
  798. m_pTabCtrl->GetItem(iTab, &tci);
  799. STRCPY_S(szText, 256, strLabel);
  800. m_pTabCtrl->SetItem(iTab, &tci);
  801. // Get the tool tips for the tab control and update
  802. // the tip text.
  803. CToolTipCtrl* pToolTips = GetTips();
  804. if (pToolTips == NULL)
  805. return FALSE;
  806. pToolTips->UpdateTipText(strLabel, m_pTabCtrl, iTab);
  807. // update the CXTTcbItem item label and tip text.
  808. pMember->szTabLabel = strLabel;
  809. pMember->szToolTipLabel = strLabel;
  810. // update other information
  811. pMember->szCondensedLabel = strLabel;
  812. return TRUE;
  813. }
  814. BOOL CXTTabExBase::SetTabText(int iTab, LPCTSTR lpszLabel)
  815. {
  816. // Get the item at the specified index.
  817. POSITION pos = m_tcbItems.FindIndex (iTab);
  818. if (pos == NULL)
  819. return FALSE;
  820. return UpdateTabLabel (iTab, m_tcbItems.GetAt(pos), lpszLabel);
  821. }
  822. BOOL CXTTabExBase::SetTabText(CWnd* pView, LPCTSTR lpszLabel)
  823. {
  824. int iTab = 0;
  825. POSITION pos;
  826. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  827. {
  828. // Get the next item in the list.
  829. CXTTcbItem* pMember = m_tcbItems.GetAt(pos);
  830. if (pView == pMember->pWnd)
  831. return UpdateTabLabel (iTab, m_tcbItems.GetAt(pos), lpszLabel);
  832. ++iTab;
  833. }
  834. return FALSE;
  835. }
  836. BOOL CXTTabExBase::SetTabText(CRuntimeClass* pViewClass, LPCTSTR lpszLabel)
  837. {
  838. int iTab = 0;
  839. POSITION pos;
  840. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  841. {
  842. // Get the next item in the list.
  843. CXTTcbItem* pMember = m_tcbItems.GetAt(pos);
  844. if (pMember->pWnd->IsKindOf(pViewClass))
  845. return UpdateTabLabel (iTab, m_tcbItems.GetAt(pos), lpszLabel);
  846. ++iTab;
  847. }
  848. return FALSE;
  849. }
  850. CWnd* CXTTabExBase::NextView()
  851. {
  852. ASSERT_VALID(m_pTabCtrl);
  853. ASSERT(m_tcbItems.GetCount() > 0);
  854. // get the current selection and increment by 1.
  855. int iIndex = m_pTabCtrl->GetCurSel();
  856. iIndex++;
  857. // if the new index is greater than or equal to
  858. // the tab count, set the index to 0.
  859. if (iIndex > m_pTabCtrl->GetItemCount()-1)
  860. iIndex = 0;
  861. // set the active view and return a pointer to
  862. // the newly activated view.
  863. SetActiveView(iIndex);
  864. return GetActiveView();
  865. }
  866. CWnd* CXTTabExBase::PrevView()
  867. {
  868. ASSERT_VALID(m_pTabCtrl);
  869. ASSERT(m_tcbItems.GetCount() > 0);
  870. // get the current selection and increment by 1.
  871. int iIndex = m_pTabCtrl->GetCurSel();
  872. iIndex--;
  873. // if the new index is greater than or equal to
  874. // the tab count, set the index to 0.
  875. if (iIndex < 0)
  876. iIndex = m_pTabCtrl->GetItemCount()-1;
  877. // set the active view and return a pointer to
  878. // the newly activated view.
  879. SetActiveView(iIndex);
  880. return GetActiveView();
  881. }
  882. CWnd* CXTTabExBase::GetView(int nView)
  883. {
  884. ASSERT_VALID(m_pTabCtrl);
  885. if (nView > -1 && nView < m_pTabCtrl->GetItemCount())
  886. {
  887. POSITION pos = m_tcbItems.FindIndex(nView);
  888. if (pos != NULL)
  889. {
  890. CWnd* pWnd = m_tcbItems.GetAt(pos)->pWnd;
  891. ASSERT_VALID(pWnd);
  892. if (pWnd && ::IsWindow(pWnd->m_hWnd))
  893. {
  894. return pWnd;
  895. }
  896. }
  897. }
  898. return NULL;
  899. }
  900. CWnd* CXTTabExBase::GetView(CRuntimeClass* pViewClass)
  901. {
  902. ASSERT_VALID(m_pTabCtrl);
  903. ASSERT(pViewClass != NULL);
  904. if (!pViewClass)
  905. return 0;
  906. ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  907. ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  908. POSITION pos;
  909. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  910. {
  911. CWnd* pWnd = m_tcbItems.GetAt(pos)->pWnd;
  912. ASSERT_VALID(pWnd);
  913. if (pWnd && ::IsWindow(pWnd->m_hWnd) && pWnd->IsKindOf(pViewClass))
  914. {
  915. return pWnd;
  916. }
  917. }
  918. return NULL;
  919. }
  920. void CXTTabExBase::ActivateView(CWnd* pNewView)
  921. {
  922. ASSERT_VALID(pNewView); // must be valid
  923. // Hide all views.
  924. int iIndex;
  925. for (iIndex = 0; iIndex < m_tcbItems.GetCount(); ++iIndex)
  926. {
  927. POSITION pos = m_tcbItems.FindIndex(iIndex);
  928. if (pos != NULL)
  929. {
  930. CXTTcbItem* pTCBItem = m_tcbItems.GetAt(pos);
  931. ASSERT(pTCBItem != NULL);
  932. if (pTCBItem && pTCBItem->pWnd)
  933. {
  934. pTCBItem->pWnd->ShowWindow(SW_HIDE);
  935. pTCBItem->pWnd->EnableWindow(FALSE);
  936. }
  937. }
  938. }
  939. ////////// ULF 2003-08-07
  940. if (m_pParentFrame && m_pParentFrame->IsChild(pNewView))
  941. {
  942. CView* pActiveView = m_pParentFrame->GetActiveView();
  943. if (pActiveView && pActiveView->GetParent() == m_pTabCtrl)
  944. {
  945. if (pActiveView != pNewView)
  946. {
  947. // Make the frame window aware of the active view (for message routing)
  948. m_pParentFrame->SetActiveView(DYNAMIC_DOWNCAST(CView, pNewView));
  949. }
  950. }
  951. }
  952. /////////
  953. // Show and enable the window.
  954. pNewView->ShowWindow(SW_SHOW);
  955. pNewView->EnableWindow(TRUE);
  956. pNewView->SetFocus();
  957. // Resize the window.
  958. ResizeTabView(pNewView);
  959. }
  960. void CXTTabExBase::SetActiveView(CRuntimeClass* pViewClass)
  961. {
  962. ASSERT_VALID(m_pTabCtrl);
  963. ASSERT(pViewClass != NULL);
  964. if (!pViewClass)
  965. return;
  966. ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  967. ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  968. // Walk through the tabs
  969. int iIndex;
  970. for (iIndex = 0; iIndex < m_tcbItems.GetCount(); ++iIndex)
  971. {
  972. POSITION pos = m_tcbItems.FindIndex(iIndex);
  973. if (pos != NULL)
  974. {
  975. CXTTcbItem* pTCBItem = m_tcbItems.GetAt(pos);
  976. ASSERT(pTCBItem != NULL);
  977. if (pTCBItem && pTCBItem->pWnd->IsKindOf(pViewClass))
  978. {
  979. // Select new the tab
  980. m_pTabCtrl->SetCurSel(iIndex);
  981. // now active the view and give it focus.
  982. ActivateView(pTCBItem->pWnd);
  983. break;
  984. }
  985. }
  986. }
  987. }
  988. void CXTTabExBase::SetActiveView(CWnd* pTabView)
  989. {
  990. ASSERT_VALID(m_pTabCtrl);
  991. ASSERT(pTabView != NULL);
  992. // Walk through the tabs
  993. int iIndex;
  994. for (iIndex = 0; iIndex < m_tcbItems.GetCount(); ++iIndex)
  995. {
  996. POSITION pos = m_tcbItems.FindIndex(iIndex);
  997. if (pos != NULL)
  998. {
  999. CXTTcbItem* pTCBItem = m_tcbItems.GetAt(pos);
  1000. ASSERT(pTCBItem != NULL);
  1001. // Does the tab view match the requested view ?
  1002. if (pTCBItem && pTCBItem->pWnd == pTabView)
  1003. {
  1004. // Select new the tab
  1005. m_pTabCtrl->SetCurSel(iIndex);
  1006. // now active the view and give it focus.
  1007. ActivateView(pTCBItem->pWnd);
  1008. break;
  1009. }
  1010. }
  1011. }
  1012. }
  1013. void CXTTabExBase::SetActiveView(int nActiveTab)
  1014. {
  1015. ASSERT_VALID(m_pTabCtrl);
  1016. ASSERT(nActiveTab >= 0);
  1017. // Find the item at the specified index.
  1018. POSITION pos = m_tcbItems.FindIndex(nActiveTab);
  1019. if (pos != NULL)
  1020. {
  1021. CXTTcbItem* pTCBItem = m_tcbItems.GetAt(pos);
  1022. ASSERT(pTCBItem != NULL);
  1023. if (pTCBItem && pTCBItem->pWnd != NULL)
  1024. {
  1025. ASSERT_VALID(pTCBItem->pWnd);
  1026. // Select new the tab
  1027. m_pTabCtrl->SetCurSel(nActiveTab);
  1028. // now active the view and give it focus.
  1029. ActivateView(pTCBItem->pWnd);
  1030. }
  1031. }
  1032. }
  1033. void CXTTabExBase::RemoveListItem(POSITION pos, BOOL bDestroyWnd/*= TRUE*/)
  1034. {
  1035. // invalid position
  1036. if (pos == NULL)
  1037. return;
  1038. // remove the page from internal list
  1039. CXTTcbItem *pMember = m_tcbItems.GetAt(pos);
  1040. // if this item is invalid, return.
  1041. if (!pMember)
  1042. return;
  1043. if (pMember->pWnd && ::IsWindow(pMember->pWnd->m_hWnd))
  1044. {
  1045. // And delete the member window, freeing our stored
  1046. // values relating to it
  1047. if (bDestroyWnd)
  1048. {
  1049. pMember->pWnd->DestroyWindow();
  1050. pMember->pWnd = NULL;
  1051. }
  1052. else
  1053. {
  1054. pMember->pWnd->ShowWindow(SW_HIDE);
  1055. }
  1056. }
  1057. // Remove from list and free memory.
  1058. m_tcbItems.RemoveAt(pos);
  1059. SAFE_DELETE(pMember);
  1060. }
  1061. void CXTTabExBase::DeleteView(int nView, BOOL bDestroyWnd/*= TRUE*/)
  1062. {
  1063. ASSERT_VALID(m_pTabCtrl);
  1064. ASSERT((nView >= 0) && (m_pTabCtrl->GetItemCount() > nView));
  1065. // Now find the view we want to delete and remove it
  1066. POSITION pos = m_tcbItems.FindIndex(nView);
  1067. if (pos != NULL)
  1068. {
  1069. CWnd* pView = m_tcbItems.GetAt(pos)->pWnd;
  1070. // Ensure that we get no dangling pointers
  1071. if (m_pParentFrame && m_pParentFrame->GetActiveView() == pView)
  1072. {
  1073. if (m_pLastActiveView && ::IsWindow(m_pLastActiveView->m_hWnd))
  1074. {
  1075. m_pParentFrame->SetActiveView(m_pLastActiveView);
  1076. }
  1077. else
  1078. {
  1079. m_pParentFrame->SetActiveView(NULL, FALSE);
  1080. m_pLastActiveView = NULL;
  1081. }
  1082. }
  1083. // Remove item from list, and free memory.
  1084. RemoveListItem(pos, bDestroyWnd);
  1085. // Remove it from the tab control
  1086. m_pTabCtrl->DeleteItem(nView);
  1087. int nCount = m_pTabCtrl->GetItemCount();
  1088. if (nCount > 0)
  1089. {
  1090. // Finally, if we have just deleted the active view, reset the
  1091. // active tab to be the first view in the list
  1092. if (nView == 0)
  1093. {
  1094. SetActiveView(nView);
  1095. }
  1096. else if (nView >= nCount)
  1097. {
  1098. SetActiveView(nCount-1);
  1099. }
  1100. else
  1101. {
  1102. SetActiveView(nView-1);
  1103. }
  1104. // Reset the tooltips for the views we have left...
  1105. ResetToolTips();
  1106. }
  1107. }
  1108. }
  1109. void CXTTabExBase::DeleteView(CRuntimeClass* pViewClass, BOOL bDestroyWnd/*= TRUE*/)
  1110. {
  1111. ASSERT_VALID(m_pTabCtrl);
  1112. ASSERT(pViewClass != NULL);
  1113. if (!pViewClass)
  1114. return;
  1115. ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  1116. ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  1117. int nView = 0;
  1118. POSITION pos;
  1119. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  1120. {
  1121. CWnd* pView = m_tcbItems.GetAt(pos)->pWnd;
  1122. ASSERT_VALID(pView);
  1123. if (pView->IsKindOf(pViewClass))
  1124. {
  1125. DeleteView(nView, bDestroyWnd);
  1126. return;
  1127. }
  1128. nView++;
  1129. }
  1130. }
  1131. void CXTTabExBase::DeleteView(CWnd* pView, BOOL bDestroyWnd/*= TRUE*/)
  1132. {
  1133. ASSERT_VALID(m_pTabCtrl);
  1134. ASSERT(pView != NULL);
  1135. ASSERT(AfxIsValidAddress(pView, sizeof(CWnd), FALSE));
  1136. int nView = 0;
  1137. POSITION pos;
  1138. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  1139. {
  1140. if (m_tcbItems.GetAt(pos)->pWnd == pView)
  1141. {
  1142. DeleteView(nView, bDestroyWnd);
  1143. return;
  1144. }
  1145. nView++;
  1146. }
  1147. }
  1148. LPCTSTR CXTTabExBase::GetViewName(int nView)
  1149. {
  1150. ASSERT_VALID(m_pTabCtrl);
  1151. ASSERT((nView >= 0) && (m_pTabCtrl->GetItemCount() > nView));
  1152. if (nView != -1)
  1153. {
  1154. POSITION pos = m_tcbItems.FindIndex(nView);
  1155. if (pos != NULL)
  1156. {
  1157. return m_tcbItems.GetAt(pos)->szTabLabel;
  1158. }
  1159. }
  1160. return NULL;
  1161. }
  1162. LPCTSTR CXTTabExBase::GetViewName(CRuntimeClass* pViewClass)
  1163. {
  1164. ASSERT_VALID(m_pTabCtrl);
  1165. ASSERT(pViewClass != NULL);
  1166. if (!pViewClass)
  1167. return NULL;
  1168. ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
  1169. ASSERT(AfxIsValidAddress(pViewClass, sizeof(CRuntimeClass), FALSE));
  1170. POSITION pos;
  1171. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  1172. {
  1173. CXTTcbItem *pMember = m_tcbItems.GetAt(pos);
  1174. ASSERT(pMember);
  1175. if (pMember && pMember->pWnd->IsKindOf(pViewClass))
  1176. {
  1177. return (LPCTSTR)pMember->szTabLabel;
  1178. }
  1179. }
  1180. return NULL;
  1181. }
  1182. BOOL CXTTabExBase::IsChildView(CWnd* pWnd)
  1183. {
  1184. POSITION pos = m_tcbItems.GetHeadPosition();
  1185. while (pos)
  1186. {
  1187. CXTTcbItem *pItem = m_tcbItems.GetNext(pos);
  1188. if (pItem && pItem->pWnd == pWnd)
  1189. {
  1190. return TRUE;
  1191. }
  1192. }
  1193. return FALSE;
  1194. }
  1195. BOOL CXTTabExBase::RemoveAllTabs(BOOL bDestroyWnd/*= TRUE*/)
  1196. {
  1197. if (m_pParentFrame)
  1198. {
  1199. // If the parent frames active view belongs to
  1200. // us set the active view to NULL.
  1201. CView * pActiveView = m_pParentFrame->GetActiveView();
  1202. if (IsChildView(pActiveView))
  1203. {
  1204. if (m_pLastActiveView && ::IsWindow(m_pLastActiveView->m_hWnd) && !IsChildView(m_pLastActiveView))
  1205. {
  1206. m_pParentFrame->SetActiveView(m_pLastActiveView);
  1207. }
  1208. else
  1209. {
  1210. m_pParentFrame->SetActiveView(NULL, FALSE);
  1211. }
  1212. }
  1213. }
  1214. m_pLastActiveView = NULL;
  1215. m_nOldIndex = -1;
  1216. // Free memory and clear tab view list.
  1217. while (!m_tcbItems.IsEmpty())
  1218. {
  1219. POSITION pos = m_tcbItems.FindIndex(0);
  1220. if (pos != NULL)
  1221. {
  1222. RemoveListItem(pos, bDestroyWnd);
  1223. }
  1224. }
  1225. // Remove all tabs from control.
  1226. m_pTabCtrl->DeleteAllItems();
  1227. return TRUE;
  1228. }
  1229. int CXTTabExBase::GetTabFromPoint(CPoint point)
  1230. {
  1231. TCHITTESTINFO tch;
  1232. memset(&tch, 0, sizeof(TCHITTESTINFO));
  1233. if (point == CPoint(0, 0))
  1234. {
  1235. CPoint pt;
  1236. GetCursorPos(&pt);
  1237. m_pTabCtrl->ScreenToClient(&pt);
  1238. tch.pt = pt;
  1239. }
  1240. else
  1241. {
  1242. tch.pt = point;
  1243. }
  1244. return m_pTabCtrl->HitTest(&tch);
  1245. }
  1246. BOOL CXTTabExBase::Defer(HDWP& hDWP, CWnd* pView)
  1247. {
  1248. if (pView && ::IsWindow(pView->m_hWnd))
  1249. {
  1250. HWND hWnd = pView->m_hWnd;
  1251. CRect rcNewSize;
  1252. GetChildRect(rcNewSize);
  1253. CRect rcOldSize;
  1254. pView->GetWindowRect(&rcOldSize);
  1255. m_pTabCtrl->ScreenToClient(&rcOldSize);
  1256. if (rcNewSize != rcOldSize)
  1257. {
  1258. int x = (int) rcNewSize.left;
  1259. int y = (int) rcNewSize.top;
  1260. int cx = (int) rcNewSize.Width();
  1261. int cy = (int) rcNewSize.Height();
  1262. // Set positioning flags
  1263. UINT uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER;
  1264. // if the x-y coordinates have not changed, there is no reason
  1265. // to move the dialog item.
  1266. if (rcNewSize.TopLeft() == rcOldSize.TopLeft())
  1267. uFlags |= SWP_NOMOVE;
  1268. // if the cx-cy size has not changed, there is no reason to
  1269. // size the dialog item.  If size has changed, don't
  1270. // copy bits of the client area (i.e. have them invalidated/redrawn)
  1271. if (rcNewSize.Size() == rcOldSize.Size())
  1272. uFlags |= SWP_NOSIZE;
  1273. else
  1274. uFlags |= SWP_NOCOPYBITS;
  1275. hDWP = ::DeferWindowPos(hDWP, hWnd, 0, x, y, cx, cy, uFlags);
  1276. if (hDWP == NULL)
  1277. {
  1278. TRACE(_T("DeferWindowPos failed for ID %in"), GetDlgCtrlID(hWnd));
  1279. return FALSE;
  1280. }
  1281. return TRUE;
  1282. }
  1283. }
  1284. return FALSE;
  1285. }
  1286. void CXTTabExBase::RecalcLayout()
  1287. {
  1288. HDWP hDWP = ::BeginDeferWindowPos((int)m_tcbItems.GetCount());
  1289. // Resize all views.
  1290. POSITION pos;
  1291. for (pos = m_tcbItems.GetHeadPosition(); pos; m_tcbItems.GetNext(pos))
  1292. {
  1293. CXTTcbItem* pTCBItem = m_tcbItems.GetAt(pos);
  1294. ASSERT(pTCBItem != NULL);
  1295. if (!pTCBItem)
  1296. continue;
  1297. CWnd* pWnd = pTCBItem->pWnd;
  1298. ASSERT_VALID(pWnd);
  1299. Defer(hDWP, pWnd);
  1300. }
  1301. ::EndDeferWindowPos(hDWP);
  1302. }
  1303. void CXTTabExBase::ResizeTabView(CWnd* pView)
  1304. {
  1305. if (pView && ::IsWindow(pView->m_hWnd))
  1306. {
  1307. CRect rcChild;
  1308. GetChildRect(rcChild);
  1309. pView->MoveWindow(rcChild);
  1310. }
  1311. }
  1312. void CXTTabExBase::InitializeFont()
  1313. {
  1314. HGDIOBJ hFont = XTAuxData().font.GetSafeHandle();
  1315. // if the tabs are vertical, use the vertical menu font.
  1316. if ((m_pTabCtrl->GetStyle() & TCS_VERTICAL) == TCS_VERTICAL)
  1317. hFont = XTAuxData().fontVert.GetSafeHandle();
  1318. if (hFont != NULL)
  1319. {
  1320. if (XTOSVersionInfo()->IsWin95())
  1321. m_pTabCtrl->PostMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
  1322. else
  1323. m_pTabCtrl->SendMessage(WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
  1324. }
  1325. }
  1326. void CXTTabExBase::SetAutoCondense(BOOL bEnable)
  1327. {
  1328. m_bAutoCondensing = bEnable;
  1329. Condense();
  1330. }
  1331. BOOL CXTTabExBase::GetAutoCondense()
  1332. {
  1333. return m_bAutoCondensing;
  1334. }
  1335. int CXTTabExBase::CalculateTabWidth(CDC* pDC, CString& sLabel, bool bHasIcon)
  1336. {
  1337. int len = pDC->GetTextExtent(sLabel).cx + 6 + 6;
  1338. if (sLabel.GetLength() == 1) ++len;
  1339. if (bHasIcon)
  1340. {
  1341. len += 16 + 6;
  1342. }
  1343. return len;
  1344. }
  1345. // used by tab condensation code
  1346. struct CXTTabExBase::ITEMANDWIDTH
  1347. {
  1348. CXTTcbItem*    pItem;
  1349. int             iWidth;
  1350. bool            bHasIcon;
  1351. bool            bAtMinLength;
  1352. int             iItemIndex;
  1353. CXTStringHelper sNewLabel;
  1354. };
  1355. void CXTTabExBase::Condense()
  1356. {
  1357. if (!m_pTabCtrl->m_hWnd || m_pTabCtrl->GetItemCount() == 0)
  1358. {
  1359. return;
  1360. }
  1361. // create a device context with the tab control's font (used for label
  1362. // widths calculations)
  1363. CFont *pFont = m_pTabCtrl->GetFont();
  1364. VERIFY(pFont != NULL);
  1365. CDC *pDC = m_pTabCtrl->GetDC();
  1366. CFont *pOldFont = pDC->SelectObject(pFont);
  1367. int iTotalWidth = 0;
  1368. CList <ITEMANDWIDTH, ITEMANDWIDTH&> lstItemsByWidth;
  1369. // the formula for iMinTabWidth is based on empirical data
  1370. TEXTMETRIC tm;
  1371. pDC->GetTextMetrics(&tm);
  1372. const int iMinTabWidth = tm.tmAveCharWidth * 6 + 12;
  1373. // calculate length of tab labels and fill our tracking list
  1374. POSITION p = m_tcbItems.GetHeadPosition();
  1375. ASSERT(p != NULL);  // there should be items
  1376. int idx = 0;
  1377. TCITEM tci;
  1378. tci.mask = TCIF_IMAGE;
  1379. while (p)
  1380. {
  1381. m_pTabCtrl->GetItem(idx, &tci);
  1382. ITEMANDWIDTH iaw;
  1383. iaw.bHasIcon = (tci.iImage >= 0);
  1384. iaw.pItem = m_tcbItems.GetNext(p);
  1385. iaw.iWidth = CalculateTabWidth(pDC, iaw.pItem->szTabLabel, iaw.bHasIcon);
  1386. iaw.sNewLabel = iaw.pItem->szTabLabel;
  1387. iaw.iItemIndex = idx;
  1388. iaw.bAtMinLength = FALSE;
  1389. ++idx;
  1390. lstItemsByWidth.AddTail(iaw);
  1391. iTotalWidth += iaw.iWidth;
  1392. }
  1393. const bool bVertical = (m_pTabCtrl->GetStyle() & TCS_VERTICAL) == TCS_VERTICAL;
  1394. const bool bMultiLine =
  1395. bVertical || ((m_pTabCtrl->GetStyle() & TCS_MULTILINE) == TCS_MULTILINE);
  1396. CRect rc;
  1397. m_pTabCtrl->GetClientRect(&rc);
  1398. const int client_width = bVertical ? rc.Height() : rc.Width();
  1399. POSITION p2;
  1400. if (client_width == 0)
  1401. {
  1402. pDC->SelectObject(pOldFont);
  1403. m_pTabCtrl->ReleaseDC(pDC);
  1404. return;
  1405. }
  1406. if (m_bAutoCondensing)
  1407. {
  1408. iTotalWidth += 4; // 4 pixels extra for the selected tab
  1409. if (bMultiLine) ++iTotalWidth;
  1410. // start condensing labels until the total width fits the client area,
  1411. // or until we can't condense any more
  1412. while (iTotalWidth > client_width)
  1413. {
  1414. // look for widest item
  1415. p = lstItemsByWidth.GetHeadPosition();
  1416. int iWidest = -1;
  1417. while (p)
  1418. {
  1419. const POSITION p3 = p;
  1420. ITEMANDWIDTH& iaw = lstItemsByWidth.GetNext(p);
  1421. if (iaw.iWidth > iWidest && !iaw.bAtMinLength)
  1422. {
  1423. iWidest = iaw.iWidth;
  1424. p2 = p3;
  1425. }
  1426. }
  1427. if (iWidest == -1)
  1428. {
  1429. break;
  1430. }
  1431. ITEMANDWIDTH& iaw = lstItemsByWidth.GetNext(p2);
  1432. const int iOldWidth = iaw.iWidth;
  1433. CXTStringHelper& label = iaw.sNewLabel;
  1434. // shorten name
  1435. if (label.Right(3) != _T("..."))
  1436. {
  1437. label += _T("...");
  1438. }
  1439. do
  1440. {
  1441. if (label.GetLength() == 3 || (iaw.iWidth <= iMinTabWidth))
  1442. {
  1443. iaw.bAtMinLength = true;
  1444. }
  1445. else
  1446. {
  1447. int iLen = label.GetLength();
  1448. if ((iLen > 0) && ((iLen-4) >= 0))
  1449. {
  1450. label.Delete((iLen-4), 1);
  1451. }
  1452. }
  1453. iaw.iWidth = CalculateTabWidth(pDC, label, iaw.bHasIcon);
  1454. }
  1455. while (!iaw.bAtMinLength && iaw.iWidth >= iOldWidth);
  1456. iTotalWidth -= (iOldWidth - iaw.iWidth);
  1457. }
  1458. }
  1459. // update actual tab labels based on new condensed labels
  1460. tci.mask = TCIF_TEXT;
  1461. p = lstItemsByWidth.GetHeadPosition();
  1462. while (p)
  1463. {
  1464. ITEMANDWIDTH& iaw = lstItemsByWidth.GetNext(p);
  1465. // only change if actually different
  1466. if (iaw.pItem->szCondensedLabel != iaw.sNewLabel)
  1467. {
  1468. iaw.pItem->szCondensedLabel = iaw.sNewLabel;
  1469. tci.pszText = (TCHAR*)(LPCTSTR)iaw.sNewLabel;
  1470. m_pTabCtrl->SetItem(iaw.iItemIndex, &tci);
  1471. }
  1472. }
  1473. pDC->SelectObject(pOldFont);
  1474. m_pTabCtrl->ReleaseDC(pDC);
  1475. }