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.

1631 lines
56 KiB

  1. // Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
  2. #include "header.h"
  3. #include "hha_strtable.h"
  4. #include "strtable.h"
  5. #include "hhctrl.h"
  6. #include "resource.h"
  7. #include "index.h"
  8. #include "htmlhelp.h"
  9. #include "cpaldc.h"
  10. #include "secwin.h"
  11. #include "wwheel.h"
  12. #include "onclick.h"
  13. #include <wininet.h>
  14. #include "secwin.h"
  15. #include "contain.h"
  16. #include "subset.h"
  17. #include "cctlww.h"
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static const char THIS_FILE[] = __FILE__;
  21. #endif
  22. AUTO_CLASS_COUNT_CHECK( CIndex );
  23. //////////////////////////////////////////////////////////////////////////
  24. //
  25. // Constants
  26. //
  27. #define BOX_HEIGHT 24
  28. #define ODA_CLEAR 0x0008
  29. const int c_StaticControlSpacing = 3; // Space between text and static control.
  30. const int c_ControlSpacing = 8 ; // Space between two controls.
  31. //////////////////////////////////////////////////////////////////////////
  32. //
  33. // Window Proc Prototypes.
  34. //
  35. LRESULT WINAPI EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  36. WNDPROC lpfnlEditWndProc = NULL;
  37. static LRESULT WINAPI ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  38. WNDPROC lpfnlBtnWndProc = NULL;
  39. //////////////////////////////////////////////////////////////////////////
  40. //
  41. // Constructor
  42. //
  43. CIndex::CIndex(CHtmlHelpControl* phhctrl, IUnknown* pUnkOuter, CHHWinType* phh)
  44. : m_hwndResizeToParent(NULL)
  45. {
  46. m_phhctrl = phhctrl;
  47. m_pOuter = pUnkOuter;
  48. m_phh = phh;
  49. m_hwndEditBox = NULL;
  50. m_hwndStaticKeyword = NULL ;
  51. m_hwndListBox = NULL;
  52. m_hwndDisplayButton = NULL;
  53. m_fSelectionChange = FALSE;
  54. m_padding = 0; // padding to put around the Index
  55. if (phh)
  56. m_NavTabPos = phh->tabpos ;
  57. else
  58. m_NavTabPos = HHWIN_NAVTAB_TOP ;
  59. m_cFonts = 0;
  60. m_ahfonts = NULL;
  61. m_fGlobal = FALSE;
  62. m_hbmpBackGround = NULL;
  63. m_hbrBackGround = NULL;
  64. m_langid = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID()));
  65. m_fBinary = FALSE; // default to FALSE until we find out which index we are reading
  66. pInfoType = NULL;
  67. m_bInit = FALSE;
  68. m_pVList = NULL;
  69. m_bUnicode = FALSE;
  70. }
  71. CIndex::~CIndex()
  72. {
  73. DESTROYIFVALID(m_hwndListBox);
  74. DESTROYIFVALID(m_hwndDisplayButton);
  75. DESTROYIFVALID(m_hwndEditBox);
  76. DESTROYIFVALID(m_hwndStaticKeyword);
  77. if (m_cFonts) {
  78. for (int i = 0; i < m_cFonts; i++)
  79. DeleteObject(m_ahfonts[i]);
  80. lcFree(m_ahfonts);
  81. }
  82. if( m_pVList )
  83. delete m_pVList;
  84. }
  85. void CIndex::HideWindow(void)
  86. {
  87. ::ShowWindow(m_hwndEditBox, SW_HIDE);
  88. ::ShowWindow(m_hwndListBox, SW_HIDE);
  89. ::ShowWindow(m_hwndDisplayButton, SW_HIDE);
  90. ::ShowWindow(m_hwndStaticKeyword, SW_HIDE);
  91. }
  92. void CIndex::ShowWindow(void)
  93. {
  94. ::ShowWindow(m_hwndEditBox, SW_SHOW);
  95. ::ShowWindow(m_hwndListBox, SW_SHOW);
  96. ::ShowWindow(m_hwndDisplayButton, SW_SHOW);
  97. ::ShowWindow(m_hwndStaticKeyword, SW_SHOW);
  98. HWND hWnd;
  99. char szClassName[MAX_PATH];
  100. if ( (hWnd = GetParent(m_hwndEditBox)) )
  101. {
  102. GetClassName(hWnd, szClassName, sizeof(szClassName));
  103. if (! lstrcmpi(szClassName, "HHCtrlWndClass") )
  104. {
  105. // Ok, we're up as an axtive x control.
  106. //
  107. COleControl* pCtl;
  108. if ( (pCtl = (COleControl*)GetWindowLongPtr(hWnd, GWLP_USERDATA)) )
  109. {
  110. pCtl->InPlaceActivate(OLEIVERB_UIACTIVATE);
  111. return;
  112. }
  113. }
  114. }
  115. SetFocus(m_hwndEditBox);
  116. }
  117. // Can't inline this because of dereferencing m_phh
  118. //
  119. //
  120. HFONT CIndex::GetContentFont()
  121. {
  122. if ( m_cFonts && m_ahfonts[m_cFonts - 1] )
  123. return m_ahfonts[m_cFonts - 1];
  124. else
  125. {
  126. if ( m_phh )
  127. return m_phh->GetContentFont();
  128. else
  129. {
  130. if ( m_phhctrl && m_phhctrl->GetContentFont() )
  131. return m_phhctrl->GetContentFont();
  132. else
  133. {
  134. // this is likely the case where the control is being instantiated via object script on an html page. We
  135. // won't have a phh. Correct thing to do would be to ask IE about content language? Maybe look in the
  136. // sitemap? For now we'll use the UI font.
  137. //
  138. return _Resource.GetUIFont();
  139. }
  140. }
  141. }
  142. }
  143. void
  144. CIndex::InitDlgItemArray()
  145. {
  146. // Currently we are only using the m_accel member.
  147. //--- Setup the dlg array for each control.
  148. //--- Keyword edit control
  149. int i = c_KeywordEdit;
  150. m_aDlgItems[i].m_hWnd = m_hwndEditBox ; //::GetDlgItem(m_hWnd, IDEDIT_INDEX) ;
  151. //::GetWindowRect(m_aDlgItems[i].m_hWnd, &rectCurrent) ; // Get screen coordinates.
  152. //ScreenRectToClientRect(m_hWnd, &rectCurrent); // Convert to client
  153. m_aDlgItems[i].m_id = IDEDIT_INDEX;
  154. m_aDlgItems[i].m_accelkey = (CHAR)GetAcceleratorKey(m_hwndStaticKeyword); // No accelerator.
  155. m_aDlgItems[i].m_Type = ItemInfo::Generic;
  156. /* TODO: Finish using this
  157. m_aDlgItems[i].m_bIgnoreEnabled = TRUE ;
  158. //m_aDlgItems[i].m_bEnabled; // Is the control enabled?
  159. m_aDlgItems[i].m_bIgnoreMax = TRUE ; // Ignore the Max parameter.
  160. m_aDlgItems[i].m_bGrowH = TRUE; // Grow Horizontally.
  161. m_aDlgItems[i].m_bGrowV = TRUE ; // Grow Vertically.
  162. m_aDlgItems[i].m_JustifyV = Justify::Top; // Do we stick to the top or the bottom.
  163. //m_aDlgItems[i].m_iOffsetV = ; // Distance from our justification point.
  164. m_aDlgItems[i].m_JustifyH = Justify::Left; // Do we stick to the right or the left
  165. //m_aDlgItems[i].m_iOffsetH = rectDlg.right - rectCurrent.left;
  166. m_aDlgItems[i].m_iPadH = rectDlg.right - rectCurrent.right; // Maintain same distance. If someone to the right grows we are broken.
  167. m_aDlgItems[i].m_iPadV = rectDlg.bottom - rectCurrent.bottom;
  168. m_aDlgItems[i].m_rectMin = rectCurrent;
  169. m_aDlgItems[i].m_rectCur = rectCurrent;
  170. //m_aDlgItems[i].m_rectMax ; // Max size.
  171. */
  172. //--- Display btn
  173. i = c_DisplayBtn;
  174. m_aDlgItems[i].m_hWnd = m_hwndDisplayButton; //::GetDlgItem(m_hWnd, IDBTN_DISPLAY) ;
  175. //::GetWindowRect(m_aDlgItems[i].m_hWnd, &rectCurrent) ; // Get screen coordinates.
  176. //ScreenRectToClientRect(m_hWnd, &rectCurrent); // Convert to client
  177. m_aDlgItems[i].m_id = IDBTN_DISPLAY;
  178. m_aDlgItems[i].m_accelkey = (CHAR)GetAcceleratorKey(m_aDlgItems[i].m_hWnd);
  179. m_aDlgItems[i].m_Type = ItemInfo::Button;
  180. /* TODO: Finish using this
  181. m_aDlgItems[i].m_bIgnoreEnabled = TRUE ;
  182. //m_aDlgItems[i].m_bEnabled; // Is the control enabled?
  183. m_aDlgItems[i].m_bIgnoreMax = TRUE ; // Ignore the Max parameter.
  184. m_aDlgItems[i].m_bGrowH = TRUE; // Grow Horizontally.
  185. m_aDlgItems[i].m_bGrowV = TRUE ; // Grow Vertically.
  186. m_aDlgItems[i].m_JustifyV = Justify::Top; // Do we stick to the top or the bottom.
  187. //m_aDlgItems[i].m_iOffsetV = ; // Distance from our justification point.
  188. m_aDlgItems[i].m_JustifyH = Justify::Left; // Do we stick to the right or the left
  189. //m_aDlgItems[i].m_iOffsetH = rectDlg.right - rectCurrent.left;
  190. m_aDlgItems[i].m_iPadH = rectDlg.right - rectCurrent.right; // Maintain same distance. If someone to the right grows we are broken.
  191. m_aDlgItems[i].m_iPadV = rectDlg.bottom - rectCurrent.bottom;
  192. m_aDlgItems[i].m_rectMin = rectCurrent;
  193. m_aDlgItems[i].m_rectCur = rectCurrent;
  194. //m_aDlgItems[i].m_rectMax ; // Max size.
  195. */
  196. }
  197. BOOL CIndex::Create(HWND hwndParent)
  198. {
  199. /* Note: hwndParent is either the Navigation Frame or its the tab ctrl.
  200. This class does not parent to the tab ctrl, but to the navigation frame.
  201. GetParentSize will always return the hwndNavigation, if hwndParent is the
  202. tabctrl.
  203. The reason that it doesn't parent to the tab ctrl is that the tab ctrl
  204. steals commands. What should really have happened is that all of the windows
  205. in this control should be contained in another window. However, its too late to
  206. change this now.
  207. */
  208. RECT rcParent, rcChild;
  209. // Save the hwndParent for ResizeWindow.
  210. m_hwndResizeToParent = hwndParent ;
  211. // Note: GetParentSize will return hwndNavigation if hwndParent is the
  212. // tab ctrl.
  213. // ???BUG??? Is bypassing the tab ctrl in the parenting structure causing painting problems?
  214. hwndParent = GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
  215. rcParent.top += GetSystemMetrics(SM_CYSIZEFRAME)*2 ; //HACK: Fudge the top since we are not parented to the tabctrl.
  216. CopyRect(&rcChild, &rcParent);
  217. //--- Keyword Static Text Control
  218. // Place the "Keyword" static text on top of the edit control
  219. m_hwndStaticKeyword = W_CreateWindowEx(WS_EX_TRANSPARENT, L"STATIC", GetStringResourceW(IDS_TYPE_KEYWORD),
  220. WS_CHILD , rcChild.left, rcChild.top,
  221. RECT_WIDTH(rcChild), BOX_HEIGHT, hwndParent,
  222. (HMENU) ID_STATIC_KEYWORDS, _Module.GetModuleInstance(), NULL, &m_bUnicode);
  223. if (!m_hwndStaticKeyword)
  224. {
  225. return FALSE ;
  226. }
  227. // Get the dimensions of the text for sizing and spacing needs.
  228. DWORD dwExt = GetStaticDimensions( m_hwndStaticKeyword, _Resource.GetUIFont(), GetStringResource(IDS_TYPE_KEYWORD), RECT_WIDTH(rcChild) );
  229. rcChild.bottom = rcChild.top+HIWORD(dwExt) ;
  230. MoveWindow(m_hwndStaticKeyword, rcChild.left, rcChild.top,
  231. RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), FALSE );
  232. //--- Edit Control
  233. // Space out.
  234. RECT rcEdit; // Save so that we can use rcChild for the display button.
  235. CopyRect(&rcEdit, &rcChild) ;
  236. rcEdit.top = rcChild.bottom + c_StaticControlSpacing; // Add space between static and control.
  237. rcEdit.bottom = rcEdit.top + BOX_HEIGHT;
  238. // Create edit control.
  239. m_hwndEditBox = W_CreateWindowEx(WS_EX_CLIENTEDGE | g_RTL_Style, L"EDIT", L"",
  240. WS_CHILD | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, rcEdit.left, rcEdit.top,
  241. RECT_WIDTH(rcEdit), RECT_HEIGHT(rcEdit), hwndParent,
  242. (HMENU) IDEDIT_INDEX, _Module.GetModuleInstance(), NULL, &m_bUnicode);
  243. if (!m_hwndEditBox)
  244. {
  245. DestroyWindow(m_hwndStaticKeyword) ;
  246. return FALSE;
  247. }
  248. // Sub-class the edit box
  249. if (lpfnlEditWndProc == NULL)
  250. lpfnlEditWndProc = W_GetWndProc(m_hwndEditBox, m_bUnicode);
  251. W_SubClassWindow (m_hwndEditBox, (LONG_PTR) EditProc, m_bUnicode);
  252. //--- Display Button.
  253. // Align from the bottom.
  254. RECT rcDisplayBtn ;
  255. CopyRect(&rcDisplayBtn, &rcChild) ;
  256. rcDisplayBtn.bottom = rcParent.bottom ; //Changed from +2.
  257. rcDisplayBtn.top = rcParent.bottom - BOX_HEIGHT;
  258. // Create
  259. m_hwndDisplayButton = W_CreateWindow(L"button",
  260. (LPCWSTR)GetStringResourceW(IDS_ENGLISH_DISPLAY),
  261. WS_CHILD | WS_TABSTOP, rcDisplayBtn.left, rcDisplayBtn.top,
  262. RECT_WIDTH(rcDisplayBtn), RECT_HEIGHT(rcDisplayBtn), hwndParent,
  263. (HMENU) IDBTN_DISPLAY, _Module.GetModuleInstance(), NULL, &m_bUnicode);
  264. if (!m_hwndDisplayButton) {
  265. DestroyWindow(m_hwndEditBox);
  266. DestroyWindow(m_hwndStaticKeyword) ;
  267. return FALSE;
  268. }
  269. // Sub-class the "display" button ?
  270. //
  271. if ( m_phh )
  272. {
  273. if (lpfnlBtnWndProc == NULL)
  274. lpfnlBtnWndProc = W_GetWndProc(m_hwndDisplayButton, m_bUnicode);
  275. W_SubClassWindow(m_hwndDisplayButton, (LONG_PTR)ButtonProc, m_bUnicode);
  276. SETTHIS(m_hwndDisplayButton);
  277. }
  278. //--- ListView.
  279. // Space
  280. rcChild.top = rcEdit.bottom + c_ControlSpacing ;
  281. rcChild.bottom = rcDisplayBtn.top - c_ControlSpacing ;
  282. m_pVList = new CVirtualListCtrl(
  283. (m_phh && m_phh->m_phmData ? m_phh->m_phmData->m_sysflags.lcid : g_lcidSystem));
  284. if (! (m_hwndListBox = m_pVList->CreateVlistbox(hwndParent, &rcChild)) )
  285. {
  286. DestroyWindow(m_hwndDisplayButton);
  287. DestroyWindow(m_hwndEditBox);
  288. DestroyWindow(m_hwndStaticKeyword) ;
  289. return FALSE;
  290. }
  291. if (m_pszFont) {
  292. if (!m_fGlobal) {
  293. m_cFonts++;
  294. if (m_cFonts == 1)
  295. m_ahfonts = (HFONT*) lcMalloc(m_cFonts * sizeof(HFONT));
  296. else
  297. m_ahfonts = (HFONT*) lcReAlloc(m_ahfonts, m_cFonts * sizeof(HFONT));
  298. INT iCharset = -1;
  299. if ( m_phh )
  300. iCharset = m_phh->GetContentCharset();
  301. else if ( m_phhctrl )
  302. iCharset = m_phhctrl->GetCharset();
  303. m_ahfonts[m_cFonts - 1] = CreateUserFont(m_pszFont, NULL, NULL, iCharset);
  304. }
  305. }
  306. // Use a more readable font
  307. if ( m_phh && !m_ahfonts )
  308. SendMessage(m_hwndListBox, WM_SETFONT, (WPARAM) m_phh->GetAccessableContentFont(), FALSE);
  309. else
  310. SendMessage(m_hwndListBox, WM_SETFONT, (WPARAM) GetContentFont(), FALSE);
  311. SendMessage(m_hwndEditBox, WM_SETFONT, (WPARAM) GetContentFont(), FALSE);
  312. SendMessage(m_hwndDisplayButton, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
  313. SendMessage(m_hwndStaticKeyword, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
  314. //BUGBUG: Doesn't resize any of the other controls.
  315. dwExt = GetButtonDimensions(m_hwndDisplayButton, _Resource.GetUIFont(), GetStringResource(IDS_ENGLISH_DISPLAY));
  316. MoveWindow(m_hwndDisplayButton, rcDisplayBtn.right - LOWORD(dwExt), rcDisplayBtn.top,
  317. LOWORD(dwExt), HIWORD(dwExt), FALSE);
  318. m_listbox.m_hWnd = m_hwndListBox;
  319. FillListBox();
  320. if (!m_fGlobal)
  321. m_pVList->PaintParamsSetup(m_clrBackground, m_clrForeground, m_pszBackBitmap);
  322. // Initialize the array containing the dialog information.
  323. InitDlgItemArray() ;
  324. ShowWindow();
  325. return TRUE;
  326. }
  327. //////////////////////////////////////////////////////////////////////////
  328. //
  329. // ResizeWindow
  330. //
  331. void CIndex::ResizeWindow()
  332. {
  333. ASSERT(::IsValidWindow(m_hwndEditBox)) ;
  334. // Resize to fit the client area of the parent.
  335. HWND hwndParent = m_hwndResizeToParent ;
  336. ASSERT(::IsValidWindow(hwndParent)) ;
  337. RECT rcParent, rcChild;
  338. GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
  339. rcParent.top += GetSystemMetrics(SM_CYSIZEFRAME)*2 ; //HACK: Fudge the top since we are not parented to the tabctrl.
  340. CopyRect(&rcChild, &rcParent);
  341. //--- Keyword Static Control
  342. // Resize the Static above the combo control
  343. RECT rcStatic ;
  344. CopyRect(&rcStatic, &rcChild) ;
  345. DWORD dwExt = GetStaticDimensions( m_hwndStaticKeyword, _Resource.GetUIFont(), GetStringResource(IDS_TYPE_KEYWORD), RECT_WIDTH(rcChild) );
  346. rcStatic.bottom = rcChild.top+HIWORD(dwExt);
  347. MoveWindow(m_hwndStaticKeyword, rcStatic.left, rcStatic.top,
  348. RECT_WIDTH(rcStatic), RECT_HEIGHT(rcStatic), TRUE);
  349. //--- Edit Control
  350. RECT rcEdit ;
  351. CopyRect(&rcEdit, &rcChild) ;
  352. rcEdit.top = rcStatic.bottom + c_StaticControlSpacing; //space for the static
  353. dwExt = GetStaticDimensions( m_hwndEditBox, GetContentFont(), "Test", RECT_WIDTH(rcEdit) );
  354. rcEdit.bottom = rcEdit.top+HIWORD(dwExt) + GetSystemMetrics(SM_CYSIZEFRAME)*2 ;
  355. MoveWindow(m_hwndEditBox, rcEdit.left, rcEdit.top, RECT_WIDTH(rcEdit), RECT_HEIGHT(rcEdit), TRUE);
  356. //--- Display Button
  357. RECT rcDisplayBtn;
  358. CopyRect(&rcDisplayBtn, &rcChild) ;
  359. dwExt = GetButtonDimensions(m_hwndDisplayButton, _Resource.GetUIFont(), GetStringResource(IDS_ENGLISH_DISPLAY));
  360. rcDisplayBtn.bottom = rcParent.bottom ;
  361. rcDisplayBtn.top = rcParent.bottom - HIWORD(dwExt);
  362. MoveWindow(m_hwndDisplayButton, rcDisplayBtn.right - LOWORD(dwExt), rcDisplayBtn.top,
  363. LOWORD(dwExt), HIWORD(dwExt), TRUE);
  364. //--- List Control
  365. rcChild.top = rcEdit.bottom + c_ControlSpacing;
  366. rcChild.bottom = rcDisplayBtn.top - c_ControlSpacing;
  367. MoveWindow(m_hwndListBox, rcChild.left,
  368. rcChild.top, RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), TRUE);
  369. }
  370. ///////////////////////////////////////////////////////////
  371. //
  372. // SeedEditCtrl - Places text into the edit control
  373. //
  374. void CIndex::Seed(WCHAR* pwszSeed)
  375. {
  376. if (IsValidWindow(m_hwndEditBox))
  377. {
  378. if (pwszSeed == NULL)
  379. pwszSeed = L"";
  380. if ( GetVersion() < 0x80000000 ) // If NT...
  381. SetWindowTextW(m_hwndEditBox, pwszSeed);
  382. else
  383. {
  384. char szTmp[MAX_URL];
  385. WideCharToMultiByte(CP_ACP, 0, pwszSeed, -1, szTmp, MAX_URL, 0, 0);
  386. SetWindowText(m_hwndEditBox, szTmp);
  387. }
  388. }
  389. }
  390. //
  391. // Narrow seed function is a fallback only. Callers are advised to use the wide version.
  392. //
  393. void CIndex::Seed(LPCSTR pszSeed)
  394. {
  395. UINT uiCP;
  396. WCHAR wszBuf[MAX_URL];
  397. if ( GetVersion() < 0x80000000 ) // If NT i.e. UNICODE OS
  398. {
  399. if ( m_phh )
  400. uiCP = m_phh->GetCodePage();
  401. else if ( m_phhctrl )
  402. uiCP = m_phhctrl->GetCodePage();
  403. else
  404. uiCP = CP_ACP;
  405. MultiByteToWideChar(uiCP, 0, pszSeed, -1, wszBuf, MAX_URL);
  406. Seed(wszBuf);
  407. }
  408. else
  409. {
  410. if (IsValidWindow(m_hwndEditBox))
  411. {
  412. if (pszSeed == NULL)
  413. pszSeed = "";
  414. SetWindowText(m_hwndEditBox, pszSeed);
  415. }
  416. }
  417. }
  418. /***************************************************************************
  419. FUNCTION: CHtmlHelpControl::LoadIndexFile
  420. PURPOSE:
  421. PARAMETERS:
  422. pszMasterFile
  423. RETURNS:
  424. COMMENTS:
  425. MODIFICATION DATES:
  426. 12-Jul-1997 [ralphw]
  427. ***************************************************************************/
  428. BOOL CHtmlHelpControl::LoadIndexFile(PCSTR pszMasterFile)
  429. {
  430. TCHAR szPath[MAX_PATH+10];
  431. if (!ConvertToCacheFile(pszMasterFile, szPath)) {
  432. szPath[0] = '\0';
  433. if (!IsCompiledHtmlFile(pszMasterFile) && m_pWebBrowserApp) {
  434. CStr cszCurUrl;
  435. m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
  436. PSTR pszChmSep = strstr(cszCurUrl, txtDoubleColonSep);
  437. if (pszChmSep) { // this is a compiled HTML file
  438. strcpy(pszChmSep + 2, pszMasterFile);
  439. strcpy(szPath, cszCurUrl);
  440. }
  441. }
  442. if (!szPath[0]) {
  443. CStr cszMsg(IDS_CANT_FIND_FILE, pszMasterFile);
  444. MsgBox(cszMsg);
  445. return FALSE;
  446. }
  447. }
  448. m_pindex = new CIndex(this, m_pUnkOuter, NULL);
  449. UINT CodePage = 0;
  450. if( m_pindex && m_pindex->m_phh && m_pindex->m_phh->m_phmData ) {
  451. CodePage = m_pindex->m_phh->m_phmData->GetInfo()->GetCodePage();
  452. }
  453. if (!m_pindex->ReadFromFile(szPath, TRUE, this, CodePage))
  454. return FALSE;
  455. return TRUE;
  456. }
  457. BOOL CIndex::ReadIndexFile( PCSTR pszFile )
  458. {
  459. UINT CodePage = 0;
  460. if( m_phh && m_phh->m_phmData ) {
  461. CodePage = m_phh->m_phmData->GetInfo()->GetCodePage();
  462. }
  463. // check for binary version of the keyword word wheel
  464. if (m_phh->m_phmData) {
  465. if (HashFromSz(FindFilePortion(pszFile)) != m_phh->m_phmData->m_hashBinaryIndexName) {
  466. return ReadFromFile(pszFile, TRUE, NULL, CodePage);
  467. }
  468. CExTitle* pTitle;
  469. CFileSystem* pFS;
  470. CSubFileSystem* pSFS;
  471. if ((pTitle = m_phh->m_phmData->m_pTitleCollection->GetFirstTitle())) {
  472. pFS = pTitle->GetTitleIdxFileSystem();
  473. pSFS = new CSubFileSystem(pFS);
  474. if (SUCCEEDED(pSFS->OpenSub("$WWKeywordLinks\\Property")))
  475. m_fBinary = TRUE;
  476. delete pSFS;
  477. }
  478. }
  479. if (m_fBinary)
  480. return m_fBinary;
  481. return ReadFromFile(pszFile, TRUE, NULL, CodePage);
  482. }
  483. void CIndex::FillListBox(BOOL fReset)
  484. {
  485. ASSERT(IsValidWindow(m_hwndListBox));
  486. if (!IsValidWindow(m_hwndListBox))
  487. return;
  488. int iCount = 0;
  489. if (m_fBinary) {
  490. CWordWheel* pWordWheel;
  491. if (m_phh->m_phmData)
  492. pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
  493. else
  494. pWordWheel = NULL;
  495. if (pWordWheel)
  496. iCount = pWordWheel->GetCount();
  497. #if 0 // subset test code
  498. // now loop thru each item in the list and if they exist (in the subset),
  499. // then add the wordwheel dword to the item data entry (entry map)
  500. DWORD dwStart = GetTickCount();
  501. int iCountSubset = 0;
  502. DWORD* pdwSubsetArray = new DWORD[iCount];
  503. CStructuralSubset* pSubset = NULL;
  504. CExTitle* pTitle = NULL;
  505. for( int iKeyword = 0; iKeyword < iCount; iKeyword++ ) {
  506. BOOL bAddItem = FALSE;
  507. // perf enhancement (cache all data for this keyword)
  508. pWordWheel->GetIndexData( iKeyword, TRUE );
  509. // if place holder add the item and continue
  510. if( pWordWheel->IsPlaceHolder( iKeyword ) ) {
  511. bAddItem = TRUE;
  512. }
  513. // scan the hits, if at least one is in the subset then add the item and continue
  514. else {
  515. DWORD dwHitCount = pWordWheel->GetHitCount( iKeyword );
  516. for( DWORD i = 0; i < dwHitCount; i++ ) {
  517. DWORD dwURLId = pWordWheel->GetHit( iKeyword, i, &pTitle);
  518. if( !pSubset && pTitle->m_pCollection->m_pSSList ) {
  519. pSubset = pTitle->m_pCollection->m_pSSList->GetF1();
  520. if( !pSubset )
  521. break;
  522. }
  523. if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList ) {
  524. if( pSubset && pSubset->IsTitleInSubset(pTitle) ) {
  525. bAddItem = TRUE;
  526. break;
  527. }
  528. }
  529. }
  530. }
  531. // add the item if found
  532. if( bAddItem ) {
  533. pdwSubsetArray[iCountSubset] = iKeyword;
  534. iCountSubset++;
  535. }
  536. }
  537. DWORD dwEnd = GetTickCount();
  538. char szTime[1024];
  539. sprintf( szTime, "Subset Filtering took:\n%d seconds\n%d original items\n%d final items",
  540. (dwEnd-dwStart)/1000, iCount, iCountSubset );
  541. MsgBox( szTime, MB_OK );
  542. delete [] pdwSubsetArray;
  543. #endif // end of subset test code
  544. }
  545. else {
  546. iCount = CountStrings();
  547. }
  548. m_pVList->SetItemCount(iCount);
  549. m_bInit = TRUE;
  550. }
  551. void CIndex::OnVKListNotify(NMHDR* pNMHdr)
  552. {
  553. PVLC_ITEM pVlcItem = NULL;
  554. int pos;
  555. SITEMAP_ENTRY* pSiteMapEntry;
  556. WCHAR wszKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
  557. CWordWheel* pWordWheel = NULL;
  558. switch(pNMHdr->code)
  559. {
  560. case NM_RDBLCLK:
  561. break;
  562. case NM_RCLICK:
  563. break;
  564. case NM_CLICK:
  565. break;
  566. case NM_KILLFOCUS:
  567. break;
  568. case NM_SETFOCUS:
  569. break;
  570. case VLN_TAB:
  571. if (GetKeyState(VK_SHIFT) < 0)
  572. SetFocus(m_hwndEditBox);
  573. else
  574. SetFocus(m_hwndDisplayButton);
  575. break;
  576. case VLN_GETITEM:
  577. pVlcItem = (PVLC_ITEM)pNMHdr;
  578. if (m_fBinary)
  579. {
  580. CWordWheel* pWordWheel;
  581. if (m_phh->m_phmData)
  582. pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
  583. else
  584. pWordWheel = NULL;
  585. if (pWordWheel) {
  586. if (pWordWheel->GetString(pVlcItem->iItem, pVlcItem->lpwsz, pVlcItem->cchMax)) {
  587. pVlcItem->iLevel = pWordWheel->GetLevel(pVlcItem->iItem) + 1;
  588. BOOL bFound = FALSE;
  589. CExTitle* pTitle = NULL;
  590. WCHAR wszSeeAlso[1024];
  591. if( pWordWheel->IsPlaceHolder(pVlcItem->iItem) )
  592. bFound = TRUE;
  593. else if( pWordWheel->GetSeeAlso(pVlcItem->iItem, wszSeeAlso, sizeof(wszSeeAlso) ) )
  594. bFound = TRUE;
  595. else {
  596. DWORD dwHitCount = pWordWheel->GetHitCount(pVlcItem->iItem);
  597. for (DWORD i = 0; i < dwHitCount; i++) {
  598. DWORD dwURLId = pWordWheel->GetHit(pVlcItem->iItem, i, &pTitle);
  599. // Structural subset filter ?
  600. //
  601. CStructuralSubset* pSubset;
  602. if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList &&
  603. (pSubset = pTitle->m_pCollection->m_pSSList->GetF1()) && !pSubset->IsEntire() )
  604. {
  605. // Yes, filter using the current structural subset for F1.
  606. //
  607. if (! pSubset->IsTitleInSubset(pTitle) ) {
  608. continue;
  609. }
  610. }
  611. bFound = TRUE;
  612. break;
  613. }
  614. }
  615. if( !bFound )
  616. pVlcItem->dwFlags = 0x1;
  617. else
  618. pVlcItem->dwFlags = 0;
  619. }
  620. }
  621. }
  622. else
  623. {
  624. // +1 because Ctable is 1-based
  625. SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pVlcItem->iItem + 1);
  626. if (pSiteMapEntry) {
  627. pSiteMapEntry->GetKeyword(pVlcItem->lpwsz, pVlcItem->cchMax);
  628. if(pVlcItem->cchMax)
  629. pVlcItem->lpwsz[pVlcItem->cchMax-1] = 0; // null terminate the string
  630. pVlcItem->iLevel = pSiteMapEntry->GetLevel();
  631. pVlcItem->dwFlags = 0;
  632. }
  633. }
  634. break;
  635. case VLN_SELECT:
  636. if( m_fBinary )
  637. {
  638. if (m_phh->m_phmData)
  639. pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
  640. }
  641. pos = m_pVList->GetSelection();
  642. m_fSelectionChange = TRUE; // ignore EN_CHANGE
  643. if (m_fBinary) {
  644. if (pWordWheel) {
  645. int iIndex = pos;
  646. if( pWordWheel->GetString(iIndex, wszKeyword, (sizeof(wszKeyword)/2), TRUE) )
  647. Seed(wszKeyword);
  648. else
  649. Seed((WCHAR*)NULL);
  650. }
  651. }
  652. else {
  653. pSiteMapEntry = GetSiteMapEntry(pos + 1);
  654. Seed(pSiteMapEntry->GetKeyword());
  655. }
  656. m_fSelectionChange = FALSE; // ignore EN_CHANGE
  657. break;
  658. case NM_RETURN:
  659. case NM_DBLCLK:
  660. PostMessage(FindMessageParent(m_hwndListBox), WM_COMMAND, MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
  661. break;
  662. }
  663. return;
  664. }
  665. void CHtmlHelpControl::OnSizeIndex(LPRECT prc)
  666. {
  667. RECT rc;
  668. GetClientRect(GetParent(m_hwnd), &rc);
  669. InflateRect(&rc,
  670. m_hpadding == -1 ? 0 : -m_hpadding,
  671. m_vpadding == -1 ? 0 : -m_vpadding);
  672. RECT rcButton;
  673. GetWindowRect(m_hwndDisplayButton, &rcButton);
  674. MoveWindow(m_hwndDisplayButton, rc.right - RECT_WIDTH(rcButton), rc.top, RECT_WIDTH(rcButton),
  675. RECT_HEIGHT(rcButton), TRUE);
  676. }
  677. // This function has the lookup code, so we want it as fast as possible
  678. #ifndef _DEBUG
  679. #pragma optimize("Ot", on)
  680. #endif
  681. LRESULT CIndex::OnCommand(HWND hwnd, UINT id, UINT uNotifiyCode, LPARAM /*lParam*/)
  682. {
  683. CStr cszKeyword;
  684. int pos;
  685. SITEMAP_ENTRY* pSiteMapEntry;
  686. int i;
  687. WCHAR wszKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
  688. CHAR szKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
  689. CWordWheel* pWordWheel = NULL;
  690. CExCollection* pTitleCollection = NULL;
  691. // Sometimes the lame main wndproc will route messages here that do not belong
  692. // to the index and thus this can result in a re-entrant call to our
  693. // binary word wheel (because the call may occur during initialization).
  694. //
  695. // Thus to work around this we need to detect when the call is bogus and skip
  696. // the message.
  697. //
  698. // We can tell if the window associated with this index has been created
  699. // by checking the m_bInit value, since it will always be set once the list box
  700. // is filled. If it is not set then bail out since these messages are not
  701. // for the index window.
  702. if( !m_bInit )
  703. return 0;
  704. if( m_fBinary )
  705. if (m_phh->m_phmData) {
  706. pTitleCollection = m_phh->m_phmData->m_pTitleCollection;
  707. pWordWheel = pTitleCollection->m_pDatabase->GetKeywordLinks();
  708. }
  709. switch (id) {
  710. case IDEDIT_INDEX:
  711. {
  712. if (uNotifiyCode != EN_CHANGE)
  713. return 0;
  714. if (m_fSelectionChange) {
  715. m_fSelectionChange = FALSE;
  716. return 0;
  717. }
  718. CStr cszKeyword(m_hwndEditBox);
  719. CWStr cwszKeyword(m_hwndEditBox);
  720. if (!*cszKeyword.psz)
  721. return 0;
  722. if (m_fBinary) {
  723. if (pWordWheel) {
  724. DWORD dwIndex = 0;
  725. if( m_bUnicode )
  726. dwIndex = pWordWheel->GetIndex(cwszKeyword.pw);
  727. else
  728. dwIndex = pWordWheel->GetIndex(cszKeyword.psz);
  729. if (dwIndex != HHWW_ERROR) {
  730. m_pVList->SetTopIndex(dwIndex);
  731. m_pVList->SetSelection(dwIndex, FALSE);
  732. }
  733. }
  734. }
  735. else {
  736. /*
  737. * REVIEW: This could be sped up by having a first character
  738. * lookup, ala the RTF tokens in lex.cpp (hcrtf). Putting this
  739. * in the thread would also improve user responsiveness.
  740. */
  741. for (i = 1; i <= CountStrings(); i++) {
  742. pSiteMapEntry = GetSiteMapEntry(i);
  743. ASSERT_COMMENT(pSiteMapEntry->GetKeyword(), "Index entry added without a keyword");
  744. /*
  745. * Unless the user specifically requested it, we
  746. * don't allow the keyboard to be used to get to
  747. * anything other then first level entries.
  748. */
  749. if (!g_fNonFirstKey && pSiteMapEntry->GetLevel() > 1)
  750. continue;
  751. BOOL bFound = FALSE;
  752. if( m_bUnicode ) {
  753. pSiteMapEntry->GetKeyword( wszKeyword, sizeof(wszKeyword)/2 );
  754. if( isSameString( wszKeyword, cwszKeyword) )
  755. bFound = TRUE;
  756. }
  757. else {
  758. // BUGBUG: isSameString is not lcid aware
  759. if( isSameString(pSiteMapEntry->GetKeyword(), cszKeyword) )
  760. bFound = TRUE;
  761. }
  762. if( bFound ) {
  763. m_pVList->SetTopIndex(i - 1);
  764. m_pVList->SetSelection(i - 1, FALSE);
  765. break;
  766. }
  767. }
  768. }
  769. }
  770. return 0;
  771. case IDBTN_DISPLAY:
  772. if (uNotifiyCode == BN_CLICKED) {
  773. pos = m_pVList->GetSelection();
  774. CStr cszKeyword(m_hwndEditBox);
  775. CWStr cwszKeyword(m_hwndEditBox);
  776. if (m_fBinary) {
  777. if (pWordWheel) {
  778. int iIndex = pos;
  779. if( m_bUnicode )
  780. pWordWheel->GetString(iIndex, wszKeyword, sizeof(wszKeyword)/2);
  781. else
  782. pWordWheel->GetString(iIndex, szKeyword, sizeof(szKeyword));
  783. }
  784. }
  785. else {
  786. pSiteMapEntry = GetSiteMapEntry(pos + 1);
  787. if (!pSiteMapEntry)
  788. break; // happens with an empty index
  789. }
  790. if (m_fBinary) {
  791. if (pWordWheel) {
  792. int iIndex = pos;
  793. if( pWordWheel->IsPlaceHolder(iIndex) ) {
  794. MsgBox(IDS_HH_E_KEYWORD_IS_PLACEHOLDER, MB_OK | MB_ICONWARNING);
  795. return 0;
  796. }
  797. if( m_bUnicode ) {
  798. if( pWordWheel->GetSeeAlso(iIndex, wszKeyword, sizeof(wszKeyword)/2) ) {
  799. Seed(wszKeyword);
  800. return 0;
  801. }
  802. }
  803. else {
  804. if( pWordWheel->GetSeeAlso(iIndex, szKeyword, sizeof(szKeyword)/2) ) {
  805. Seed(szKeyword);
  806. return 0;
  807. }
  808. }
  809. }
  810. }
  811. else {
  812. if (pSiteMapEntry->fSeeAlso) {
  813. /*
  814. * A See Also entry simply jumps to another location
  815. * in the Index.
  816. */
  817. Seed(GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
  818. return 0;
  819. }
  820. }
  821. // If we have one or more titles, then give the user
  822. // a choice of what to jump to.
  823. if (m_fBinary) {
  824. if( pWordWheel ) {
  825. DWORD dwIndex = pos;
  826. DWORD dwHitCount = pWordWheel->GetHitCount(dwIndex);
  827. UINT CodePage = pTitleCollection->GetMasterTitle()->GetInfo()->GetCodePage();
  828. CWTable tblTitles( CodePage );
  829. CTable tblURLs;
  830. CWTable tblLocations( CodePage );
  831. BOOL bExcludedBySubset = FALSE;
  832. BOOL bExcludedByInfoType = FALSE;
  833. if (dwHitCount != HHWW_ERROR) {
  834. for (DWORD i = 0; i < dwHitCount; i++) {
  835. CExTitle* pTitle = NULL;
  836. DWORD dwURLId = pWordWheel->GetHit(dwIndex, i, &pTitle);
  837. if (pTitle && dwURLId != HHWW_ERROR) {
  838. #if 0 // infotypes not supported
  839. CSubSet* pSS;
  840. const unsigned int *pdwITBits;
  841. // Filter it?
  842. if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSubSets &&
  843. (pSS = pTitle->m_pCollection->m_pSubSets->GetIndexSubset()) &&
  844. !pSS->m_bIsEntireCollection ) {
  845. pdwITBits = pTitle->GetTopicITBits(dwURLId);
  846. if( !pTitle->m_pCollection->m_pSubSets->fIndexFilter(pdwITBits) ) {
  847. bExcludedByInfoType = TRUE;
  848. continue;
  849. }
  850. }
  851. #endif
  852. // Structural subset filter ?
  853. //
  854. CStructuralSubset* pSubset;
  855. if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList &&
  856. (pSubset = pTitle->m_pCollection->m_pSSList->GetF1()) && !pSubset->IsEntire() )
  857. {
  858. // Yes, filter using the current structural subset for F1.
  859. //
  860. if (! pSubset->IsTitleInSubset(pTitle) ) {
  861. bExcludedBySubset = TRUE;
  862. continue;
  863. }
  864. }
  865. char szTitle[1024];
  866. szTitle[0] = 0;
  867. pTitle->GetTopicName( dwURLId, szTitle, sizeof(szTitle) );
  868. if( !szTitle[0] )
  869. strcpy( szTitle, GetStringResource( IDS_UNTITLED ) );
  870. char szLocation[INTERNET_MAX_PATH_LENGTH];
  871. szLocation[0] = 0;
  872. if( pTitle->GetTopicLocation(dwURLId, szLocation, INTERNET_MAX_PATH_LENGTH) != S_OK )
  873. strcpy( szLocation, GetStringResource( IDS_UNKNOWN ) );
  874. char szURL[INTERNET_MAX_URL_LENGTH];
  875. szURL[0] = 0;
  876. pTitle->GetTopicURL( dwURLId, szURL, sizeof(szURL) );
  877. if( szURL[0] )
  878. {
  879. if( !tblURLs.IsStringInTable(szURL) )
  880. {
  881. int iIndex = tblURLs.AddString(szURL);
  882. tblTitles.AddIntAndString(iIndex, szTitle[0]?szTitle:"");
  883. tblLocations.AddString( *szLocation?szLocation:"" );
  884. }
  885. }
  886. }
  887. }
  888. }
  889. // if we get no topics then display a message stating so
  890. if (tblURLs.CountStrings() < 1) {
  891. int iStr = 0;
  892. if( bExcludedBySubset && bExcludedByInfoType )
  893. iStr = IDS_HH_E_KEYWORD_EXCLUDED;
  894. else if( bExcludedBySubset )
  895. iStr = IDS_HH_E_KEYWORD_NOT_IN_SUBSET;
  896. else if( bExcludedByInfoType )
  897. iStr = IDS_HH_E_KEYWORD_NOT_IN_INFOTYPE;
  898. else
  899. iStr = IDS_HH_E_KEYWORD_NOT_FOUND;
  900. MsgBox( iStr, MB_OK | MB_ICONWARNING );
  901. return 0;
  902. }
  903. // if only one topic then jump to it
  904. if( tblURLs.CountStrings() == 1 ) {
  905. char szURL[INTERNET_MAX_URL_LENGTH];
  906. tblURLs.GetString( szURL, 1 );
  907. ChangeHtmlTopic( szURL, hwnd );
  908. return 0;
  909. }
  910. // we can sort the title table since it contains the index value
  911. // of the associated URL so just make sure to always fetch the
  912. // URL index from the selected title string and use that to get the URL
  913. if( /*bAlphaSortHits*/ TRUE ) {
  914. tblTitles.SetSorting(GetSystemDefaultLCID());
  915. tblTitles.SortTable(sizeof(HASH));
  916. }
  917. HWND hWnd = GetFocus();
  918. CTopicList TopicList(hWnd, &tblTitles, GetContentFont(), &tblLocations);
  919. if (TopicList.DoModal()) {
  920. char szURL[INTERNET_MAX_URL_LENGTH];
  921. int iIndex = tblTitles.GetInt(TopicList.m_pos);
  922. tblURLs.GetString( szURL, iIndex );
  923. ChangeHtmlTopic( szURL, hwnd );
  924. }
  925. SetFocus(hWnd);
  926. }
  927. }
  928. else {
  929. UINT CodePage = pSiteMapEntry->pSiteMap->GetCodePage();
  930. CWTable tblTitles( CodePage );
  931. if (pSiteMapEntry->cUrls > 1)
  932. {
  933. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  934. for (int i = 0; i < pSiteMapEntry->cUrls; i++)
  935. {
  936. strcpy(szURL, GetUrlTitle(pSiteMapEntry, i) );
  937. tblTitles.AddIntAndString(i, szURL);
  938. }
  939. // we can sort the title table since it contains the index value
  940. // of the associated URL so just make sure to always fetch the
  941. // URL index from the selected title string and use that to get the URL
  942. if( /*bAlphaSortHits*/ TRUE ) {
  943. tblTitles.SetSorting(GetSystemDefaultLCID());
  944. tblTitles.SortTable(sizeof(HASH));
  945. }
  946. // CTopicList TopicList(m_phhctrl ? m_phhctrl->m_hwnd : FindMessageParent(m_hwndEditBox),
  947. // &tblTitles, GetContentFont());
  948. CTopicList* pTopicList;
  949. if ( m_phhctrl )
  950. pTopicList = new CTopicList(m_phhctrl, &tblTitles, GetContentFont());
  951. else
  952. pTopicList = new CTopicList(FindMessageParent(m_hwndEditBox), &tblTitles, GetContentFont());
  953. if (m_phhctrl)
  954. m_phhctrl->ModalDialog(TRUE);
  955. int fResult = pTopicList->DoModal();
  956. if (m_phhctrl)
  957. m_phhctrl->ModalDialog(FALSE);
  958. if (fResult)
  959. {
  960. int iIndex = tblTitles.GetInt( pTopicList->m_pos );
  961. SITE_ENTRY_URL* pUrl = GetUrlEntry(pSiteMapEntry, iIndex);
  962. JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, pInfoType, this, pUrl);
  963. }
  964. SetFocus(m_hwndEditBox);
  965. delete pTopicList;
  966. return 0;
  967. }
  968. JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, pInfoType, this, NULL);
  969. SetFocus(m_hwndEditBox);
  970. }
  971. }
  972. return 0;
  973. case ID_VIEW_ENTRY:
  974. {
  975. pos = m_pVList->GetSelection();
  976. pSiteMapEntry = GetSiteMapEntry(pos + 1);
  977. if(pSiteMapEntry)
  978. DisplayAuthorInfo(pInfoType, this, pSiteMapEntry, FindMessageParent(m_hwndListBox), m_phhctrl);
  979. }
  980. return 0;
  981. #ifdef _DEBUG
  982. case ID_VIEW_MEMORY:
  983. OnReportMemoryUsage();
  984. return 0;
  985. #endif
  986. }
  987. return 0;
  988. }
  989. #ifndef _DEBUG
  990. #pragma optimize("", on)
  991. #endif
  992. LRESULT WINAPI EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  993. {
  994. switch (msg) {
  995. case WM_CHAR: //Process this message to avoid damn beeps.
  996. if ((wParam == VK_RETURN) || (wParam == VK_TAB))
  997. return 0;
  998. return W_DelegateWindowProc(lpfnlEditWndProc, hwnd, msg, wParam,lParam);
  999. case WM_KEYDOWN:
  1000. switch (wParam)
  1001. {
  1002. case VK_RETURN:
  1003. SendMessage(FindMessageParent(hwnd), WM_COMMAND, MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
  1004. return 0;
  1005. case VK_TAB:
  1006. if (GetKeyState(VK_SHIFT) < 0)
  1007. {
  1008. SetFocus(GetDlgItem(GetParent(hwnd), IDBTN_DISPLAY));
  1009. return 0;
  1010. }
  1011. SetFocus(GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST));
  1012. return 0;
  1013. }
  1014. // fall through
  1015. case WM_KEYUP:
  1016. if ( VK_UP == wParam ||
  1017. VK_DOWN == wParam ||
  1018. VK_PRIOR == wParam ||
  1019. VK_NEXT == wParam )
  1020. {
  1021. #ifdef _DEBUG
  1022. HWND hwndListBox = GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST);
  1023. ASSERT(hwndListBox);
  1024. #endif
  1025. SendMessage(GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST), msg, wParam, lParam);
  1026. // Move caret to the end of the edit control
  1027. PostMessage(hwnd, msg, VK_END, lParam);
  1028. return 0;
  1029. }
  1030. // fall through
  1031. default:
  1032. return W_DelegateWindowProc(lpfnlEditWndProc, hwnd, msg, wParam, lParam);
  1033. }
  1034. }
  1035. static LRESULT WINAPI ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1036. {
  1037. switch(msg) {
  1038. case WM_KEYDOWN:
  1039. // REVIEW: 17-Oct-1997 [ralphw] Why are we special-casing VK_RETURN?
  1040. // lpfnlBtnWndProc should handle this automatically
  1041. if (wParam == VK_RETURN) {
  1042. SendMessage(FindMessageParent(hwnd), WM_COMMAND,MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
  1043. return 0;
  1044. }
  1045. if (wParam == VK_TAB) {
  1046. CIndex* pThis = (CIndex*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1047. if (GetKeyState(VK_SHIFT) < 0) {
  1048. SetFocus(pThis->m_hwndListBox);
  1049. return 0;
  1050. }
  1051. SetFocus(GetDlgItem(GetParent(hwnd), IDEDIT_INDEX));
  1052. return 0;
  1053. // PostMessage(pThis->m_phh->GetHwnd(), WMP_HH_TAB_KEY, 0, 0);
  1054. }
  1055. break;
  1056. }
  1057. return W_DelegateWindowProc(lpfnlBtnWndProc, hwnd, msg, wParam, lParam);
  1058. }
  1059. /***************************************************************************
  1060. FUNCTION: StrToken
  1061. PURPOSE: DBCS-enabed variant of strtok
  1062. PARAMETERS:
  1063. pszList
  1064. chDelimiter
  1065. RETURNS:
  1066. COMMENTS:
  1067. You can NOT specify a DBCS character to look for, but you can
  1068. search a DBCS string for an ANSI character
  1069. MODIFICATION DATES:
  1070. 06-Jan-1996 [ralphw]
  1071. ***************************************************************************/
  1072. PSTR StrToken(PSTR pszList, PCSTR pszDelimeters)
  1073. {
  1074. static PSTR pszSavedList = NULL;
  1075. PSTR psz, pszTokens;
  1076. if (pszList) {
  1077. pszSavedList = pszList;
  1078. // On the first call, remove any leading token matches
  1079. for (psz = (PSTR) pszDelimeters; *psz; psz++) {
  1080. if (*psz == *pszSavedList) {
  1081. pszSavedList++;
  1082. psz = (PSTR) pszDelimeters - 1;
  1083. }
  1084. }
  1085. }
  1086. if (g_fDBCSSystem) {
  1087. psz = pszSavedList;
  1088. while (*psz) {
  1089. for (pszTokens = (PSTR) pszDelimeters; *pszTokens; pszTokens++) {
  1090. if (*pszTokens == *psz)
  1091. break;
  1092. }
  1093. if (*pszTokens == *psz)
  1094. break;
  1095. psz = CharNext(psz);
  1096. }
  1097. if (!*psz)
  1098. psz = NULL;
  1099. }
  1100. else {
  1101. psz = strpbrk(pszSavedList, pszDelimeters);
  1102. }
  1103. if (!psz) {
  1104. if (!*pszSavedList)
  1105. return NULL;
  1106. else {
  1107. PSTR pszReturn = pszSavedList;
  1108. pszSavedList = pszSavedList + strlen(pszSavedList);
  1109. return pszReturn;
  1110. }
  1111. }
  1112. *psz++ = '\0';
  1113. PSTR pszReturn = pszSavedList;
  1114. pszSavedList = psz;
  1115. return pszReturn;
  1116. }
  1117. ///////////////////////////////////////////////////////////
  1118. //
  1119. // INavUI as Implemented by CIndex
  1120. //
  1121. ///////////////////////////////////////////////////////////
  1122. //
  1123. // ProcessMenuChar
  1124. //
  1125. bool
  1126. CIndex::ProcessMenuChar(HWND hwndParent, int ch)
  1127. {
  1128. return ::ProcessMenuChar(this, hwndParent, m_aDlgItems, c_NumDlgItems, ch) ;
  1129. }
  1130. ///////////////////////////////////////////////////////////
  1131. //
  1132. // SetDefaultFocus
  1133. //
  1134. void
  1135. CIndex::SetDefaultFocus()
  1136. {
  1137. ASSERT(::IsValidWindow(m_hwndListBox));
  1138. if (SendMessage(m_hwndListBox, LB_GETCURSEL, 0, NULL) == LB_ERR)
  1139. {
  1140. SendMessage(m_hwndListBox, LB_SETCURSEL, 0,0);
  1141. }
  1142. SetFocus(m_hwndEditBox); // Set Focus to the Edit control
  1143. }
  1144. const int c_TopicColumn = 0;
  1145. const int c_LocationColumn = 1;
  1146. typedef struct tag_TOPICLISTSORTINFO
  1147. {
  1148. CTopicList* pThis; // The CTopicList object controlling the sort.
  1149. int iSubItem; // column we are sorting.
  1150. LCID lcid; // locale to sort by
  1151. WCHAR* pwszUntitled;
  1152. WCHAR* pwszUnknown;
  1153. } TOPICLISTSORTINFO;
  1154. ///////////////////////////////////////////////////////////
  1155. //
  1156. // TopicListCompareProc - Used to sort columns in the Topics List.
  1157. //
  1158. int CALLBACK TopicListCompareProc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
  1159. {
  1160. int iReturn = 0;
  1161. int iItem1 = (int)lParam1;
  1162. int iItem2 = (int)lParam2;
  1163. TOPICLISTSORTINFO* pInfo = reinterpret_cast<TOPICLISTSORTINFO*>(lParamSort);
  1164. CTopicList* pThis = pInfo->pThis;
  1165. switch( pInfo->iSubItem )
  1166. {
  1167. case c_TopicColumn: // Topic String
  1168. {
  1169. WCHAR wsz1[4096];
  1170. wsz1[0] = 0;
  1171. const WCHAR* pwsz1 = wsz1;
  1172. pThis->m_ptblTitles->GetHashStringW( iItem1, wsz1, 4096 );
  1173. if( !(*pwsz1) )
  1174. pwsz1 = pInfo->pwszUntitled;
  1175. WCHAR wsz2[4096];
  1176. wsz2[0] = 0;
  1177. const WCHAR* pwsz2 = wsz2;
  1178. pThis->m_ptblTitles->GetHashStringW( iItem2, wsz2, 4096 );
  1179. if( !(*pwsz2) )
  1180. pwsz2 = pInfo->pwszUntitled;
  1181. iReturn = W_CompareString( pInfo->lcid, 0, pwsz1, -1, pwsz2, -1 ) - 2;
  1182. }
  1183. break;
  1184. case c_LocationColumn: // Location String
  1185. {
  1186. WCHAR wsz1[4096];
  1187. wsz1[0] = 0;
  1188. const WCHAR* pwsz1 = wsz1;
  1189. pThis->m_ptblLocations->GetStringW( pThis->m_ptblTitles->GetInt(iItem1), wsz1, 4096 );
  1190. if( !(*pwsz1) )
  1191. pwsz1 = pInfo->pwszUnknown;
  1192. WCHAR wsz2[4096];
  1193. wsz2[0] = 0;
  1194. const WCHAR* pwsz2 = wsz2;
  1195. pThis->m_ptblLocations->GetStringW( pThis->m_ptblTitles->GetInt(iItem2), wsz2, 4096 );
  1196. if( !(*pwsz2) )
  1197. pwsz2 = pInfo->pwszUnknown;
  1198. iReturn = W_CompareString( pInfo->lcid, 0, pwsz1, -1, pwsz2, -1 ) - 2;
  1199. }
  1200. break;
  1201. default:
  1202. ASSERT(0);
  1203. break;
  1204. }
  1205. return iReturn;
  1206. }
  1207. extern BOOL WINAPI EnumListViewFont(HWND hwnd, LPARAM lval);
  1208. BOOL CTopicList::OnBeginOrEnd(void)
  1209. {
  1210. if (m_fInitializing)
  1211. {
  1212. m_fInitializing = FALSE;
  1213. #if 0
  1214. // note, we assume that some other part of HH detects that we either do or do
  1215. // not have ListView Unicode support and properly sets this bool
  1216. extern BOOL g_fUnicodeListView;
  1217. // if we can use a Unicode version of the control then all is well
  1218. // otherwise we need to use List1 as a template to create a Unicode
  1219. // version of the list view and hide the old ANSI version --
  1220. // we only need to do this for Windows 95/98 since Windows NT works
  1221. // just fine with Unicode
  1222. //
  1223. if( g_fSysWinNT || g_fUnicodeListView ) {
  1224. m_hwndListView = ::GetDlgItem(m_hWnd, IDC_TOPICS);
  1225. }
  1226. else { // Windows 95/98 w/o the new ComCtl32
  1227. HWND hWndList = ::GetDlgItem(m_hWnd, IDC_TOPICS);
  1228. ::ShowWindow( hWndList, SW_HIDE );
  1229. RECT ListRect = { 0,0,0,0 };
  1230. ::MapDialogRect( m_hWnd, &ListRect );
  1231. DWORD dwStyles = ::GetWindowLong( hWndList, GWL_STYLE );
  1232. // get the size of the control from List1
  1233. RECT rect;
  1234. ::GetWindowRect( hWndList, &rect );
  1235. POINT pt;
  1236. pt.x = rect.left;
  1237. pt.y = rect.top;
  1238. ::ScreenToClient( m_hWnd, &pt );
  1239. ListRect.top = pt.y;
  1240. ListRect.bottom = ListRect.top + (rect.bottom - rect.top);
  1241. ListRect.left = pt.x;
  1242. ListRect.right = ListRect.left + (rect.right - rect.left);
  1243. m_hwndListView = W_CreateControlWindow(
  1244. g_RTL_Style | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
  1245. dwStyles | WS_CHILD | WS_VISIBLE,
  1246. W_ListView, L"List0",
  1247. ListRect.left, ListRect.top, RECT_WIDTH(ListRect), RECT_HEIGHT(ListRect),
  1248. m_hWnd, NULL, _Module.GetModuleInstance(), NULL);
  1249. // force it to be the "active" window
  1250. m_fFocusChanged = TRUE;
  1251. ::SetFocus( m_hwndListView );
  1252. }
  1253. #else
  1254. m_hwndListView = ::GetDlgItem(m_hWnd, IDC_TOPICS);
  1255. #endif
  1256. W_EnableUnicode(m_hwndListView, W_ListView);
  1257. // ::SendMessage(m_hwndListView, WM_SETFONT, (WPARAM)_Resource.GetUIFont(), FALSE);
  1258. // Add Column Headings to the List View Control
  1259. LV_COLUMNW column;
  1260. column.mask = LVCF_FMT | LVCF_TEXT;
  1261. column.fmt = LVCFMT_LEFT ;
  1262. // Title Column
  1263. column.pszText = (LPWSTR)GetStringResourceW(IDS_ADVSEARCH_HEADING_TITLE);
  1264. int iCol = c_TopicColumn ;
  1265. int iResult = W_ListView_InsertColumn(m_hwndListView, iCol++, &column);
  1266. ASSERT(iResult != -1) ;
  1267. // Location column
  1268. ::SendMessage(m_hwndListView, WM_SETFONT, (WPARAM)m_hfont, FALSE);
  1269. if ( m_ptblLocations != NULL )
  1270. {
  1271. column.pszText = (LPWSTR)GetStringResourceW(IDS_ADVSEARCH_HEADING_LOCATION);
  1272. ListView_SetExtendedListViewStyle( m_hwndListView, LVS_EX_FULLROWSELECT );
  1273. iResult = W_ListView_InsertColumn(m_hwndListView, iCol, &column);
  1274. }
  1275. ASSERT(iResult != -1) ;
  1276. if(g_fBiDi)
  1277. ::SetWindowLong(m_hwndListView, GWL_EXSTYLE, GetWindowLong(m_hwndListView, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING);
  1278. // Make sure the list header uses a normal font
  1279. EnumChildWindows(m_hwndListView, (WNDENUMPROC) EnumListViewFont, 0);
  1280. RECT rc;
  1281. int col1;
  1282. GetWindowRect(m_hwndListView, &rc);
  1283. int nScrollBarWidth = GetSystemMetrics(SM_CXVSCROLL);
  1284. if ( m_ptblLocations == NULL )
  1285. col1 = RECT_WIDTH(rc)-nScrollBarWidth;
  1286. else
  1287. col1 = (RECT_WIDTH(rc)/2)-nScrollBarWidth;
  1288. W_ListView_SetColumnWidth(m_hwndListView, c_TopicColumn, col1 );
  1289. if ( m_ptblLocations != NULL )
  1290. W_ListView_SetColumnWidth(m_hwndListView, c_LocationColumn, RECT_WIDTH(rc)-col1-nScrollBarWidth/*LVSCW_AUTOSIZE_USEHEADER*/ );
  1291. AddItems();
  1292. }
  1293. else
  1294. {
  1295. if (m_pos <= 0 ) // nothing to do on end.
  1296. m_pos = 1;
  1297. }
  1298. return TRUE;
  1299. }
  1300. void CTopicList::AddItems()
  1301. {
  1302. ASSERT(m_cResultCount>0);
  1303. LV_ITEMW item; // To add to the list view.
  1304. ListView_DeleteAllItems(m_hwndListView);
  1305. ListView_SetItemCount( m_hwndListView, m_cResultCount );
  1306. WCHAR wsz[1024];
  1307. for ( int i=0; i< m_cResultCount; i++)
  1308. {
  1309. // need to get the topic string from the Topic Number
  1310. // Add the Topic string to the List View.
  1311. //
  1312. WCHAR wsz[4096];
  1313. WCHAR* pwsz = wsz;
  1314. m_ptblTitles->GetHashStringW(i+1, wsz, 4096);
  1315. item.pszText = wsz;
  1316. item.mask = LVIF_TEXT|LVIF_PARAM;
  1317. item.iImage = 0;
  1318. item.state = 0;
  1319. item.stateMask = 0;
  1320. item.iItem = i;
  1321. item.iSubItem = c_TopicColumn;
  1322. item.lParam = i+1;
  1323. W_ListView_InsertItem( m_hwndListView, &item );
  1324. }
  1325. // Add Location Column (do this after the inserts since the list could be sorted)
  1326. if( m_ptblLocations ) {
  1327. for ( int i=0; i< m_cResultCount; i++)
  1328. {
  1329. item.iItem = i;
  1330. item.iSubItem = c_TopicColumn;
  1331. item.mask = LVIF_PARAM;
  1332. W_ListView_GetItem( m_hwndListView, &item );
  1333. m_ptblLocations->GetStringW( m_ptblTitles->GetInt((int)item.lParam), wsz, 1024 );
  1334. item.pszText = wsz;
  1335. W_ListView_SetItemText(m_hwndListView, i, c_LocationColumn, wsz);
  1336. }
  1337. }
  1338. W_ListView_SetItemState( m_hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED , LVIF_STATE | LVIS_SELECTED | LVIS_FOCUSED);
  1339. m_pos = 1;
  1340. }
  1341. LRESULT CTopicList::OnDlgMsg(UINT msg, WPARAM wParam, LPARAM lParam)
  1342. {
  1343. if ( msg == WM_NOTIFY )
  1344. {
  1345. if ( ListViewMsg( GetParent(*this), (NM_LISTVIEW*)lParam) )
  1346. // EndDialog(TRUE);
  1347. ::SendMessage(m_hWnd, WM_COMMAND, (WPARAM)1, (LPARAM)0); // WPARAM == ((BN_CLICKED<16)|IDOK)
  1348. }
  1349. return FALSE;
  1350. }
  1351. LRESULT CTopicList::ListViewMsg(HWND hwnd, NM_LISTVIEW* lParam)
  1352. {
  1353. switch(lParam->hdr.code)
  1354. {
  1355. case NM_DBLCLK:
  1356. case NM_RETURN:
  1357. if ( m_pos == -1 )
  1358. return FALSE;
  1359. else
  1360. return TRUE;
  1361. case LVN_ITEMCHANGING:
  1362. if ( ((NM_LISTVIEW*)lParam)->uNewState & LVIS_SELECTED )
  1363. m_pos = (int)((NM_LISTVIEW*)lParam)->lParam;
  1364. else
  1365. m_pos = -1 ;
  1366. break;
  1367. case LVN_GETDISPINFOA: // the control wants to draw the items
  1368. case LVN_GETDISPINFOW: // the control wants to draw the items
  1369. break;
  1370. case LVN_COLUMNCLICK: {
  1371. CHourGlass waitcur;
  1372. NM_LISTVIEW *pNM = reinterpret_cast<NM_LISTVIEW*>(lParam);
  1373. // Get the string for untitled things.
  1374. CWStr wstrUntitled(IDS_UNTITLED);
  1375. CWStr wstrUnknown(IDS_UNKNOWN);
  1376. // Fill this structure to make the sorting quicker/more efficient.
  1377. TOPICLISTSORTINFO Info;
  1378. Info.pThis = this;
  1379. Info.iSubItem = pNM->iSubItem;
  1380. LCID lcid = 0;
  1381. LCIDFromCodePage( m_ptblTitles->GetCodePage(), &lcid );
  1382. Info.lcid = lcid;
  1383. Info.pwszUntitled = wstrUntitled;
  1384. Info.pwszUnknown = wstrUnknown;
  1385. W_ListView_SortItems(pNM->hdr.hwndFrom,
  1386. TopicListCompareProc,
  1387. reinterpret_cast<LPARAM>(&Info));
  1388. }
  1389. // Fall through...
  1390. default:
  1391. ;
  1392. }
  1393. return 0;
  1394. }