1632 lines
56 KiB
C++
1632 lines
56 KiB
C++
// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
|
|
|
|
#include "header.h"
|
|
#include "hha_strtable.h"
|
|
#include "strtable.h"
|
|
#include "hhctrl.h"
|
|
#include "resource.h"
|
|
#include "index.h"
|
|
#include "htmlhelp.h"
|
|
#include "cpaldc.h"
|
|
#include "secwin.h"
|
|
#include "wwheel.h"
|
|
#include "onclick.h"
|
|
#include <wininet.h>
|
|
#include "secwin.h"
|
|
#include "contain.h"
|
|
#include "subset.h"
|
|
#include "cctlww.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static const char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
AUTO_CLASS_COUNT_CHECK( CIndex );
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Constants
|
|
//
|
|
#define BOX_HEIGHT 24
|
|
#define ODA_CLEAR 0x0008
|
|
const int c_StaticControlSpacing = 3; // Space between text and static control.
|
|
const int c_ControlSpacing = 8 ; // Space between two controls.
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Window Proc Prototypes.
|
|
//
|
|
LRESULT WINAPI EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
WNDPROC lpfnlEditWndProc = NULL;
|
|
static LRESULT WINAPI ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
WNDPROC lpfnlBtnWndProc = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Constructor
|
|
//
|
|
CIndex::CIndex(CHtmlHelpControl* phhctrl, IUnknown* pUnkOuter, CHHWinType* phh)
|
|
: m_hwndResizeToParent(NULL)
|
|
{
|
|
m_phhctrl = phhctrl;
|
|
m_pOuter = pUnkOuter;
|
|
m_phh = phh;
|
|
|
|
m_hwndEditBox = NULL;
|
|
m_hwndStaticKeyword = NULL ;
|
|
|
|
m_hwndListBox = NULL;
|
|
m_hwndDisplayButton = NULL;
|
|
m_fSelectionChange = FALSE;
|
|
m_padding = 0; // padding to put around the Index
|
|
if (phh)
|
|
m_NavTabPos = phh->tabpos ;
|
|
else
|
|
m_NavTabPos = HHWIN_NAVTAB_TOP ;
|
|
|
|
m_cFonts = 0;
|
|
m_ahfonts = NULL;
|
|
m_fGlobal = FALSE;
|
|
m_hbmpBackGround = NULL;
|
|
m_hbrBackGround = NULL;
|
|
m_langid = PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID()));
|
|
m_fBinary = FALSE; // default to FALSE until we find out which index we are reading
|
|
pInfoType = NULL;
|
|
m_bInit = FALSE;
|
|
m_pVList = NULL;
|
|
m_bUnicode = FALSE;
|
|
}
|
|
|
|
CIndex::~CIndex()
|
|
{
|
|
DESTROYIFVALID(m_hwndListBox);
|
|
DESTROYIFVALID(m_hwndDisplayButton);
|
|
DESTROYIFVALID(m_hwndEditBox);
|
|
DESTROYIFVALID(m_hwndStaticKeyword);
|
|
|
|
if (m_cFonts) {
|
|
for (int i = 0; i < m_cFonts; i++)
|
|
DeleteObject(m_ahfonts[i]);
|
|
lcFree(m_ahfonts);
|
|
}
|
|
|
|
if( m_pVList )
|
|
delete m_pVList;
|
|
}
|
|
|
|
void CIndex::HideWindow(void)
|
|
{
|
|
::ShowWindow(m_hwndEditBox, SW_HIDE);
|
|
::ShowWindow(m_hwndListBox, SW_HIDE);
|
|
::ShowWindow(m_hwndDisplayButton, SW_HIDE);
|
|
::ShowWindow(m_hwndStaticKeyword, SW_HIDE);
|
|
}
|
|
|
|
void CIndex::ShowWindow(void)
|
|
{
|
|
::ShowWindow(m_hwndEditBox, SW_SHOW);
|
|
::ShowWindow(m_hwndListBox, SW_SHOW);
|
|
::ShowWindow(m_hwndDisplayButton, SW_SHOW);
|
|
::ShowWindow(m_hwndStaticKeyword, SW_SHOW);
|
|
|
|
HWND hWnd;
|
|
char szClassName[MAX_PATH];
|
|
|
|
if ( (hWnd = GetParent(m_hwndEditBox)) )
|
|
{
|
|
GetClassName(hWnd, szClassName, sizeof(szClassName));
|
|
if (! lstrcmpi(szClassName, "HHCtrlWndClass") )
|
|
{
|
|
// Ok, we're up as an axtive x control.
|
|
//
|
|
COleControl* pCtl;
|
|
if ( (pCtl = (COleControl*)GetWindowLongPtr(hWnd, GWLP_USERDATA)) )
|
|
{
|
|
pCtl->InPlaceActivate(OLEIVERB_UIACTIVATE);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
SetFocus(m_hwndEditBox);
|
|
}
|
|
|
|
// Can't inline this because of dereferencing m_phh
|
|
//
|
|
//
|
|
HFONT CIndex::GetContentFont()
|
|
{
|
|
if ( m_cFonts && m_ahfonts[m_cFonts - 1] )
|
|
return m_ahfonts[m_cFonts - 1];
|
|
else
|
|
{
|
|
if ( m_phh )
|
|
return m_phh->GetContentFont();
|
|
else
|
|
{
|
|
if ( m_phhctrl && m_phhctrl->GetContentFont() )
|
|
return m_phhctrl->GetContentFont();
|
|
else
|
|
{
|
|
// this is likely the case where the control is being instantiated via object script on an html page. We
|
|
// won't have a phh. Correct thing to do would be to ask IE about content language? Maybe look in the
|
|
// sitemap? For now we'll use the UI font.
|
|
//
|
|
return _Resource.GetUIFont();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CIndex::InitDlgItemArray()
|
|
{
|
|
// Currently we are only using the m_accel member.
|
|
//--- Setup the dlg array for each control.
|
|
|
|
//--- Keyword edit control
|
|
int i = c_KeywordEdit;
|
|
m_aDlgItems[i].m_hWnd = m_hwndEditBox ; //::GetDlgItem(m_hWnd, IDEDIT_INDEX) ;
|
|
//::GetWindowRect(m_aDlgItems[i].m_hWnd, &rectCurrent) ; // Get screen coordinates.
|
|
//ScreenRectToClientRect(m_hWnd, &rectCurrent); // Convert to client
|
|
|
|
m_aDlgItems[i].m_id = IDEDIT_INDEX;
|
|
m_aDlgItems[i].m_accelkey = (CHAR)GetAcceleratorKey(m_hwndStaticKeyword); // No accelerator.
|
|
|
|
m_aDlgItems[i].m_Type = ItemInfo::Generic;
|
|
|
|
/* TODO: Finish using this
|
|
m_aDlgItems[i].m_bIgnoreEnabled = TRUE ;
|
|
//m_aDlgItems[i].m_bEnabled; // Is the control enabled?
|
|
m_aDlgItems[i].m_bIgnoreMax = TRUE ; // Ignore the Max parameter.
|
|
m_aDlgItems[i].m_bGrowH = TRUE; // Grow Horizontally.
|
|
m_aDlgItems[i].m_bGrowV = TRUE ; // Grow Vertically.
|
|
|
|
m_aDlgItems[i].m_JustifyV = Justify::Top; // Do we stick to the top or the bottom.
|
|
//m_aDlgItems[i].m_iOffsetV = ; // Distance from our justification point.
|
|
m_aDlgItems[i].m_JustifyH = Justify::Left; // Do we stick to the right or the left
|
|
//m_aDlgItems[i].m_iOffsetH = rectDlg.right - rectCurrent.left;
|
|
m_aDlgItems[i].m_iPadH = rectDlg.right - rectCurrent.right; // Maintain same distance. If someone to the right grows we are broken.
|
|
m_aDlgItems[i].m_iPadV = rectDlg.bottom - rectCurrent.bottom;
|
|
|
|
m_aDlgItems[i].m_rectMin = rectCurrent;
|
|
m_aDlgItems[i].m_rectCur = rectCurrent;
|
|
//m_aDlgItems[i].m_rectMax ; // Max size.
|
|
*/
|
|
|
|
//--- Display btn
|
|
i = c_DisplayBtn;
|
|
m_aDlgItems[i].m_hWnd = m_hwndDisplayButton; //::GetDlgItem(m_hWnd, IDBTN_DISPLAY) ;
|
|
//::GetWindowRect(m_aDlgItems[i].m_hWnd, &rectCurrent) ; // Get screen coordinates.
|
|
//ScreenRectToClientRect(m_hWnd, &rectCurrent); // Convert to client
|
|
|
|
m_aDlgItems[i].m_id = IDBTN_DISPLAY;
|
|
m_aDlgItems[i].m_accelkey = (CHAR)GetAcceleratorKey(m_aDlgItems[i].m_hWnd);
|
|
|
|
m_aDlgItems[i].m_Type = ItemInfo::Button;
|
|
|
|
/* TODO: Finish using this
|
|
m_aDlgItems[i].m_bIgnoreEnabled = TRUE ;
|
|
//m_aDlgItems[i].m_bEnabled; // Is the control enabled?
|
|
m_aDlgItems[i].m_bIgnoreMax = TRUE ; // Ignore the Max parameter.
|
|
m_aDlgItems[i].m_bGrowH = TRUE; // Grow Horizontally.
|
|
m_aDlgItems[i].m_bGrowV = TRUE ; // Grow Vertically.
|
|
|
|
m_aDlgItems[i].m_JustifyV = Justify::Top; // Do we stick to the top or the bottom.
|
|
//m_aDlgItems[i].m_iOffsetV = ; // Distance from our justification point.
|
|
m_aDlgItems[i].m_JustifyH = Justify::Left; // Do we stick to the right or the left
|
|
//m_aDlgItems[i].m_iOffsetH = rectDlg.right - rectCurrent.left;
|
|
m_aDlgItems[i].m_iPadH = rectDlg.right - rectCurrent.right; // Maintain same distance. If someone to the right grows we are broken.
|
|
m_aDlgItems[i].m_iPadV = rectDlg.bottom - rectCurrent.bottom;
|
|
|
|
m_aDlgItems[i].m_rectMin = rectCurrent;
|
|
m_aDlgItems[i].m_rectCur = rectCurrent;
|
|
//m_aDlgItems[i].m_rectMax ; // Max size.
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
BOOL CIndex::Create(HWND hwndParent)
|
|
{
|
|
/* Note: hwndParent is either the Navigation Frame or its the tab ctrl.
|
|
This class does not parent to the tab ctrl, but to the navigation frame.
|
|
GetParentSize will always return the hwndNavigation, if hwndParent is the
|
|
tabctrl.
|
|
The reason that it doesn't parent to the tab ctrl is that the tab ctrl
|
|
steals commands. What should really have happened is that all of the windows
|
|
in this control should be contained in another window. However, its too late to
|
|
change this now.
|
|
*/
|
|
|
|
RECT rcParent, rcChild;
|
|
// Save the hwndParent for ResizeWindow.
|
|
m_hwndResizeToParent = hwndParent ;
|
|
|
|
// Note: GetParentSize will return hwndNavigation if hwndParent is the
|
|
// tab ctrl.
|
|
// ???BUG??? Is bypassing the tab ctrl in the parenting structure causing painting problems?
|
|
hwndParent = GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
|
|
rcParent.top += GetSystemMetrics(SM_CYSIZEFRAME)*2 ; //HACK: Fudge the top since we are not parented to the tabctrl.
|
|
|
|
CopyRect(&rcChild, &rcParent);
|
|
|
|
//--- Keyword Static Text Control
|
|
// Place the "Keyword" static text on top of the edit control
|
|
m_hwndStaticKeyword = W_CreateWindowEx(WS_EX_TRANSPARENT, L"STATIC", GetStringResourceW(IDS_TYPE_KEYWORD),
|
|
WS_CHILD , rcChild.left, rcChild.top,
|
|
RECT_WIDTH(rcChild), BOX_HEIGHT, hwndParent,
|
|
(HMENU) ID_STATIC_KEYWORDS, _Module.GetModuleInstance(), NULL, &m_bUnicode);
|
|
|
|
if (!m_hwndStaticKeyword)
|
|
{
|
|
return FALSE ;
|
|
}
|
|
|
|
// Get the dimensions of the text for sizing and spacing needs.
|
|
DWORD dwExt = GetStaticDimensions( m_hwndStaticKeyword, _Resource.GetUIFont(), GetStringResource(IDS_TYPE_KEYWORD), RECT_WIDTH(rcChild) );
|
|
rcChild.bottom = rcChild.top+HIWORD(dwExt) ;
|
|
MoveWindow(m_hwndStaticKeyword, rcChild.left, rcChild.top,
|
|
RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), FALSE );
|
|
|
|
//--- Edit Control
|
|
// Space out.
|
|
RECT rcEdit; // Save so that we can use rcChild for the display button.
|
|
CopyRect(&rcEdit, &rcChild) ;
|
|
rcEdit.top = rcChild.bottom + c_StaticControlSpacing; // Add space between static and control.
|
|
rcEdit.bottom = rcEdit.top + BOX_HEIGHT;
|
|
|
|
// Create edit control.
|
|
m_hwndEditBox = W_CreateWindowEx(WS_EX_CLIENTEDGE | g_RTL_Style, L"EDIT", L"",
|
|
WS_CHILD | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, rcEdit.left, rcEdit.top,
|
|
RECT_WIDTH(rcEdit), RECT_HEIGHT(rcEdit), hwndParent,
|
|
(HMENU) IDEDIT_INDEX, _Module.GetModuleInstance(), NULL, &m_bUnicode);
|
|
|
|
if (!m_hwndEditBox)
|
|
{
|
|
DestroyWindow(m_hwndStaticKeyword) ;
|
|
return FALSE;
|
|
}
|
|
// Sub-class the edit box
|
|
if (lpfnlEditWndProc == NULL)
|
|
lpfnlEditWndProc = W_GetWndProc(m_hwndEditBox, m_bUnicode);
|
|
W_SubClassWindow (m_hwndEditBox, (LONG_PTR) EditProc, m_bUnicode);
|
|
|
|
//--- Display Button.
|
|
// Align from the bottom.
|
|
RECT rcDisplayBtn ;
|
|
CopyRect(&rcDisplayBtn, &rcChild) ;
|
|
rcDisplayBtn.bottom = rcParent.bottom ; //Changed from +2.
|
|
rcDisplayBtn.top = rcParent.bottom - BOX_HEIGHT;
|
|
|
|
// Create
|
|
m_hwndDisplayButton = W_CreateWindow(L"button",
|
|
(LPCWSTR)GetStringResourceW(IDS_ENGLISH_DISPLAY),
|
|
WS_CHILD | WS_TABSTOP, rcDisplayBtn.left, rcDisplayBtn.top,
|
|
RECT_WIDTH(rcDisplayBtn), RECT_HEIGHT(rcDisplayBtn), hwndParent,
|
|
(HMENU) IDBTN_DISPLAY, _Module.GetModuleInstance(), NULL, &m_bUnicode);
|
|
|
|
if (!m_hwndDisplayButton) {
|
|
DestroyWindow(m_hwndEditBox);
|
|
DestroyWindow(m_hwndStaticKeyword) ;
|
|
return FALSE;
|
|
}
|
|
// Sub-class the "display" button ?
|
|
//
|
|
if ( m_phh )
|
|
{
|
|
if (lpfnlBtnWndProc == NULL)
|
|
lpfnlBtnWndProc = W_GetWndProc(m_hwndDisplayButton, m_bUnicode);
|
|
W_SubClassWindow(m_hwndDisplayButton, (LONG_PTR)ButtonProc, m_bUnicode);
|
|
SETTHIS(m_hwndDisplayButton);
|
|
}
|
|
|
|
//--- ListView.
|
|
// Space
|
|
rcChild.top = rcEdit.bottom + c_ControlSpacing ;
|
|
rcChild.bottom = rcDisplayBtn.top - c_ControlSpacing ;
|
|
|
|
m_pVList = new CVirtualListCtrl(
|
|
(m_phh && m_phh->m_phmData ? m_phh->m_phmData->m_sysflags.lcid : g_lcidSystem));
|
|
if (! (m_hwndListBox = m_pVList->CreateVlistbox(hwndParent, &rcChild)) )
|
|
{
|
|
DestroyWindow(m_hwndDisplayButton);
|
|
DestroyWindow(m_hwndEditBox);
|
|
DestroyWindow(m_hwndStaticKeyword) ;
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_pszFont) {
|
|
if (!m_fGlobal) {
|
|
m_cFonts++;
|
|
if (m_cFonts == 1)
|
|
m_ahfonts = (HFONT*) lcMalloc(m_cFonts * sizeof(HFONT));
|
|
else
|
|
m_ahfonts = (HFONT*) lcReAlloc(m_ahfonts, m_cFonts * sizeof(HFONT));
|
|
|
|
INT iCharset = -1;
|
|
if ( m_phh )
|
|
iCharset = m_phh->GetContentCharset();
|
|
else if ( m_phhctrl )
|
|
iCharset = m_phhctrl->GetCharset();
|
|
m_ahfonts[m_cFonts - 1] = CreateUserFont(m_pszFont, NULL, NULL, iCharset);
|
|
}
|
|
}
|
|
|
|
// Use a more readable font
|
|
|
|
if ( m_phh && !m_ahfonts )
|
|
SendMessage(m_hwndListBox, WM_SETFONT, (WPARAM) m_phh->GetAccessableContentFont(), FALSE);
|
|
else
|
|
SendMessage(m_hwndListBox, WM_SETFONT, (WPARAM) GetContentFont(), FALSE);
|
|
SendMessage(m_hwndEditBox, WM_SETFONT, (WPARAM) GetContentFont(), FALSE);
|
|
SendMessage(m_hwndDisplayButton, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
|
|
SendMessage(m_hwndStaticKeyword, WM_SETFONT, (WPARAM) _Resource.GetUIFont(), FALSE);
|
|
|
|
//BUGBUG: Doesn't resize any of the other controls.
|
|
dwExt = GetButtonDimensions(m_hwndDisplayButton, _Resource.GetUIFont(), GetStringResource(IDS_ENGLISH_DISPLAY));
|
|
MoveWindow(m_hwndDisplayButton, rcDisplayBtn.right - LOWORD(dwExt), rcDisplayBtn.top,
|
|
LOWORD(dwExt), HIWORD(dwExt), FALSE);
|
|
|
|
m_listbox.m_hWnd = m_hwndListBox;
|
|
FillListBox();
|
|
|
|
if (!m_fGlobal)
|
|
m_pVList->PaintParamsSetup(m_clrBackground, m_clrForeground, m_pszBackBitmap);
|
|
|
|
// Initialize the array containing the dialog information.
|
|
InitDlgItemArray() ;
|
|
|
|
ShowWindow();
|
|
|
|
return TRUE;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ResizeWindow
|
|
//
|
|
void CIndex::ResizeWindow()
|
|
{
|
|
ASSERT(::IsValidWindow(m_hwndEditBox)) ;
|
|
|
|
// Resize to fit the client area of the parent.
|
|
HWND hwndParent = m_hwndResizeToParent ;
|
|
ASSERT(::IsValidWindow(hwndParent)) ;
|
|
|
|
RECT rcParent, rcChild;
|
|
GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
|
|
rcParent.top += GetSystemMetrics(SM_CYSIZEFRAME)*2 ; //HACK: Fudge the top since we are not parented to the tabctrl.
|
|
|
|
CopyRect(&rcChild, &rcParent);
|
|
|
|
//--- Keyword Static Control
|
|
// Resize the Static above the combo control
|
|
RECT rcStatic ;
|
|
CopyRect(&rcStatic, &rcChild) ;
|
|
DWORD dwExt = GetStaticDimensions( m_hwndStaticKeyword, _Resource.GetUIFont(), GetStringResource(IDS_TYPE_KEYWORD), RECT_WIDTH(rcChild) );
|
|
rcStatic.bottom = rcChild.top+HIWORD(dwExt);
|
|
MoveWindow(m_hwndStaticKeyword, rcStatic.left, rcStatic.top,
|
|
RECT_WIDTH(rcStatic), RECT_HEIGHT(rcStatic), TRUE);
|
|
|
|
//--- Edit Control
|
|
RECT rcEdit ;
|
|
CopyRect(&rcEdit, &rcChild) ;
|
|
rcEdit.top = rcStatic.bottom + c_StaticControlSpacing; //space for the static
|
|
|
|
dwExt = GetStaticDimensions( m_hwndEditBox, GetContentFont(), "Test", RECT_WIDTH(rcEdit) );
|
|
rcEdit.bottom = rcEdit.top+HIWORD(dwExt) + GetSystemMetrics(SM_CYSIZEFRAME)*2 ;
|
|
MoveWindow(m_hwndEditBox, rcEdit.left, rcEdit.top, RECT_WIDTH(rcEdit), RECT_HEIGHT(rcEdit), TRUE);
|
|
|
|
//--- Display Button
|
|
RECT rcDisplayBtn;
|
|
CopyRect(&rcDisplayBtn, &rcChild) ;
|
|
dwExt = GetButtonDimensions(m_hwndDisplayButton, _Resource.GetUIFont(), GetStringResource(IDS_ENGLISH_DISPLAY));
|
|
rcDisplayBtn.bottom = rcParent.bottom ;
|
|
rcDisplayBtn.top = rcParent.bottom - HIWORD(dwExt);
|
|
MoveWindow(m_hwndDisplayButton, rcDisplayBtn.right - LOWORD(dwExt), rcDisplayBtn.top,
|
|
LOWORD(dwExt), HIWORD(dwExt), TRUE);
|
|
|
|
//--- List Control
|
|
rcChild.top = rcEdit.bottom + c_ControlSpacing;
|
|
rcChild.bottom = rcDisplayBtn.top - c_ControlSpacing;
|
|
MoveWindow(m_hwndListBox, rcChild.left,
|
|
rcChild.top, RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), TRUE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// SeedEditCtrl - Places text into the edit control
|
|
//
|
|
void CIndex::Seed(WCHAR* pwszSeed)
|
|
{
|
|
if (IsValidWindow(m_hwndEditBox))
|
|
{
|
|
if (pwszSeed == NULL)
|
|
pwszSeed = L"";
|
|
|
|
if ( GetVersion() < 0x80000000 ) // If NT...
|
|
SetWindowTextW(m_hwndEditBox, pwszSeed);
|
|
else
|
|
{
|
|
char szTmp[MAX_URL];
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pwszSeed, -1, szTmp, MAX_URL, 0, 0);
|
|
|
|
SetWindowText(m_hwndEditBox, szTmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Narrow seed function is a fallback only. Callers are advised to use the wide version.
|
|
//
|
|
void CIndex::Seed(LPCSTR pszSeed)
|
|
{
|
|
UINT uiCP;
|
|
WCHAR wszBuf[MAX_URL];
|
|
|
|
if ( GetVersion() < 0x80000000 ) // If NT i.e. UNICODE OS
|
|
{
|
|
if ( m_phh )
|
|
uiCP = m_phh->GetCodePage();
|
|
else if ( m_phhctrl )
|
|
uiCP = m_phhctrl->GetCodePage();
|
|
else
|
|
uiCP = CP_ACP;
|
|
|
|
MultiByteToWideChar(uiCP, 0, pszSeed, -1, wszBuf, MAX_URL);
|
|
Seed(wszBuf);
|
|
}
|
|
else
|
|
{
|
|
if (IsValidWindow(m_hwndEditBox))
|
|
{
|
|
if (pszSeed == NULL)
|
|
pszSeed = "";
|
|
SetWindowText(m_hwndEditBox, pszSeed);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CHtmlHelpControl::LoadIndexFile
|
|
|
|
PURPOSE:
|
|
|
|
PARAMETERS:
|
|
pszMasterFile
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
12-Jul-1997 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL CHtmlHelpControl::LoadIndexFile(PCSTR pszMasterFile)
|
|
{
|
|
TCHAR szPath[MAX_PATH+10];
|
|
if (!ConvertToCacheFile(pszMasterFile, szPath)) {
|
|
szPath[0] = '\0';
|
|
if (!IsCompiledHtmlFile(pszMasterFile) && m_pWebBrowserApp) {
|
|
CStr cszCurUrl;
|
|
m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
|
|
PSTR pszChmSep = strstr(cszCurUrl, txtDoubleColonSep);
|
|
if (pszChmSep) { // this is a compiled HTML file
|
|
strcpy(pszChmSep + 2, pszMasterFile);
|
|
strcpy(szPath, cszCurUrl);
|
|
}
|
|
}
|
|
if (!szPath[0]) {
|
|
CStr cszMsg(IDS_CANT_FIND_FILE, pszMasterFile);
|
|
MsgBox(cszMsg);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
m_pindex = new CIndex(this, m_pUnkOuter, NULL);
|
|
|
|
UINT CodePage = 0;
|
|
if( m_pindex && m_pindex->m_phh && m_pindex->m_phh->m_phmData ) {
|
|
CodePage = m_pindex->m_phh->m_phmData->GetInfo()->GetCodePage();
|
|
}
|
|
|
|
if (!m_pindex->ReadFromFile(szPath, TRUE, this, CodePage))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CIndex::ReadIndexFile( PCSTR pszFile )
|
|
{
|
|
UINT CodePage = 0;
|
|
if( m_phh && m_phh->m_phmData ) {
|
|
CodePage = m_phh->m_phmData->GetInfo()->GetCodePage();
|
|
}
|
|
|
|
// check for binary version of the keyword word wheel
|
|
if (m_phh->m_phmData) {
|
|
if (HashFromSz(FindFilePortion(pszFile)) != m_phh->m_phmData->m_hashBinaryIndexName) {
|
|
return ReadFromFile(pszFile, TRUE, NULL, CodePage);
|
|
}
|
|
|
|
CExTitle* pTitle;
|
|
CFileSystem* pFS;
|
|
CSubFileSystem* pSFS;
|
|
|
|
if ((pTitle = m_phh->m_phmData->m_pTitleCollection->GetFirstTitle())) {
|
|
pFS = pTitle->GetTitleIdxFileSystem();
|
|
pSFS = new CSubFileSystem(pFS);
|
|
if (SUCCEEDED(pSFS->OpenSub("$WWKeywordLinks\\Property")))
|
|
m_fBinary = TRUE;
|
|
delete pSFS;
|
|
}
|
|
}
|
|
if (m_fBinary)
|
|
return m_fBinary;
|
|
|
|
return ReadFromFile(pszFile, TRUE, NULL, CodePage);
|
|
}
|
|
|
|
void CIndex::FillListBox(BOOL fReset)
|
|
{
|
|
ASSERT(IsValidWindow(m_hwndListBox));
|
|
if (!IsValidWindow(m_hwndListBox))
|
|
return;
|
|
|
|
int iCount = 0;
|
|
if (m_fBinary) {
|
|
CWordWheel* pWordWheel;
|
|
if (m_phh->m_phmData)
|
|
pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
|
|
else
|
|
pWordWheel = NULL;
|
|
if (pWordWheel)
|
|
iCount = pWordWheel->GetCount();
|
|
|
|
#if 0 // subset test code
|
|
|
|
// now loop thru each item in the list and if they exist (in the subset),
|
|
// then add the wordwheel dword to the item data entry (entry map)
|
|
DWORD dwStart = GetTickCount();
|
|
int iCountSubset = 0;
|
|
|
|
DWORD* pdwSubsetArray = new DWORD[iCount];
|
|
CStructuralSubset* pSubset = NULL;
|
|
CExTitle* pTitle = NULL;
|
|
|
|
for( int iKeyword = 0; iKeyword < iCount; iKeyword++ ) {
|
|
BOOL bAddItem = FALSE;
|
|
|
|
// perf enhancement (cache all data for this keyword)
|
|
pWordWheel->GetIndexData( iKeyword, TRUE );
|
|
|
|
// if place holder add the item and continue
|
|
if( pWordWheel->IsPlaceHolder( iKeyword ) ) {
|
|
bAddItem = TRUE;
|
|
}
|
|
// scan the hits, if at least one is in the subset then add the item and continue
|
|
else {
|
|
DWORD dwHitCount = pWordWheel->GetHitCount( iKeyword );
|
|
for( DWORD i = 0; i < dwHitCount; i++ ) {
|
|
DWORD dwURLId = pWordWheel->GetHit( iKeyword, i, &pTitle);
|
|
if( !pSubset && pTitle->m_pCollection->m_pSSList ) {
|
|
pSubset = pTitle->m_pCollection->m_pSSList->GetF1();
|
|
if( !pSubset )
|
|
break;
|
|
}
|
|
if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList ) {
|
|
if( pSubset && pSubset->IsTitleInSubset(pTitle) ) {
|
|
bAddItem = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add the item if found
|
|
if( bAddItem ) {
|
|
pdwSubsetArray[iCountSubset] = iKeyword;
|
|
iCountSubset++;
|
|
}
|
|
|
|
}
|
|
DWORD dwEnd = GetTickCount();
|
|
char szTime[1024];
|
|
sprintf( szTime, "Subset Filtering took:\n%d seconds\n%d original items\n%d final items",
|
|
(dwEnd-dwStart)/1000, iCount, iCountSubset );
|
|
MsgBox( szTime, MB_OK );
|
|
|
|
delete [] pdwSubsetArray;
|
|
|
|
#endif // end of subset test code
|
|
|
|
}
|
|
else {
|
|
iCount = CountStrings();
|
|
}
|
|
m_pVList->SetItemCount(iCount);
|
|
m_bInit = TRUE;
|
|
}
|
|
|
|
void CIndex::OnVKListNotify(NMHDR* pNMHdr)
|
|
{
|
|
PVLC_ITEM pVlcItem = NULL;
|
|
int pos;
|
|
SITEMAP_ENTRY* pSiteMapEntry;
|
|
WCHAR wszKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
|
|
CWordWheel* pWordWheel = NULL;
|
|
|
|
switch(pNMHdr->code)
|
|
{
|
|
case NM_RDBLCLK:
|
|
break;
|
|
|
|
case NM_RCLICK:
|
|
break;
|
|
|
|
case NM_CLICK:
|
|
break;
|
|
|
|
case NM_KILLFOCUS:
|
|
break;
|
|
|
|
case NM_SETFOCUS:
|
|
break;
|
|
|
|
case VLN_TAB:
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
SetFocus(m_hwndEditBox);
|
|
else
|
|
SetFocus(m_hwndDisplayButton);
|
|
break;
|
|
|
|
case VLN_GETITEM:
|
|
pVlcItem = (PVLC_ITEM)pNMHdr;
|
|
if (m_fBinary)
|
|
{
|
|
CWordWheel* pWordWheel;
|
|
if (m_phh->m_phmData)
|
|
pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
|
|
else
|
|
pWordWheel = NULL;
|
|
if (pWordWheel) {
|
|
if (pWordWheel->GetString(pVlcItem->iItem, pVlcItem->lpwsz, pVlcItem->cchMax)) {
|
|
pVlcItem->iLevel = pWordWheel->GetLevel(pVlcItem->iItem) + 1;
|
|
BOOL bFound = FALSE;
|
|
CExTitle* pTitle = NULL;
|
|
WCHAR wszSeeAlso[1024];
|
|
if( pWordWheel->IsPlaceHolder(pVlcItem->iItem) )
|
|
bFound = TRUE;
|
|
else if( pWordWheel->GetSeeAlso(pVlcItem->iItem, wszSeeAlso, sizeof(wszSeeAlso) ) )
|
|
bFound = TRUE;
|
|
else {
|
|
DWORD dwHitCount = pWordWheel->GetHitCount(pVlcItem->iItem);
|
|
for (DWORD i = 0; i < dwHitCount; i++) {
|
|
DWORD dwURLId = pWordWheel->GetHit(pVlcItem->iItem, i, &pTitle);
|
|
|
|
// Structural subset filter ?
|
|
//
|
|
CStructuralSubset* pSubset;
|
|
if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList &&
|
|
(pSubset = pTitle->m_pCollection->m_pSSList->GetF1()) && !pSubset->IsEntire() )
|
|
{
|
|
// Yes, filter using the current structural subset for F1.
|
|
//
|
|
if (! pSubset->IsTitleInSubset(pTitle) ) {
|
|
continue;
|
|
}
|
|
}
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !bFound )
|
|
pVlcItem->dwFlags = 0x1;
|
|
else
|
|
pVlcItem->dwFlags = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// +1 because Ctable is 1-based
|
|
SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pVlcItem->iItem + 1);
|
|
if (pSiteMapEntry) {
|
|
pSiteMapEntry->GetKeyword(pVlcItem->lpwsz, pVlcItem->cchMax);
|
|
if(pVlcItem->cchMax)
|
|
pVlcItem->lpwsz[pVlcItem->cchMax-1] = 0; // null terminate the string
|
|
pVlcItem->iLevel = pSiteMapEntry->GetLevel();
|
|
pVlcItem->dwFlags = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VLN_SELECT:
|
|
if( m_fBinary )
|
|
{
|
|
if (m_phh->m_phmData)
|
|
pWordWheel = m_phh->m_phmData->m_pTitleCollection->m_pDatabase->GetKeywordLinks();
|
|
}
|
|
pos = m_pVList->GetSelection();
|
|
m_fSelectionChange = TRUE; // ignore EN_CHANGE
|
|
|
|
if (m_fBinary) {
|
|
if (pWordWheel) {
|
|
int iIndex = pos;
|
|
if( pWordWheel->GetString(iIndex, wszKeyword, (sizeof(wszKeyword)/2), TRUE) )
|
|
Seed(wszKeyword);
|
|
else
|
|
Seed((WCHAR*)NULL);
|
|
}
|
|
}
|
|
else {
|
|
pSiteMapEntry = GetSiteMapEntry(pos + 1);
|
|
Seed(pSiteMapEntry->GetKeyword());
|
|
}
|
|
m_fSelectionChange = FALSE; // ignore EN_CHANGE
|
|
break;
|
|
|
|
case NM_RETURN:
|
|
case NM_DBLCLK:
|
|
PostMessage(FindMessageParent(m_hwndListBox), WM_COMMAND, MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void CHtmlHelpControl::OnSizeIndex(LPRECT prc)
|
|
{
|
|
RECT rc;
|
|
GetClientRect(GetParent(m_hwnd), &rc);
|
|
|
|
InflateRect(&rc,
|
|
m_hpadding == -1 ? 0 : -m_hpadding,
|
|
m_vpadding == -1 ? 0 : -m_vpadding);
|
|
|
|
RECT rcButton;
|
|
GetWindowRect(m_hwndDisplayButton, &rcButton);
|
|
|
|
MoveWindow(m_hwndDisplayButton, rc.right - RECT_WIDTH(rcButton), rc.top, RECT_WIDTH(rcButton),
|
|
RECT_HEIGHT(rcButton), TRUE);
|
|
}
|
|
|
|
// This function has the lookup code, so we want it as fast as possible
|
|
|
|
#ifndef _DEBUG
|
|
#pragma optimize("Ot", on)
|
|
#endif
|
|
|
|
LRESULT CIndex::OnCommand(HWND hwnd, UINT id, UINT uNotifiyCode, LPARAM /*lParam*/)
|
|
{
|
|
CStr cszKeyword;
|
|
int pos;
|
|
SITEMAP_ENTRY* pSiteMapEntry;
|
|
int i;
|
|
WCHAR wszKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
|
|
CHAR szKeyword[HHWW_MAX_KEYWORD_LENGTH+1];
|
|
CWordWheel* pWordWheel = NULL;
|
|
CExCollection* pTitleCollection = NULL;
|
|
|
|
// Sometimes the lame main wndproc will route messages here that do not belong
|
|
// to the index and thus this can result in a re-entrant call to our
|
|
// binary word wheel (because the call may occur during initialization).
|
|
//
|
|
// Thus to work around this we need to detect when the call is bogus and skip
|
|
// the message.
|
|
//
|
|
// We can tell if the window associated with this index has been created
|
|
// by checking the m_bInit value, since it will always be set once the list box
|
|
// is filled. If it is not set then bail out since these messages are not
|
|
// for the index window.
|
|
if( !m_bInit )
|
|
return 0;
|
|
|
|
if( m_fBinary )
|
|
if (m_phh->m_phmData) {
|
|
pTitleCollection = m_phh->m_phmData->m_pTitleCollection;
|
|
pWordWheel = pTitleCollection->m_pDatabase->GetKeywordLinks();
|
|
}
|
|
|
|
switch (id) {
|
|
case IDEDIT_INDEX:
|
|
{
|
|
if (uNotifiyCode != EN_CHANGE)
|
|
return 0;
|
|
if (m_fSelectionChange) {
|
|
m_fSelectionChange = FALSE;
|
|
return 0;
|
|
}
|
|
CStr cszKeyword(m_hwndEditBox);
|
|
CWStr cwszKeyword(m_hwndEditBox);
|
|
if (!*cszKeyword.psz)
|
|
return 0;
|
|
|
|
if (m_fBinary) {
|
|
if (pWordWheel) {
|
|
DWORD dwIndex = 0;
|
|
if( m_bUnicode )
|
|
dwIndex = pWordWheel->GetIndex(cwszKeyword.pw);
|
|
else
|
|
dwIndex = pWordWheel->GetIndex(cszKeyword.psz);
|
|
|
|
if (dwIndex != HHWW_ERROR) {
|
|
m_pVList->SetTopIndex(dwIndex);
|
|
m_pVList->SetSelection(dwIndex, FALSE);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* REVIEW: This could be sped up by having a first character
|
|
* lookup, ala the RTF tokens in lex.cpp (hcrtf). Putting this
|
|
* in the thread would also improve user responsiveness.
|
|
*/
|
|
|
|
for (i = 1; i <= CountStrings(); i++) {
|
|
pSiteMapEntry = GetSiteMapEntry(i);
|
|
ASSERT_COMMENT(pSiteMapEntry->GetKeyword(), "Index entry added without a keyword");
|
|
|
|
/*
|
|
* Unless the user specifically requested it, we
|
|
* don't allow the keyboard to be used to get to
|
|
* anything other then first level entries.
|
|
*/
|
|
|
|
if (!g_fNonFirstKey && pSiteMapEntry->GetLevel() > 1)
|
|
continue;
|
|
|
|
BOOL bFound = FALSE;
|
|
if( m_bUnicode ) {
|
|
pSiteMapEntry->GetKeyword( wszKeyword, sizeof(wszKeyword)/2 );
|
|
if( isSameString( wszKeyword, cwszKeyword) )
|
|
bFound = TRUE;
|
|
}
|
|
else {
|
|
// BUGBUG: isSameString is not lcid aware
|
|
if( isSameString(pSiteMapEntry->GetKeyword(), cszKeyword) )
|
|
bFound = TRUE;
|
|
}
|
|
|
|
if( bFound ) {
|
|
m_pVList->SetTopIndex(i - 1);
|
|
m_pVList->SetSelection(i - 1, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case IDBTN_DISPLAY:
|
|
if (uNotifiyCode == BN_CLICKED) {
|
|
pos = m_pVList->GetSelection();
|
|
CStr cszKeyword(m_hwndEditBox);
|
|
CWStr cwszKeyword(m_hwndEditBox);
|
|
|
|
if (m_fBinary) {
|
|
if (pWordWheel) {
|
|
int iIndex = pos;
|
|
if( m_bUnicode )
|
|
pWordWheel->GetString(iIndex, wszKeyword, sizeof(wszKeyword)/2);
|
|
else
|
|
pWordWheel->GetString(iIndex, szKeyword, sizeof(szKeyword));
|
|
}
|
|
}
|
|
else {
|
|
pSiteMapEntry = GetSiteMapEntry(pos + 1);
|
|
if (!pSiteMapEntry)
|
|
break; // happens with an empty index
|
|
}
|
|
|
|
if (m_fBinary) {
|
|
if (pWordWheel) {
|
|
int iIndex = pos;
|
|
if( pWordWheel->IsPlaceHolder(iIndex) ) {
|
|
MsgBox(IDS_HH_E_KEYWORD_IS_PLACEHOLDER, MB_OK | MB_ICONWARNING);
|
|
return 0;
|
|
}
|
|
if( m_bUnicode ) {
|
|
if( pWordWheel->GetSeeAlso(iIndex, wszKeyword, sizeof(wszKeyword)/2) ) {
|
|
Seed(wszKeyword);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
if( pWordWheel->GetSeeAlso(iIndex, szKeyword, sizeof(szKeyword)/2) ) {
|
|
Seed(szKeyword);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (pSiteMapEntry->fSeeAlso) {
|
|
|
|
/*
|
|
* A See Also entry simply jumps to another location
|
|
* in the Index.
|
|
*/
|
|
Seed(GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
// If we have one or more titles, then give the user
|
|
// a choice of what to jump to.
|
|
|
|
if (m_fBinary) {
|
|
if( pWordWheel ) {
|
|
DWORD dwIndex = pos;
|
|
DWORD dwHitCount = pWordWheel->GetHitCount(dwIndex);
|
|
UINT CodePage = pTitleCollection->GetMasterTitle()->GetInfo()->GetCodePage();
|
|
CWTable tblTitles( CodePage );
|
|
CTable tblURLs;
|
|
CWTable tblLocations( CodePage );
|
|
BOOL bExcludedBySubset = FALSE;
|
|
BOOL bExcludedByInfoType = FALSE;
|
|
|
|
if (dwHitCount != HHWW_ERROR) {
|
|
for (DWORD i = 0; i < dwHitCount; i++) {
|
|
CExTitle* pTitle = NULL;
|
|
DWORD dwURLId = pWordWheel->GetHit(dwIndex, i, &pTitle);
|
|
if (pTitle && dwURLId != HHWW_ERROR) {
|
|
|
|
#if 0 // infotypes not supported
|
|
CSubSet* pSS;
|
|
const unsigned int *pdwITBits;
|
|
// Filter it?
|
|
if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSubSets &&
|
|
(pSS = pTitle->m_pCollection->m_pSubSets->GetIndexSubset()) &&
|
|
!pSS->m_bIsEntireCollection ) {
|
|
pdwITBits = pTitle->GetTopicITBits(dwURLId);
|
|
if( !pTitle->m_pCollection->m_pSubSets->fIndexFilter(pdwITBits) ) {
|
|
bExcludedByInfoType = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Structural subset filter ?
|
|
//
|
|
CStructuralSubset* pSubset;
|
|
if( pTitle->m_pCollection && pTitle->m_pCollection->m_pSSList &&
|
|
(pSubset = pTitle->m_pCollection->m_pSSList->GetF1()) && !pSubset->IsEntire() )
|
|
{
|
|
// Yes, filter using the current structural subset for F1.
|
|
//
|
|
if (! pSubset->IsTitleInSubset(pTitle) ) {
|
|
bExcludedBySubset = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
char szTitle[1024];
|
|
szTitle[0] = 0;
|
|
pTitle->GetTopicName( dwURLId, szTitle, sizeof(szTitle) );
|
|
if( !szTitle[0] )
|
|
strcpy( szTitle, GetStringResource( IDS_UNTITLED ) );
|
|
|
|
char szLocation[INTERNET_MAX_PATH_LENGTH];
|
|
szLocation[0] = 0;
|
|
if( pTitle->GetTopicLocation(dwURLId, szLocation, INTERNET_MAX_PATH_LENGTH) != S_OK )
|
|
strcpy( szLocation, GetStringResource( IDS_UNKNOWN ) );
|
|
|
|
char szURL[INTERNET_MAX_URL_LENGTH];
|
|
szURL[0] = 0;
|
|
pTitle->GetTopicURL( dwURLId, szURL, sizeof(szURL) );
|
|
|
|
if( szURL[0] )
|
|
{
|
|
if( !tblURLs.IsStringInTable(szURL) )
|
|
{
|
|
int iIndex = tblURLs.AddString(szURL);
|
|
tblTitles.AddIntAndString(iIndex, szTitle[0]?szTitle:"");
|
|
tblLocations.AddString( *szLocation?szLocation:"" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we get no topics then display a message stating so
|
|
if (tblURLs.CountStrings() < 1) {
|
|
int iStr = 0;
|
|
|
|
if( bExcludedBySubset && bExcludedByInfoType )
|
|
iStr = IDS_HH_E_KEYWORD_EXCLUDED;
|
|
else if( bExcludedBySubset )
|
|
iStr = IDS_HH_E_KEYWORD_NOT_IN_SUBSET;
|
|
else if( bExcludedByInfoType )
|
|
iStr = IDS_HH_E_KEYWORD_NOT_IN_INFOTYPE;
|
|
else
|
|
iStr = IDS_HH_E_KEYWORD_NOT_FOUND;
|
|
|
|
MsgBox( iStr, MB_OK | MB_ICONWARNING );
|
|
return 0;
|
|
}
|
|
|
|
// if only one topic then jump to it
|
|
if( tblURLs.CountStrings() == 1 ) {
|
|
char szURL[INTERNET_MAX_URL_LENGTH];
|
|
tblURLs.GetString( szURL, 1 );
|
|
ChangeHtmlTopic( szURL, hwnd );
|
|
return 0;
|
|
}
|
|
|
|
// we can sort the title table since it contains the index value
|
|
// of the associated URL so just make sure to always fetch the
|
|
// URL index from the selected title string and use that to get the URL
|
|
if( /*bAlphaSortHits*/ TRUE ) {
|
|
tblTitles.SetSorting(GetSystemDefaultLCID());
|
|
tblTitles.SortTable(sizeof(HASH));
|
|
}
|
|
|
|
HWND hWnd = GetFocus();
|
|
CTopicList TopicList(hWnd, &tblTitles, GetContentFont(), &tblLocations);
|
|
if (TopicList.DoModal()) {
|
|
char szURL[INTERNET_MAX_URL_LENGTH];
|
|
int iIndex = tblTitles.GetInt(TopicList.m_pos);
|
|
tblURLs.GetString( szURL, iIndex );
|
|
ChangeHtmlTopic( szURL, hwnd );
|
|
}
|
|
SetFocus(hWnd);
|
|
}
|
|
}
|
|
else {
|
|
UINT CodePage = pSiteMapEntry->pSiteMap->GetCodePage();
|
|
CWTable tblTitles( CodePage );
|
|
|
|
if (pSiteMapEntry->cUrls > 1)
|
|
{
|
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
for (int i = 0; i < pSiteMapEntry->cUrls; i++)
|
|
{
|
|
strcpy(szURL, GetUrlTitle(pSiteMapEntry, i) );
|
|
tblTitles.AddIntAndString(i, szURL);
|
|
}
|
|
|
|
// we can sort the title table since it contains the index value
|
|
// of the associated URL so just make sure to always fetch the
|
|
// URL index from the selected title string and use that to get the URL
|
|
if( /*bAlphaSortHits*/ TRUE ) {
|
|
tblTitles.SetSorting(GetSystemDefaultLCID());
|
|
tblTitles.SortTable(sizeof(HASH));
|
|
}
|
|
|
|
// CTopicList TopicList(m_phhctrl ? m_phhctrl->m_hwnd : FindMessageParent(m_hwndEditBox),
|
|
// &tblTitles, GetContentFont());
|
|
|
|
CTopicList* pTopicList;
|
|
if ( m_phhctrl )
|
|
pTopicList = new CTopicList(m_phhctrl, &tblTitles, GetContentFont());
|
|
else
|
|
pTopicList = new CTopicList(FindMessageParent(m_hwndEditBox), &tblTitles, GetContentFont());
|
|
|
|
if (m_phhctrl)
|
|
m_phhctrl->ModalDialog(TRUE);
|
|
int fResult = pTopicList->DoModal();
|
|
if (m_phhctrl)
|
|
m_phhctrl->ModalDialog(FALSE);
|
|
if (fResult)
|
|
{
|
|
int iIndex = tblTitles.GetInt( pTopicList->m_pos );
|
|
SITE_ENTRY_URL* pUrl = GetUrlEntry(pSiteMapEntry, iIndex);
|
|
JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, pInfoType, this, pUrl);
|
|
}
|
|
SetFocus(m_hwndEditBox);
|
|
delete pTopicList;
|
|
return 0;
|
|
}
|
|
JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, pInfoType, this, NULL);
|
|
SetFocus(m_hwndEditBox);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case ID_VIEW_ENTRY:
|
|
{
|
|
pos = m_pVList->GetSelection();
|
|
pSiteMapEntry = GetSiteMapEntry(pos + 1);
|
|
if(pSiteMapEntry)
|
|
DisplayAuthorInfo(pInfoType, this, pSiteMapEntry, FindMessageParent(m_hwndListBox), m_phhctrl);
|
|
}
|
|
return 0;
|
|
|
|
#ifdef _DEBUG
|
|
case ID_VIEW_MEMORY:
|
|
OnReportMemoryUsage();
|
|
return 0;
|
|
#endif
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
#ifndef _DEBUG
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
LRESULT WINAPI EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_CHAR: //Process this message to avoid damn beeps.
|
|
if ((wParam == VK_RETURN) || (wParam == VK_TAB))
|
|
return 0;
|
|
return W_DelegateWindowProc(lpfnlEditWndProc, hwnd, msg, wParam,lParam);
|
|
|
|
case WM_KEYDOWN:
|
|
switch (wParam)
|
|
{
|
|
case VK_RETURN:
|
|
SendMessage(FindMessageParent(hwnd), WM_COMMAND, MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
|
|
return 0;
|
|
|
|
case VK_TAB:
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SetFocus(GetDlgItem(GetParent(hwnd), IDBTN_DISPLAY));
|
|
return 0;
|
|
}
|
|
SetFocus(GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST));
|
|
return 0;
|
|
}
|
|
|
|
// fall through
|
|
|
|
case WM_KEYUP:
|
|
if ( VK_UP == wParam ||
|
|
VK_DOWN == wParam ||
|
|
VK_PRIOR == wParam ||
|
|
VK_NEXT == wParam )
|
|
{
|
|
#ifdef _DEBUG
|
|
HWND hwndListBox = GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST);
|
|
ASSERT(hwndListBox);
|
|
#endif
|
|
SendMessage(GetDlgItem(GetParent(hwnd), IDC_KWD_VLIST), msg, wParam, lParam);
|
|
// Move caret to the end of the edit control
|
|
PostMessage(hwnd, msg, VK_END, lParam);
|
|
return 0;
|
|
}
|
|
|
|
// fall through
|
|
|
|
default:
|
|
return W_DelegateWindowProc(lpfnlEditWndProc, hwnd, msg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
static LRESULT WINAPI ButtonProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(msg) {
|
|
case WM_KEYDOWN:
|
|
// REVIEW: 17-Oct-1997 [ralphw] Why are we special-casing VK_RETURN?
|
|
// lpfnlBtnWndProc should handle this automatically
|
|
|
|
if (wParam == VK_RETURN) {
|
|
SendMessage(FindMessageParent(hwnd), WM_COMMAND,MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
|
|
return 0;
|
|
}
|
|
|
|
if (wParam == VK_TAB) {
|
|
CIndex* pThis = (CIndex*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
if (GetKeyState(VK_SHIFT) < 0) {
|
|
SetFocus(pThis->m_hwndListBox);
|
|
return 0;
|
|
}
|
|
SetFocus(GetDlgItem(GetParent(hwnd), IDEDIT_INDEX));
|
|
return 0;
|
|
// PostMessage(pThis->m_phh->GetHwnd(), WMP_HH_TAB_KEY, 0, 0);
|
|
}
|
|
break;
|
|
}
|
|
return W_DelegateWindowProc(lpfnlBtnWndProc, hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: StrToken
|
|
|
|
PURPOSE: DBCS-enabed variant of strtok
|
|
|
|
PARAMETERS:
|
|
pszList
|
|
chDelimiter
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
You can NOT specify a DBCS character to look for, but you can
|
|
search a DBCS string for an ANSI character
|
|
|
|
MODIFICATION DATES:
|
|
06-Jan-1996 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
PSTR StrToken(PSTR pszList, PCSTR pszDelimeters)
|
|
{
|
|
static PSTR pszSavedList = NULL;
|
|
PSTR psz, pszTokens;
|
|
|
|
if (pszList) {
|
|
pszSavedList = pszList;
|
|
|
|
// On the first call, remove any leading token matches
|
|
|
|
for (psz = (PSTR) pszDelimeters; *psz; psz++) {
|
|
if (*psz == *pszSavedList) {
|
|
pszSavedList++;
|
|
psz = (PSTR) pszDelimeters - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_fDBCSSystem) {
|
|
psz = pszSavedList;
|
|
|
|
while (*psz) {
|
|
for (pszTokens = (PSTR) pszDelimeters; *pszTokens; pszTokens++) {
|
|
if (*pszTokens == *psz)
|
|
break;
|
|
}
|
|
if (*pszTokens == *psz)
|
|
break;
|
|
psz = CharNext(psz);
|
|
}
|
|
if (!*psz)
|
|
psz = NULL;
|
|
}
|
|
else {
|
|
psz = strpbrk(pszSavedList, pszDelimeters);
|
|
}
|
|
|
|
if (!psz) {
|
|
if (!*pszSavedList)
|
|
return NULL;
|
|
else {
|
|
PSTR pszReturn = pszSavedList;
|
|
pszSavedList = pszSavedList + strlen(pszSavedList);
|
|
return pszReturn;
|
|
}
|
|
}
|
|
*psz++ = '\0';
|
|
PSTR pszReturn = pszSavedList;
|
|
pszSavedList = psz;
|
|
return pszReturn;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// INavUI as Implemented by CIndex
|
|
//
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// ProcessMenuChar
|
|
//
|
|
bool
|
|
CIndex::ProcessMenuChar(HWND hwndParent, int ch)
|
|
{
|
|
return ::ProcessMenuChar(this, hwndParent, m_aDlgItems, c_NumDlgItems, ch) ;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// SetDefaultFocus
|
|
//
|
|
void
|
|
CIndex::SetDefaultFocus()
|
|
{
|
|
ASSERT(::IsValidWindow(m_hwndListBox));
|
|
|
|
if (SendMessage(m_hwndListBox, LB_GETCURSEL, 0, NULL) == LB_ERR)
|
|
{
|
|
SendMessage(m_hwndListBox, LB_SETCURSEL, 0,0);
|
|
}
|
|
SetFocus(m_hwndEditBox); // Set Focus to the Edit control
|
|
}
|
|
|
|
const int c_TopicColumn = 0;
|
|
const int c_LocationColumn = 1;
|
|
|
|
typedef struct tag_TOPICLISTSORTINFO
|
|
{
|
|
CTopicList* pThis; // The CTopicList object controlling the sort.
|
|
int iSubItem; // column we are sorting.
|
|
LCID lcid; // locale to sort by
|
|
WCHAR* pwszUntitled;
|
|
WCHAR* pwszUnknown;
|
|
} TOPICLISTSORTINFO;
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// TopicListCompareProc - Used to sort columns in the Topics List.
|
|
//
|
|
int CALLBACK TopicListCompareProc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
|
|
{
|
|
int iReturn = 0;
|
|
|
|
int iItem1 = (int)lParam1;
|
|
int iItem2 = (int)lParam2;
|
|
|
|
TOPICLISTSORTINFO* pInfo = reinterpret_cast<TOPICLISTSORTINFO*>(lParamSort);
|
|
CTopicList* pThis = pInfo->pThis;
|
|
|
|
switch( pInfo->iSubItem )
|
|
{
|
|
|
|
case c_TopicColumn: // Topic String
|
|
{
|
|
WCHAR wsz1[4096];
|
|
wsz1[0] = 0;
|
|
const WCHAR* pwsz1 = wsz1;
|
|
pThis->m_ptblTitles->GetHashStringW( iItem1, wsz1, 4096 );
|
|
if( !(*pwsz1) )
|
|
pwsz1 = pInfo->pwszUntitled;
|
|
|
|
WCHAR wsz2[4096];
|
|
wsz2[0] = 0;
|
|
const WCHAR* pwsz2 = wsz2;
|
|
pThis->m_ptblTitles->GetHashStringW( iItem2, wsz2, 4096 );
|
|
if( !(*pwsz2) )
|
|
pwsz2 = pInfo->pwszUntitled;
|
|
|
|
iReturn = W_CompareString( pInfo->lcid, 0, pwsz1, -1, pwsz2, -1 ) - 2;
|
|
}
|
|
break;
|
|
|
|
case c_LocationColumn: // Location String
|
|
{
|
|
WCHAR wsz1[4096];
|
|
wsz1[0] = 0;
|
|
const WCHAR* pwsz1 = wsz1;
|
|
pThis->m_ptblLocations->GetStringW( pThis->m_ptblTitles->GetInt(iItem1), wsz1, 4096 );
|
|
if( !(*pwsz1) )
|
|
pwsz1 = pInfo->pwszUnknown;
|
|
|
|
WCHAR wsz2[4096];
|
|
wsz2[0] = 0;
|
|
const WCHAR* pwsz2 = wsz2;
|
|
pThis->m_ptblLocations->GetStringW( pThis->m_ptblTitles->GetInt(iItem2), wsz2, 4096 );
|
|
if( !(*pwsz2) )
|
|
pwsz2 = pInfo->pwszUnknown;
|
|
|
|
iReturn = W_CompareString( pInfo->lcid, 0, pwsz1, -1, pwsz2, -1 ) - 2;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
extern BOOL WINAPI EnumListViewFont(HWND hwnd, LPARAM lval);
|
|
|
|
BOOL CTopicList::OnBeginOrEnd(void)
|
|
{
|
|
if (m_fInitializing)
|
|
{
|
|
m_fInitializing = FALSE;
|
|
|
|
#if 0
|
|
// note, we assume that some other part of HH detects that we either do or do
|
|
// not have ListView Unicode support and properly sets this bool
|
|
extern BOOL g_fUnicodeListView;
|
|
|
|
// if we can use a Unicode version of the control then all is well
|
|
// otherwise we need to use List1 as a template to create a Unicode
|
|
// version of the list view and hide the old ANSI version --
|
|
// we only need to do this for Windows 95/98 since Windows NT works
|
|
// just fine with Unicode
|
|
//
|
|
if( g_fSysWinNT || g_fUnicodeListView ) {
|
|
m_hwndListView = ::GetDlgItem(m_hWnd, IDC_TOPICS);
|
|
}
|
|
else { // Windows 95/98 w/o the new ComCtl32
|
|
HWND hWndList = ::GetDlgItem(m_hWnd, IDC_TOPICS);
|
|
::ShowWindow( hWndList, SW_HIDE );
|
|
RECT ListRect = { 0,0,0,0 };
|
|
::MapDialogRect( m_hWnd, &ListRect );
|
|
DWORD dwStyles = ::GetWindowLong( hWndList, GWL_STYLE );
|
|
|
|
// get the size of the control from List1
|
|
RECT rect;
|
|
::GetWindowRect( hWndList, &rect );
|
|
POINT pt;
|
|
pt.x = rect.left;
|
|
pt.y = rect.top;
|
|
::ScreenToClient( m_hWnd, &pt );
|
|
ListRect.top = pt.y;
|
|
ListRect.bottom = ListRect.top + (rect.bottom - rect.top);
|
|
ListRect.left = pt.x;
|
|
ListRect.right = ListRect.left + (rect.right - rect.left);
|
|
|
|
m_hwndListView = W_CreateControlWindow(
|
|
g_RTL_Style | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
|
|
dwStyles | WS_CHILD | WS_VISIBLE,
|
|
W_ListView, L"List0",
|
|
ListRect.left, ListRect.top, RECT_WIDTH(ListRect), RECT_HEIGHT(ListRect),
|
|
m_hWnd, NULL, _Module.GetModuleInstance(), NULL);
|
|
|
|
// force it to be the "active" window
|
|
m_fFocusChanged = TRUE;
|
|
::SetFocus( m_hwndListView );
|
|
}
|
|
#else
|
|
m_hwndListView = ::GetDlgItem(m_hWnd, IDC_TOPICS);
|
|
#endif
|
|
|
|
W_EnableUnicode(m_hwndListView, W_ListView);
|
|
// ::SendMessage(m_hwndListView, WM_SETFONT, (WPARAM)_Resource.GetUIFont(), FALSE);
|
|
|
|
// Add Column Headings to the List View Control
|
|
LV_COLUMNW column;
|
|
column.mask = LVCF_FMT | LVCF_TEXT;
|
|
column.fmt = LVCFMT_LEFT ;
|
|
// Title Column
|
|
column.pszText = (LPWSTR)GetStringResourceW(IDS_ADVSEARCH_HEADING_TITLE);
|
|
int iCol = c_TopicColumn ;
|
|
int iResult = W_ListView_InsertColumn(m_hwndListView, iCol++, &column);
|
|
ASSERT(iResult != -1) ;
|
|
// Location column
|
|
::SendMessage(m_hwndListView, WM_SETFONT, (WPARAM)m_hfont, FALSE);
|
|
if ( m_ptblLocations != NULL )
|
|
{
|
|
column.pszText = (LPWSTR)GetStringResourceW(IDS_ADVSEARCH_HEADING_LOCATION);
|
|
ListView_SetExtendedListViewStyle( m_hwndListView, LVS_EX_FULLROWSELECT );
|
|
|
|
iResult = W_ListView_InsertColumn(m_hwndListView, iCol, &column);
|
|
}
|
|
ASSERT(iResult != -1) ;
|
|
|
|
if(g_fBiDi)
|
|
::SetWindowLong(m_hwndListView, GWL_EXSTYLE, GetWindowLong(m_hwndListView, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING);
|
|
|
|
// Make sure the list header uses a normal font
|
|
EnumChildWindows(m_hwndListView, (WNDENUMPROC) EnumListViewFont, 0);
|
|
|
|
RECT rc;
|
|
int col1;
|
|
GetWindowRect(m_hwndListView, &rc);
|
|
int nScrollBarWidth = GetSystemMetrics(SM_CXVSCROLL);
|
|
if ( m_ptblLocations == NULL )
|
|
col1 = RECT_WIDTH(rc)-nScrollBarWidth;
|
|
else
|
|
col1 = (RECT_WIDTH(rc)/2)-nScrollBarWidth;
|
|
W_ListView_SetColumnWidth(m_hwndListView, c_TopicColumn, col1 );
|
|
if ( m_ptblLocations != NULL )
|
|
W_ListView_SetColumnWidth(m_hwndListView, c_LocationColumn, RECT_WIDTH(rc)-col1-nScrollBarWidth/*LVSCW_AUTOSIZE_USEHEADER*/ );
|
|
|
|
AddItems();
|
|
|
|
}
|
|
else
|
|
{
|
|
if (m_pos <= 0 ) // nothing to do on end.
|
|
m_pos = 1;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void CTopicList::AddItems()
|
|
{
|
|
ASSERT(m_cResultCount>0);
|
|
LV_ITEMW item; // To add to the list view.
|
|
ListView_DeleteAllItems(m_hwndListView);
|
|
ListView_SetItemCount( m_hwndListView, m_cResultCount );
|
|
WCHAR wsz[1024];
|
|
|
|
for ( int i=0; i< m_cResultCount; i++)
|
|
{
|
|
// need to get the topic string from the Topic Number
|
|
// Add the Topic string to the List View.
|
|
//
|
|
WCHAR wsz[4096];
|
|
WCHAR* pwsz = wsz;
|
|
m_ptblTitles->GetHashStringW(i+1, wsz, 4096);
|
|
item.pszText = wsz;
|
|
item.mask = LVIF_TEXT|LVIF_PARAM;
|
|
item.iImage = 0;
|
|
item.state = 0;
|
|
item.stateMask = 0;
|
|
item.iItem = i;
|
|
item.iSubItem = c_TopicColumn;
|
|
item.lParam = i+1;
|
|
W_ListView_InsertItem( m_hwndListView, &item );
|
|
}
|
|
|
|
// Add Location Column (do this after the inserts since the list could be sorted)
|
|
if( m_ptblLocations ) {
|
|
for ( int i=0; i< m_cResultCount; i++)
|
|
{
|
|
item.iItem = i;
|
|
item.iSubItem = c_TopicColumn;
|
|
item.mask = LVIF_PARAM;
|
|
W_ListView_GetItem( m_hwndListView, &item );
|
|
m_ptblLocations->GetStringW( m_ptblTitles->GetInt((int)item.lParam), wsz, 1024 );
|
|
item.pszText = wsz;
|
|
W_ListView_SetItemText(m_hwndListView, i, c_LocationColumn, wsz);
|
|
}
|
|
}
|
|
W_ListView_SetItemState( m_hwndListView, 0, LVIS_SELECTED | LVIS_FOCUSED , LVIF_STATE | LVIS_SELECTED | LVIS_FOCUSED);
|
|
m_pos = 1;
|
|
}
|
|
|
|
|
|
LRESULT CTopicList::OnDlgMsg(UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if ( msg == WM_NOTIFY )
|
|
{
|
|
if ( ListViewMsg( GetParent(*this), (NM_LISTVIEW*)lParam) )
|
|
// EndDialog(TRUE);
|
|
::SendMessage(m_hWnd, WM_COMMAND, (WPARAM)1, (LPARAM)0); // WPARAM == ((BN_CLICKED<16)|IDOK)
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
LRESULT CTopicList::ListViewMsg(HWND hwnd, NM_LISTVIEW* lParam)
|
|
{
|
|
switch(lParam->hdr.code)
|
|
{
|
|
case NM_DBLCLK:
|
|
case NM_RETURN:
|
|
if ( m_pos == -1 )
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
case LVN_ITEMCHANGING:
|
|
if ( ((NM_LISTVIEW*)lParam)->uNewState & LVIS_SELECTED )
|
|
m_pos = (int)((NM_LISTVIEW*)lParam)->lParam;
|
|
else
|
|
m_pos = -1 ;
|
|
|
|
break;
|
|
case LVN_GETDISPINFOA: // the control wants to draw the items
|
|
case LVN_GETDISPINFOW: // the control wants to draw the items
|
|
break;
|
|
|
|
case LVN_COLUMNCLICK: {
|
|
CHourGlass waitcur;
|
|
NM_LISTVIEW *pNM = reinterpret_cast<NM_LISTVIEW*>(lParam);
|
|
|
|
// Get the string for untitled things.
|
|
CWStr wstrUntitled(IDS_UNTITLED);
|
|
CWStr wstrUnknown(IDS_UNKNOWN);
|
|
|
|
// Fill this structure to make the sorting quicker/more efficient.
|
|
TOPICLISTSORTINFO Info;
|
|
Info.pThis = this;
|
|
Info.iSubItem = pNM->iSubItem;
|
|
LCID lcid = 0;
|
|
LCIDFromCodePage( m_ptblTitles->GetCodePage(), &lcid );
|
|
Info.lcid = lcid;
|
|
Info.pwszUntitled = wstrUntitled;
|
|
Info.pwszUnknown = wstrUnknown;
|
|
|
|
W_ListView_SortItems(pNM->hdr.hwndFrom,
|
|
TopicListCompareProc,
|
|
reinterpret_cast<LPARAM>(&Info));
|
|
}
|
|
// Fall through...
|
|
|
|
default:
|
|
;
|
|
}
|
|
return 0;
|
|
|
|
}
|