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.

755 lines
18 KiB

  1. #include "precomp.h"
  2. #include "mcinc.h"
  3. #include "marswin.h"
  4. #include "panel.h"
  5. #include "place.h"
  6. ////static void DebugLog( LPCWSTR szMessageFmt ,
  7. //// ... )
  8. ////{
  9. //// const int BUFFER_LINE_LENGTH = 512;
  10. //// WCHAR rgLine[BUFFER_LINE_LENGTH+1];
  11. //// va_list arglist;
  12. //// int iLen;
  13. //// BOOL bRetVal = TRUE;
  14. ////
  15. ////
  16. //// //
  17. //// // Format the log line.
  18. //// //
  19. //// va_start( arglist, szMessageFmt );
  20. //// iLen = _vsnwprintf( rgLine, BUFFER_LINE_LENGTH, szMessageFmt, arglist );
  21. //// va_end( arglist );
  22. ////
  23. //// //
  24. //// // Is the arglist too big for us?
  25. //// //
  26. //// if(iLen < 0)
  27. //// {
  28. //// iLen = BUFFER_LINE_LENGTH;
  29. //// }
  30. //// rgLine[iLen] = 0;
  31. ////
  32. //// ::OutputDebugStringW( rgLine );
  33. ////}
  34. //==================================================================
  35. // CPlacePanelCollection
  36. //==================================================================
  37. CPlacePanelCollection::~CPlacePanelCollection()
  38. {
  39. for (int i=0; i<GetSize(); i++)
  40. {
  41. delete (*this)[i];
  42. }
  43. }
  44. //==================================================================
  45. // CPlacePanel
  46. //==================================================================
  47. CPlacePanel::CPlacePanel( MarsAppDef_PlacePanel* pp) :
  48. m_bstrName(pp->szName),
  49. m_fWasVisible(pp->fStartVisible),
  50. m_PersistVisible(pp->persistVisible)
  51. {
  52. }
  53. VARIANT_BOOL CPlacePanel::ShowOnTransition(CMarsPanel *pPanel)
  54. {
  55. VARIANT_BOOL bResult;
  56. switch(m_PersistVisible)
  57. {
  58. case PANEL_PERSIST_VISIBLE_DONTTOUCH:
  59. if(pPanel->WasInPreviousPlace())
  60. {
  61. bResult = pPanel->IsVisible();
  62. break;
  63. }
  64. case PANEL_PERSIST_VISIBLE_ALWAYS:
  65. bResult = m_fWasVisible ? VARIANT_TRUE : VARIANT_FALSE;
  66. break;
  67. default:
  68. bResult = VARIANT_TRUE;
  69. break;
  70. }
  71. return bResult;
  72. }
  73. void CPlacePanel::SaveLayout(CMarsPanel *pPanel)
  74. {
  75. m_fWasVisible = pPanel->IsVisible();
  76. }
  77. //==================================================================
  78. // CMarsPlace
  79. //==================================================================
  80. CMarsPlace::CMarsPlace(CPlaceCollection *pParent, CMarsDocument *pMarsDocument)
  81. {
  82. m_spPlaceCollection = pParent;
  83. m_spMarsDocument = pMarsDocument;
  84. }
  85. HRESULT CMarsPlace::DoPassivate()
  86. {
  87. m_spPlaceCollection.Release();
  88. m_spMarsDocument.Release();
  89. return S_OK;
  90. }
  91. HRESULT CMarsPlace::Init(LPCWSTR pwszName)
  92. {
  93. m_bstrName = pwszName;
  94. return S_OK;
  95. }
  96. IMPLEMENT_ADDREF_RELEASE(CMarsPlace);
  97. STDMETHODIMP CMarsPlace::QueryInterface(REFIID iid, void ** ppvObject)
  98. {
  99. HRESULT hr;
  100. if(API_IsValidWritePtr(ppvObject))
  101. {
  102. hr = E_NOINTERFACE;
  103. *ppvObject = NULL;
  104. if((iid == IID_IMarsPlace) ||
  105. (iid == IID_IDispatch ) ||
  106. (iid == IID_IUnknown ) )
  107. {
  108. *ppvObject = SAFECAST(this, IMarsPlace *);
  109. }
  110. if(*ppvObject)
  111. {
  112. hr = S_OK;
  113. AddRef();
  114. }
  115. }
  116. else
  117. {
  118. hr = E_INVALIDARG;
  119. }
  120. return hr;
  121. }
  122. // IMarsPlace
  123. STDMETHODIMP CMarsPlace::get_name(BSTR *pbstrName)
  124. {
  125. HRESULT hr = E_INVALIDARG;
  126. if(API_IsValidWritePtr(pbstrName) && VerifyNotPassive(&hr))
  127. {
  128. hr = SUCCEEDED(m_bstrName.CopyTo(pbstrName)) ? S_OK : S_FALSE;
  129. }
  130. return hr;
  131. }
  132. STDMETHODIMP CMarsPlace::transitionTo()
  133. {
  134. FAIL_AFTER_PASSIVATE();
  135. return m_spPlaceCollection->transitionTo(m_bstrName);
  136. }
  137. HRESULT CMarsPlace::DoTransition()
  138. {
  139. FAIL_AFTER_PASSIVATE();
  140. CPanelCollection *pPanels = m_spMarsDocument->GetPanels();
  141. if(pPanels)
  142. {
  143. pPanels->lockLayout();
  144. //
  145. // For each panel in our window, show or hide it depending on if it is visible within our place.
  146. //
  147. for(int i=0; i<pPanels->GetSize(); i++)
  148. {
  149. CMarsPanel* pPanel = (*pPanels)[i];
  150. if(pPanel)
  151. {
  152. LPCWSTR pwszName = pPanel->GetName();
  153. VARIANT_BOOL bMakeVisible = VARIANT_FALSE;
  154. for(int j=0; j<m_PlacePanels.GetSize(); j++)
  155. {
  156. CPlacePanel* pPlacePanel = m_PlacePanels[j];
  157. if(pPlacePanel && StrEqlW(pwszName, pPlacePanel->GetName()))
  158. {
  159. // Let the place panel decide whether it should be shown
  160. bMakeVisible = pPlacePanel->ShowOnTransition( pPanel );
  161. break;
  162. }
  163. }
  164. pPanel->put_visible( bMakeVisible );
  165. }
  166. }
  167. pPanels->unlockLayout();
  168. }
  169. return S_OK;
  170. }
  171. HRESULT CMarsPlace::AddPanel(CPlacePanel *pPlacePanel)
  172. {
  173. ATLASSERT(!IsPassive());
  174. m_PlacePanels.Add(pPlacePanel);
  175. return S_OK;
  176. }
  177. static HRESULT local_TranslateFocusAccelerator(MSG *pMsg, CComPtr<IOleInPlaceActiveObject> pObj)
  178. {
  179. // identify Ctrl-Tab and F6 keystrokes
  180. BOOL isKeydown = (pMsg && (pMsg->message == WM_KEYDOWN));
  181. BOOL isCtrlTab = (isKeydown && (pMsg->wParam == VK_TAB) &&
  182. (::GetKeyState( VK_CONTROL ) & 0x8000));
  183. BOOL isF6 = (isKeydown && (pMsg->wParam == VK_F6));
  184. // map F6 and Ctrl-TAB to TAB for the Control in panel can set
  185. // focus to the first item
  186. HRESULT hr = S_FALSE;
  187. if (isF6 || isCtrlTab)
  188. {
  189. BYTE bState[256];
  190. if (isCtrlTab)
  191. {
  192. ::GetKeyboardState(bState);
  193. bState[VK_CONTROL] &= 0x7F;
  194. ::SetKeyboardState(bState);
  195. }
  196. pMsg->wParam = VK_TAB;
  197. hr = pObj->TranslateAccelerator(pMsg);
  198. if (isCtrlTab)
  199. {
  200. bState[VK_CONTROL] |= 0x80;
  201. ::SetKeyboardState(bState);
  202. }
  203. }
  204. return hr;
  205. }
  206. HRESULT CMarsPlace::TranslateAccelerator(MSG *pMsg)
  207. {
  208. FAIL_AFTER_PASSIVATE();
  209. HRESULT hr = S_FALSE;
  210. CMarsPanel *pActivePanel = m_spPlaceCollection->Document()->GetPanels()->ActivePanel();
  211. // First give the active panel a shot.
  212. if(pActivePanel)
  213. {
  214. pActivePanel->ResetTabCycle();
  215. hr = pActivePanel->TranslateAccelerator(pMsg);
  216. // Trident will return S_OK but we may have decided
  217. // we want it. This happens when you tab past the last
  218. // focusable item on the page.
  219. if(pActivePanel->GetTabCycle())
  220. {
  221. pActivePanel->ResetTabCycle();
  222. hr = S_FALSE;
  223. }
  224. }
  225. if(S_OK != hr)
  226. {
  227. int i;
  228. int nCurrent = -1;
  229. int nPanels = m_PlacePanels.GetSize();
  230. ATLASSERT(nPanels > 0);
  231. if(pActivePanel)
  232. {
  233. for (i = 0; i < nPanels; i++)
  234. {
  235. if(StrEql(pActivePanel->GetName(), m_PlacePanels[i]->GetName()))
  236. {
  237. nCurrent = i;
  238. break;
  239. }
  240. }
  241. }
  242. else
  243. {
  244. // This will force us to start at 0 in the for loop below
  245. nCurrent = nPanels;
  246. }
  247. CMarsPanel *pPanel;
  248. if(IsGlobalKeyMessage(pMsg))
  249. {
  250. // Now give the rest of the panels a crack at it
  251. for (i = 0; (i < nPanels) && (S_OK != hr); i++)
  252. {
  253. nCurrent++;
  254. if(nCurrent >= nPanels)
  255. {
  256. nCurrent = 0;
  257. }
  258. pPanel = m_spMarsDocument->GetPanels()->FindPanel(m_PlacePanels[nCurrent]->GetName());
  259. if(pPanel != pActivePanel)
  260. {
  261. hr = pPanel->TranslateAccelerator(pMsg);
  262. }
  263. else
  264. {
  265. // We're right back where we started
  266. break;
  267. }
  268. }
  269. }
  270. else
  271. {
  272. int nTab = IsVK_TABCycler(pMsg);
  273. if(nTab)
  274. {
  275. int nCount = nPanels;
  276. if(pActivePanel)
  277. {
  278. nCurrent += nTab;
  279. if(nCurrent < 0)
  280. {
  281. nCurrent = nPanels - 1;
  282. }
  283. else if(nCurrent >= nPanels)
  284. {
  285. nCurrent = 0;
  286. }
  287. }
  288. else
  289. {
  290. // If there is no active panel then let's tab to the first one
  291. nCurrent = 0;
  292. }
  293. while(nCount-- > 0)
  294. {
  295. pPanel = m_spMarsDocument->GetPanels()->FindPanel(m_PlacePanels[nCurrent]->GetName());
  296. if(pPanel && pPanel->IsVisible())
  297. {
  298. CComPtr<IOleInPlaceActiveObject> pObj;
  299. if(SUCCEEDED(pPanel->Window()->QueryControl( IID_IOleInPlaceActiveObject, (LPVOID*)&pObj )))
  300. {
  301. pPanel->ResetTabCycle();
  302. hr = pObj->TranslateAccelerator( pMsg );
  303. if(hr == S_FALSE)
  304. {
  305. // The WebOC behaves a little differently -- go figure :)
  306. // It seems to rely on getting the TranslateAccelerator call to do the
  307. // right UI activation the very first time.
  308. if(pPanel->IsWebBrowser())
  309. {
  310. pPanel->activate();
  311. // Fix up the hwnd so the panel will think it was intended for it.
  312. pMsg->hwnd = pPanel->Window()->m_hWnd;
  313. hr = pPanel->TranslateAccelerator(pMsg);
  314. if(hr == S_OK)
  315. {
  316. local_TranslateFocusAccelerator(pMsg, pObj);
  317. break;
  318. }
  319. // REVIEW -- this happens when we tab into a panel with no place to
  320. // tab to. IOW, it has nothing which can take the focus so we might
  321. // want to loop until we find someone who does.
  322. if(pPanel->GetTabCycle())
  323. {
  324. pPanel->ResetTabCycle();
  325. }
  326. }
  327. }
  328. else
  329. {
  330. if(pPanel->IsWebBrowser () ||
  331. pPanel->IsCustomControl() )
  332. {
  333. break;
  334. }
  335. if(pPanel->GetTabCycle() == false)
  336. {
  337. break;
  338. }
  339. pPanel->ResetTabCycle();
  340. hr = local_TranslateFocusAccelerator(pMsg, pObj);
  341. if (hr == S_OK && pPanel->GetTabCycle() == false)
  342. {
  343. break;
  344. }
  345. }
  346. }
  347. }
  348. nCurrent += nTab;
  349. if(nCurrent < 0)
  350. {
  351. nCurrent = nPanels - 1;
  352. }
  353. else if(nCurrent >= nPanels)
  354. {
  355. nCurrent = 0;
  356. }
  357. }
  358. if(pPanel && pPanel != pActivePanel)
  359. {
  360. m_spMarsDocument->GetPanels()->SetActivePanel( pPanel, TRUE );
  361. }
  362. hr = S_OK;
  363. }
  364. }
  365. }
  366. return hr;
  367. }
  368. void CMarsPlace::SaveLayout()
  369. {
  370. if(IsPassive()) return;
  371. //
  372. // For each panel in our window, save the layout and flag if it's present in the current place.
  373. //
  374. CPanelCollection *pPanels = m_spMarsDocument->GetPanels();
  375. for(int i=0; i<pPanels->GetSize(); i++)
  376. {
  377. CMarsPanel* pPanel = (*pPanels)[i];
  378. if(pPanel)
  379. {
  380. LPCWSTR pwszName = pPanel->GetName();
  381. BOOL fPresent = FALSE;
  382. for(int j=0; j<m_PlacePanels.GetSize(); j++)
  383. {
  384. CPlacePanel* pPlacePanel = m_PlacePanels[j];
  385. if(pPlacePanel && StrEqlW(pwszName, pPlacePanel->GetName()))
  386. {
  387. pPlacePanel->SaveLayout(pPanel);
  388. fPresent = TRUE;
  389. break;
  390. }
  391. }
  392. pPanel->SetPresenceInPlace( fPresent );
  393. }
  394. }
  395. }
  396. //==================================================================
  397. //
  398. // CPlaceCollection implementation
  399. //
  400. //==================================================================
  401. CPlaceCollection::CPlaceCollection(CMarsDocument *pMarsDocument)
  402. {
  403. m_spMarsDocument = pMarsDocument;
  404. m_lCurrentPlaceIndex = -1;
  405. m_lOldPlaceIndex = -1;
  406. }
  407. void CPlaceCollection::FreePlaces()
  408. {
  409. for (int i=0; i<GetSize(); i++)
  410. {
  411. (*this)[i]->Passivate();
  412. (*this)[i]->Release();
  413. }
  414. RemoveAll();
  415. }
  416. HRESULT CPlaceCollection::DoPassivate()
  417. {
  418. FreePlaces();
  419. m_spMarsDocument.Release();
  420. return S_OK;
  421. }
  422. IMPLEMENT_ADDREF_RELEASE(CPlaceCollection);
  423. STDMETHODIMP CPlaceCollection::QueryInterface(REFIID iid, void ** ppvObject)
  424. {
  425. HRESULT hr;
  426. if(API_IsValidWritePtr(ppvObject))
  427. {
  428. if((iid == IID_IUnknown ) ||
  429. (iid == IID_IDispatch ) ||
  430. (iid == IID_IMarsPlaceCollection) )
  431. {
  432. AddRef();
  433. *ppvObject = SAFECAST(this, IMarsPlaceCollection *);
  434. hr = S_OK;
  435. }
  436. else
  437. {
  438. *ppvObject = NULL;
  439. hr = E_NOINTERFACE;
  440. }
  441. }
  442. else
  443. {
  444. hr = E_INVALIDARG;
  445. }
  446. return hr;
  447. }
  448. // IMarsPlaceCollection
  449. STDMETHODIMP CPlaceCollection::place(LPWSTR pwszName, IMarsPlace **ppMarsPlace)
  450. {
  451. HRESULT hr = E_INVALIDARG;
  452. if(API_IsValidString(pwszName) && API_IsValidWritePtr(ppMarsPlace))
  453. {
  454. *ppMarsPlace = NULL;
  455. if(VerifyNotPassive(&hr))
  456. {
  457. CMarsPlace *pPlace;
  458. if(SUCCEEDED(GetPlace(pwszName, &pPlace)))
  459. {
  460. (*ppMarsPlace) = SAFECAST(pPlace, IMarsPlace *);
  461. hr = S_OK;
  462. }
  463. else
  464. {
  465. hr = S_FALSE;
  466. }
  467. }
  468. }
  469. return hr;
  470. }
  471. STDMETHODIMP CPlaceCollection::get_currentPlace(/* out, retval */ IMarsPlace **ppMarsPlace)
  472. {
  473. HRESULT hr = E_INVALIDARG;
  474. if(API_IsValidWritePtr(ppMarsPlace))
  475. {
  476. *ppMarsPlace = NULL;
  477. if(VerifyNotPassive(&hr))
  478. {
  479. if(m_lCurrentPlaceIndex != -1)
  480. {
  481. CMarsPlace *pPlace = (*this)[m_lCurrentPlaceIndex];
  482. *ppMarsPlace = SAFECAST(pPlace, IMarsPlace *);
  483. pPlace->AddRef();
  484. }
  485. hr = (*ppMarsPlace) ? S_OK : S_FALSE;
  486. }
  487. }
  488. return hr;
  489. }
  490. void CPlaceCollection::OnPanelReady()
  491. {
  492. // First see if we need to bother with this
  493. if(m_lCurrentPlaceIndex != m_lOldPlaceIndex)
  494. {
  495. CPlacePanelCollection& PlacePanels = GetCurrentPlace()->m_PlacePanels;
  496. CPanelCollection* pPanels = m_spMarsDocument->GetPanels();
  497. int nPanels = PlacePanels.GetSize();
  498. int nPanelsReady = 0;
  499. for(int i = 0; i < nPanels; i++)
  500. {
  501. CMarsPanel *pPanel = pPanels->FindPanel(PlacePanels[i]->GetName());
  502. if(pPanel && (!pPanel->IsTrusted() || (pPanel->GetReadyState()==READYSTATE_COMPLETE)))
  503. {
  504. nPanelsReady++;
  505. }
  506. }
  507. if(nPanelsReady >= nPanels)
  508. {
  509. if(m_lCurrentPlaceIndex != m_lOldPlaceIndex)
  510. {
  511. m_spMarsDocument->MarsWindow()->OnTransitionComplete();
  512. m_lOldPlaceIndex = m_lCurrentPlaceIndex;
  513. }
  514. }
  515. }
  516. }
  517. STDMETHODIMP CPlaceCollection::transitionTo(/* in */ BSTR bstrName)
  518. {
  519. HRESULT hr = E_INVALIDARG;
  520. if(API_IsValidString(bstrName))
  521. {
  522. if(VerifyNotPassive())
  523. {
  524. hr = S_FALSE;
  525. long lNewPlaceIndex;
  526. if(SUCCEEDED(FindPlaceIndex(bstrName, &lNewPlaceIndex)))
  527. {
  528. if(m_lCurrentPlaceIndex != lNewPlaceIndex)
  529. {
  530. if(m_lCurrentPlaceIndex >= 0)
  531. {
  532. GetCurrentPlace()->SaveLayout();
  533. }
  534. if(m_spMarsDocument->MarsWindow()->IsEventCancelled() == VARIANT_FALSE)
  535. {
  536. // Layout panels for new place
  537. m_lCurrentPlaceIndex = lNewPlaceIndex;
  538. (*this)[m_lCurrentPlaceIndex]->DoTransition();
  539. OnPanelReady();
  540. }
  541. hr = S_OK;
  542. }
  543. m_spMarsDocument->MarsWindow()->NotifyHost( MARSHOST_ON_PLACE_TRANSITION_DONE, SAFECAST(GetCurrentPlace(), IMarsPlace *), 0 );
  544. }
  545. }
  546. }
  547. return hr;
  548. }
  549. HRESULT CPlaceCollection::FindPlaceIndex(LPCWSTR pwszName, long *plIndex)
  550. {
  551. ATLASSERT(!IsPassive());
  552. int i;
  553. *plIndex = -1;
  554. for (i=0; i<GetSize(); i++)
  555. {
  556. if(pwszName == NULL || StrEqlW(pwszName, (*this)[i]->GetName()))
  557. {
  558. *plIndex = (long)i;
  559. return S_OK;
  560. }
  561. }
  562. return E_FAIL;
  563. }
  564. HRESULT CPlaceCollection::GetPlace(LPCWSTR pwszName, /*optional*/ CMarsPlace **ppPlace)
  565. {
  566. ATLASSERT(!IsPassive());
  567. long lIndex;
  568. HRESULT hrRet;
  569. if(ppPlace)
  570. {
  571. *ppPlace = NULL;
  572. }
  573. if(SUCCEEDED(hrRet = FindPlaceIndex(pwszName, &lIndex)))
  574. {
  575. if(ppPlace)
  576. {
  577. *ppPlace = (*this)[lIndex];
  578. (*ppPlace)->AddRef();
  579. }
  580. }
  581. return hrRet;
  582. }
  583. // Called by our XML parser only
  584. HRESULT CPlaceCollection::AddPlace(LPCWSTR pwszName, CMarsPlace **ppPlace)
  585. {
  586. *ppPlace = NULL;
  587. HRESULT hr = S_OK;
  588. if(VerifyNotPassive(&hr))
  589. {
  590. if(SUCCEEDED(GetPlace(pwszName, NULL)))
  591. {
  592. // Place of this name already exists
  593. return E_FAIL;
  594. }
  595. CMarsPlace *pPlace = new CMarsPlace(this, m_spMarsDocument);
  596. if(pPlace)
  597. {
  598. if(Add(pPlace))
  599. {
  600. pPlace->Init(pwszName);
  601. pPlace->AddRef();
  602. *ppPlace = pPlace;
  603. }
  604. else
  605. {
  606. pPlace->Release();
  607. hr = E_OUTOFMEMORY;
  608. }
  609. }
  610. else
  611. {
  612. hr = E_OUTOFMEMORY;
  613. }
  614. }
  615. return hr;
  616. }