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

// 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;
}