windows-nt/Source/XPSP1/NT/enduser/stuff/hhctrl/contents.cpp

2364 lines
81 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
#include "header.h"
#include "strtable.h"
#include "hha_strtable.h"
#include "hhctrl.h"
#include "resource.h"
#include <intshcut.h>
#include "htmlhelp.h"
#include "secwin.h"
#include "cpaldc.h"
#include "cprint.h"
#include <wininet.h>
#include "contain.h"
#include "cdefinss.h"
#include "cctlww.h"
// Forward Declarations
LRESULT WINAPI TreeViewProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void LoadFirstLevel (CTreeNode *pRoot, HWND hwndTreeView, HTREEITEM * m_tiFirstVisible );
HTREEITEM AddTitleChildren (CTreeNode *pNode, HTREEITEM hParent, HWND hwndTreeView);
HTREEITEM AddNode (CTreeNode *pNode, HTREEITEM hParent, HWND hwndTreeView);
BOOL HandleExpanding (TVITEMW* pTvi, HWND hwndTreeView, UINT action, BOOL *pSync);
void AddChildren (TVITEMW* pTvi, HWND hwndTreeView);
void DeleteChildren (TVITEMW* pTvi, HWND hwndTreeView);
void FreeChildrenAllocations (HWND hwndTreeView, HTREEITEM ti);
UINT cpTemp = CP_ACP;
WNDPROC lpfnlTreeViewWndProc = NULL; // Initialize.
// Constants
const int SITEMAP_MAX_LEVELS = 50; // maximum nested folders
CToc::CToc(CHtmlHelpControl* phhctrl, IUnknown* pUnkOuter, CHHWinType* phh)
{
m_phhctrl = phhctrl;
m_pOuter = pUnkOuter;
m_phh = phh;
m_hwndTree = NULL;
m_cntCurHighlight = m_cntFirstVisible = 0;
m_fSuppressJump = FALSE;
m_fIgnoreNextSelChange = FALSE;
m_fHack = FALSE;
m_exStyles = 0;
m_dwStyles = 0;
m_padding = 0; // padding to put around the TOC
if (phh)
m_NavTabPos = phh->tabpos;
else
m_NavTabPos = HHWIN_NAVTAB_TOP ;;
m_fSuspendSync = FALSE;
m_hbmpBackGround = NULL;
m_hbrBackGround = NULL;
m_cFonts = 0;
m_fGlobal = FALSE;
m_tiFirstVisible = NULL;
m_pInfoType = NULL;
m_pBinTOCRoot = NULL;
m_fBinaryTOC = NULL;
m_fSyncOnActivation = FALSE;
m_phTreeItem = NULL ;
m_hil = NULL;
}
CToc::~CToc()
{
#if 1
if ( m_pInfoType )
delete m_pInfoType;
#endif
if (m_fBinaryTOC)
{
// clean up memory for binary tree
// get the root item
TV_ITEMW hCur;
HTREEITEM hNext;
CTreeNode *pCurNode;
hCur.hItem = W_TreeView_GetRoot(m_hwndTree);
// this loop will iterate through the top level nodes
//
while(hCur.hItem)
{
FreeChildrenAllocations(m_hwndTree, hCur.hItem);
// get the next sibling (if any)
//
hNext = TreeView_GetNextSibling(m_hwndTree, hCur.hItem);
// free this nodes item data
//
hCur.mask = TVIF_PARAM;
if (W_TreeView_GetItem(m_hwndTree, &hCur) == TRUE)
{
if (hCur.lParam)
{
// delete the node from the treeview
//
W_TreeView_DeleteItem(m_hwndTree, hCur.hItem);
// free the node's data
//
pCurNode = (CTreeNode *)hCur.lParam;
delete pCurNode;
}
}
// on to the next top level node
//
hCur.hItem = hNext;
}
}
// free the node
if (m_pBinTOCRoot)
delete m_pBinTOCRoot;
if (IsValidWindow(m_hwndTree))
{
DestroyWindow(m_hwndTree);
// Destroying the TreeView control, make sure we no longer point to it as a valid
// subclassed window.
if (NULL != lpfnlTreeViewWndProc)
{
lpfnlTreeViewWndProc = NULL;
}
}
if (m_hbrBackGround)
DeleteObject(m_hbrBackGround);
if (m_cFonts) {
for (int i = 0; i < m_cFonts; i++)
DeleteObject(m_ahfonts[i]);
lcFree(m_ahfonts);
}
if (m_hbmpBackGround)
DeleteObject(m_hbmpBackGround);
if (m_hil)
{
ImageList_Destroy(m_hil);
m_hil = NULL;
}
if ( m_phTreeItem )
lcFree(m_phTreeItem);
}
BOOL CToc::ReadFile(PCSTR pszFile)
{
if (m_phh && m_phh->m_phmData && m_phh->m_phmData->m_pTitleCollection &&
HashFromSz(FindFilePortion(pszFile)) == m_phh->m_phmData->m_hashBinaryTocName) {
m_pBinTOCRoot = m_phh->m_phmData->m_pTitleCollection->GetRootNode();
m_fBinaryTOC = (m_pBinTOCRoot && m_phh->m_phmData->m_pTitleCollection->GetFirstTitle() != NULL) ? TRUE : FALSE;
if (!m_fBinaryTOC) {
delete m_pBinTOCRoot;
m_pBinTOCRoot = NULL;
}
else
return TRUE;
}
UINT CodePage = -1;
if( m_phh && m_phh->m_phmData ) {
CodePage = m_phh->m_phmData->GetInfo()->GetCodePage();
}
return m_sitemap.ReadFromFile(pszFile, FALSE, NULL, CodePage);
}
BOOL CToc::Create(HWND hwndParent)
{
RECT rcParent;
GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
DWORD dwTempStyle = 0;
// Disable tooltips for bi-di due to common control bug
//
// if(g_RTL_Mirror_Style)
// dwTempStyle = TVS_NOTOOLTIPS;
if(g_RTL_Style && !g_RTL_Mirror_Style)
dwTempStyle |= TVS_RTLREADING;
m_hwndTree = W_CreateControlWindow(
m_exStyles | g_RTL_Mirror_Style,
WS_CHILD | m_dwStyles | dwTempStyle,
W_TreeView, L"",
rcParent.left, rcParent.top, RECT_WIDTH(rcParent), RECT_HEIGHT(rcParent),
hwndParent, NULL, _Module.GetModuleInstance(), NULL);
return m_hwndTree != NULL; // REVIEW: notify here if failure?
}
void CToc::ResizeWindow()
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
// Resize to fit the client area of the parent.
HWND hwndParent = GetParent(m_hwndTree) ;
ASSERT(::IsValidWindow(hwndParent)) ;
RECT rcParent;
GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
MoveWindow(m_hwndTree, rcParent.left,
rcParent.top, RECT_WIDTH(rcParent), RECT_HEIGHT(rcParent), TRUE);
}
void CToc::HideWindow(void)
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
::ShowWindow(m_hwndTree, SW_HIDE);
}
void CToc::ShowWindow(void)
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
::ShowWindow(m_hwndTree, SW_SHOW);
SetFocus(m_hwndTree);
}
/***************************************************************************
FUNCTION: LoadContentsFile
PURPOSE: Load the Contents file, convert it into g_pbTree
PARAMETERS:
pszMasterFile
RETURNS:
TRUE if successfully loaded
COMMENTS:
Assumes we are being run from a thread without a message queue.
MODIFICATION DATES:
09-Jul-1997 [ralphw]
***************************************************************************/
BOOL CHtmlHelpControl::LoadContentsFile(PCSTR pszMasterFile)
{
TCHAR szPath[MAX_PATH];
if (!ConvertToCacheFile(pszMasterFile, szPath)) {
szPath[0] = '\0';
if (!IsCompiledHtmlFile(pszMasterFile) && m_pWebBrowserApp) {
CStr cszCurUrl;
m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
cszCurUrl.ReSize(cszCurUrl.SizeAlloc() + (int)strlen(pszMasterFile));
PSTR pszChmSep = strstr(cszCurUrl, txtDoubleColonSep);
if (pszChmSep) { // this is a compiled HTML file
strcpy(pszChmSep + 2, pszMasterFile);
strcpy(szPath, cszCurUrl);
}
}
if (!szPath[0]) {
AuthorMsg(IDS_CANT_OPEN, pszMasterFile);
strncpy(szPath, pszMasterFile, MAX_PATH); // BugFix: Don't over write buffer.
szPath[MAX_PATH-1] = 0;
}
}
// Even if we failed, we continue on to let ReadFromFile create
// a dummy entry.
m_ptoc= new CToc(this, m_pUnkOuter);
UINT CodePage = -1;
if( m_ptoc && m_ptoc->m_phh && m_ptoc->m_phh->m_phmData ) {
CodePage = m_ptoc->m_phh->m_phmData->GetInfo()->GetCodePage();
}
if (!m_ptoc->m_sitemap.ReadFromFile(szPath, FALSE, this, CodePage))
return FALSE;
if (m_ptoc->m_sitemap.CountStrings())
m_ptoc->m_cntCurHighlight = m_ptoc->m_cntFirstVisible = 1;
// populate the InfoType member object of the CToc
if ( !m_ptoc->m_pInfoType )
{
if (m_ptoc->m_phh && m_ptoc->m_phh->m_phmData && m_ptoc->m_phh->m_phmData->m_pdInfoTypes )
{ // load from the global IT store
m_ptoc->m_pInfoType = new CInfoType;
m_ptoc->m_pInfoType->CopyTo( m_ptoc->m_phh->m_phmData );
// if there are info type bits set by the API assign them here
if ( m_ptoc->m_phh->m_phmData->m_pAPIInfoTypes &&
m_ptoc->m_pInfoType->AnyInfoTypes(m_ptoc->m_phh->m_phmData->m_pAPIInfoTypes) )
{
memcpy(m_ptoc->m_pInfoType->m_pInfoTypes,
m_ptoc->m_phh->m_phmData->m_pAPIInfoTypes,
m_ptoc->m_pInfoType->InfoTypeSize() );
}
}else
{
// no global IT's; load from the .hhc IT store
m_ptoc->m_pInfoType = new CInfoType;
*m_ptoc->m_pInfoType = m_ptoc->m_sitemap;
}
}
return TRUE;
}
__inline HTREEITEM Tree_AddItem(HWND hwndTree,
HTREEITEM htiParent, int iImage, UINT cChildren, LPARAM lParam,
TV_INSERTSTRUCTW* ptcInsert)
{
ptcInsert->hParent = htiParent;
ptcInsert->item.iImage = iImage;
ptcInsert->item.iSelectedImage = iImage;
ptcInsert->item.cChildren = cChildren;
ptcInsert->item.lParam = lParam;
return W_TreeView_InsertItem(hwndTree, ptcInsert);
}
BOOL CToc::InitTreeView()
{
// REVIEW: following line from WinHelp codebase. Do we need it?
ASSERT(::IsValidWindow(m_hwndTree)) ;
WORD dwImageListResource = IDBMP_CNT_IMAGE_LIST;
if(g_RTL_Mirror_Style)
dwImageListResource = IDBMP_IMAGE_LIST_BIDI;
SetWindowPos(m_hwndTree, NULL, 0, 0, 1, 1,
SWP_DRAWFRAME | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
if (!m_fGlobal ) { // BUGBUG [Pat H] Binary TOC needs to be enhanced for ImageLists.
if (!m_sitemap.m_pszImageList || m_fBinaryTOC)
m_hil = ImageList_LoadImage(_Module.GetResourceInstance(),
MAKEINTRESOURCE(dwImageListResource),
CWIDTH_IMAGE_LIST, 0, 0x00FF00FF, IMAGE_BITMAP, 0);
else {
char szBitmap[MAX_PATH];
BOOL fResult;
if (m_phhctrl)
fResult = m_phhctrl->ConvertToCacheFile(m_sitemap.m_pszImageList, szBitmap);
else
fResult = ConvertToCacheFile(m_sitemap.m_pszImageList, szBitmap);
if (fResult)
m_hil = ImageList_LoadImage(NULL, szBitmap,
m_sitemap.m_cImageWidth, 0, m_sitemap.m_clrMask, IMAGE_BITMAP, LR_LOADFROMFILE);
else
m_hil = NULL;
if (!m_hil) {
AuthorMsg(IDS_CANT_OPEN, m_sitemap.m_pszImageList, FindMessageParent(m_hwndTree), m_phhctrl);
m_hil = ImageList_LoadImage(_Module.GetResourceInstance(),
MAKEINTRESOURCE(dwImageListResource),
CWIDTH_IMAGE_LIST, 0, 0x00FF00FF, IMAGE_BITMAP, 0);
}
}
}
if ( !m_fBinaryTOC )
m_sitemap.m_cImages = ImageList_GetImageCount(m_hil);
W_TreeView_SetImageList(m_hwndTree, m_hil, TVSIL_NORMAL);
SendMessage(m_hwndTree, WM_SETREDRAW, FALSE, 0);
// BUGBUG [Pat H] Binary TOC needs to be enhanced for FONT information.
if (!m_fBinaryTOC && m_sitemap.m_pszFont) {
/*
* If the TOC had a font, it will over-ride any font specified in
* the CHM file.
*/
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));
//
// Insure correct charset...
//
int iCharset = -1;
if ( m_phh )
iCharset = m_phh->GetContentCharset();
else if ( m_phhctrl )
iCharset = m_phhctrl->GetCharset();
if(g_fSysWinNT)
{
UINT CodePage = CP_ACP;
if( m_phh && m_phh->m_phmData )
CodePage = m_phh->m_phmData->GetInfo()->GetCodePage();
WCHAR *pwcLocal = MakeWideStr((char *)m_sitemap.m_pszFont, CodePage);
if(pwcLocal)
{
m_ahfonts[m_cFonts - 1] = CreateUserFontW(pwcLocal, NULL, NULL, iCharset);
free(pwcLocal);
}
else
m_ahfonts[m_cFonts - 1] = CreateUserFont(m_sitemap.m_pszFont, NULL, NULL, iCharset);
}
else
m_ahfonts[m_cFonts - 1] = CreateUserFont(m_sitemap.m_pszFont, NULL, NULL, iCharset);
}
if (m_ahfonts[m_cFonts - 1])
SendMessage(m_hwndTree, WM_SETFONT, (WPARAM) m_ahfonts[m_cFonts - 1], 0);
}
else {
if ( m_phh )
SendMessage(m_hwndTree, WM_SETFONT, (WPARAM)m_phh->GetAccessableContentFont(), 0);
else if ( m_phhctrl )
SendMessage(m_hwndTree, WM_SETFONT, (WPARAM)m_phhctrl->GetContentFont(), 0);
}
// +1 because we are a 1-based table
if (!m_fBinaryTOC )
{
m_phTreeItem = (HTREEITEM*) lcCalloc((m_sitemap.CountStrings() + 1) * sizeof(HTREEITEM));
TV_INSERTSTRUCTW tcAdd;
tcAdd.hInsertAfter = TVI_LAST;
tcAdd.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM;
tcAdd.item.hItem = NULL;
tcAdd.item.pszText = LPSTR_TEXTCALLBACKW;
HTREEITEM ahtiParents[SITEMAP_MAX_LEVELS + 1];
HTREEITEM hti = NULL;
HTREEITEM htiParent = TVI_ROOT;
int curLevel = 0;
ahtiParents[0] = TVI_ROOT;
int pos;
CSubSets *pSSs = NULL;
if ( m_phh && m_phh->m_phmData && m_phh->m_phmData->m_pTitleCollection &&
m_phh->m_phmData->m_pTitleCollection->m_pSubSets )
pSSs = m_phh->m_phmData->m_pTitleCollection->m_pSubSets;
for (pos = 1; pos <= m_sitemap.CountStrings(); pos++)
{
dontAdd:
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(pos);
// the m_pInfoType member is set by the customize
// option on the right click menu.
if (!pSiteMapEntry->fShowToEveryOne && pSiteMapEntry->cUrls &&
#if 0 // enable for subset filtering.
m_pInfoType && !m_pInfoType->IsEntryInCurTypeList(pSiteMapEntry, pSSs ) )
#else
m_pInfoType && !m_pInfoType->IsEntryInCurTypeList(pSiteMapEntry ) )
#endif
//!m_sitemap.IsEntryInCurTypeList(pSiteMapEntry))
{
continue;
}
if (pSiteMapEntry->IsTopic()) {
if (pSiteMapEntry->level > 0 && pSiteMapEntry->level <= curLevel) {
// if (pSiteMapEntry->level < 1)
// pSiteMapEntry->level = 1;
htiParent = ahtiParents[curLevel = pSiteMapEntry->level - 1];
}
pSiteMapEntry->iImage = (BYTE)m_sitemap.GetImageNumber(pSiteMapEntry);
// Add the topic to the treeview control
HTREEITEM hItem = Tree_AddItem(m_hwndTree,
htiParent, // parent
pSiteMapEntry->iImage - 1,
0, // has kids
(LPARAM) pos, // extra data
&tcAdd);
m_phTreeItem[pos] = hItem;
}
else {
int i=0;
SITEMAP_ENTRY *pSME;
do {
i++;
pSME = m_sitemap.GetSiteMapEntry(pos+i);
if ( (pSME>0) && (pSME->level <= pSiteMapEntry->level) )
{
pos+=i;
goto dontAdd; // don't add the node with no topics to the TV.
}
}
while( pSME > 0 && !pSME->fTopic );
// *** FOLDER LINE ***
if (pSiteMapEntry->level > curLevel + 1) // can't skip levels
pSiteMapEntry->level = curLevel + 1;
int this_level = pSiteMapEntry->level;
if (this_level < 1)
this_level = 1;
// -1 to get a closed book
pSiteMapEntry->iImage = (BYTE)m_sitemap.GetImageNumber(pSiteMapEntry);
// switch to closed image
if (pSiteMapEntry->iImage == IMAGE_OPEN_BOOK ||
pSiteMapEntry->iImage == IMAGE_OPEN_BOOK_NEW ||
pSiteMapEntry->iImage == IMAGE_OPEN_FOLDER ||
pSiteMapEntry->iImage == IMAGE_OPEN_FOLDER_NEW)
pSiteMapEntry->iImage--;
htiParent = Tree_AddItem(m_hwndTree,
ahtiParents[this_level - 1],
pSiteMapEntry->iImage - 1,
TRUE, (DWORD) pos, &tcAdd);
m_phTreeItem[pos] = htiParent;
ahtiParents[curLevel = this_level] = htiParent;
}
}
}
else
LoadFirstLevel( m_pBinTOCRoot, m_hwndTree, &m_tiFirstVisible ); // binary TOC, load the first level of the tree view.
#if 0
12-Aug-1997 [ralphw] This code is only useful if we are restoring
a treeview control that was closed but not deleted.
// REVIEW: this was in WinHelp code base
// FlushMessageQueue(WM_USER);
for (pos = 1; pos <= CountStrings(); pos++) {
SITEMAP_ENTRY* pSiteMapEntry = GetSiteMapEntry(pos);
// Restore our position
if (pSiteMapEntry->iImage == IMAGE_OPEN_FOLDER) {
W_TreeView_Expand(m_hwndTree, m_phTreeItem[pos],
TVE_EXPAND);
// REVIEW: this was in WinHelp code base
// FlushMessageQueue(WM_USER);
}
}
#endif
// BUGBUG [Pat H] Binary TOC needs to be enhanced to support colors and background bitmaps
if (!m_fBinaryTOC && !m_fGlobal) {
if (m_sitemap.m_clrBackground != -1 && m_sitemap.m_clrForeground != -1) {
HDC hdc = GetWindowDC(m_hwndTree);
// If the colors are the same, then ignore them both
if (GetHighContrastFlag() ||
GetNearestColor(hdc, m_sitemap.m_clrBackground) ==
GetNearestColor(hdc, m_sitemap.m_clrForeground))
m_sitemap.m_clrBackground = m_sitemap.m_clrForeground = (COLORREF) -1;
ReleaseDC(m_hwndTree, hdc);
}
if (m_sitemap.m_clrBackground != -1)
m_hbrBackGround = CreateSolidBrush(m_sitemap.m_clrBackground);
if (m_sitemap.m_pszBackBitmap && !m_hbmpBackGround) {
char szBitmap[MAX_PATH];
if (ConvertToCacheFile(m_sitemap.m_pszBackBitmap, szBitmap) &&
LoadGif(szBitmap, &m_hbmpBackGround, &m_hpalBackGround, NULL)) {
BITMAP bmp;
GetObject(m_hbmpBackGround, sizeof(BITMAP), &bmp);
m_cxBackBmp = bmp.bmWidth;
m_cyBackBmp = bmp.bmHeight;
}
}
}
if (m_phh || m_hbrBackGround || m_hbmpBackGround)
{
BOOL fUni = IsWindowUnicode(m_hwndTree);
if (lpfnlTreeViewWndProc == NULL)
lpfnlTreeViewWndProc = W_GetWndProc(m_hwndTree, fUni);
W_SubClassWindow(m_hwndTree, (LONG_PTR) TreeViewProc, fUni);
SETTHIS(m_hwndTree);
}
SendMessage(m_hwndTree, WM_SETREDRAW, TRUE, 0);
m_fSuppressJump = TRUE;
if ( !m_fBinaryTOC )
{
ASSERT(m_cntFirstVisible <= m_sitemap.CountStrings());
if (m_cntFirstVisible && m_phTreeItem)
W_TreeView_Select(m_hwndTree, m_phTreeItem[m_cntFirstVisible],
TVGN_FIRSTVISIBLE);
}
else
{
if ( m_tiFirstVisible )
{
W_TreeView_Select(m_hwndTree, m_tiFirstVisible, TVGN_FIRSTVISIBLE);
m_hitemCurHighlight = m_tiFirstVisible;
}
}
#ifdef _DEBUG
HTREEITEM hItemFirstVisible = W_TreeView_GetFirstVisible(m_hwndTree);
#endif
if (!m_fBinaryTOC && m_cntCurHighlight && m_phTreeItem)
W_TreeView_SelectItem(m_hwndTree, m_phTreeItem[m_cntCurHighlight]);
m_hitemCurHighlight = W_TreeView_GetSelection(m_hwndTree);
m_fSuppressJump = FALSE;
if (m_fGlobal && !m_cszCurUrl.IsEmpty()) {
m_fSuspendSync = FALSE;
Synchronize(m_cszCurUrl);
}
::ShowWindow(m_hwndTree, SW_SHOW);
return TRUE;
}
__inline void Tree_SetImage(HWND hwndTree, int iImage, HTREEITEM hItem)
{
ASSERT(::IsValidWindow(hwndTree)) ;
TV_ITEMW tvinfo;
ZeroMemory(&tvinfo, sizeof(tvinfo));
tvinfo.hItem = hItem;
tvinfo.iImage = iImage - 1;
tvinfo.iSelectedImage = iImage - 1;
tvinfo.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
W_TreeView_SetItem(hwndTree, &tvinfo);
}
LRESULT CToc::OnSiteMapTVMsg( NM_TREEVIEW *pnmhdr )
{
SITEMAP_ENTRY* pSiteMapEntry;
TV_HITTESTINFO ht;
switch(pnmhdr->hdr.code) {
case TVN_GETDISPINFOA:
#define pdi ((TV_DISPINFOA*) pnmhdr)
if (pdi->item.mask & TVIF_TEXT)
{
pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)pdi->item.lParam);
strncpy(pdi->item.pszText, pSiteMapEntry->pszText, pdi->item.cchTextMax);
}
break;
#undef pdi
case TVN_GETDISPINFOW:
#define pdi ((TV_DISPINFOW*) pnmhdr)
if (pdi->item.mask & TVIF_TEXT)
{
pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)pdi->item.lParam);
if (FAILED(pSiteMapEntry->GetKeyword(pdi->item.pszText, pdi->item.cchTextMax)))
_wcsncpy(pdi->item.pszText, GetStringResourceW(IDS_UNTITLED), pdi->item.cchTextMax);
}
break;
#undef pdi
case NM_RETURN:
case NM_DBLCLK:
{
TV_ITEMW tvi;
ASSERT(::IsValidWindow(m_hwndTree)) ;
tvi.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvi.hItem)
break; // probably ENTER with no selection
tvi.mask = TVIF_PARAM;
W_TreeView_GetItem(m_hwndTree, &tvi);
pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)tvi.lParam);
if (pSiteMapEntry->pUrls) {
m_fSuspendSync = TRUE;
if (pSiteMapEntry->fSendEvent && m_phhctrl) {
m_phhctrl->SendEvent(m_sitemap.GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
return NULL;
}
JumpToUrl(m_pOuter, m_hwndTree, pSiteMapEntry, m_pInfoType, &(this->m_sitemap), NULL);
if (m_phh)
{
m_phh->m_hwndControl = m_hwndTree;
}
}
// The treeview does not automatically expand the node with the enter key.
// so we do it here.
if ( pnmhdr->hdr.code == NM_RETURN )
{
if ( tvi.state & TVIS_EXPANDED )
{
W_TreeView_Expand( m_hwndTree, tvi.hItem, TVE_COLLAPSE );
ASSERT(pSiteMapEntry->iImage);
if ( (pSiteMapEntry->iImage>1) && (pSiteMapEntry->iImage <= IMAGE_OPEN_FOLDER_NEW) )
{
pSiteMapEntry->iImage--;
}
}
else
{
W_TreeView_Expand( m_hwndTree, tvi.hItem, TVE_EXPAND );
// The first time we send the TVE_EXPAND message we get a TVIS_ITEMEXPANDING message for the item.
// The TVIS_ITEMEXPANDING message is not sent on subsequent expands of the same item.
if ( tvi.state & TVIS_EXPANDEDONCE )
{
if (pSiteMapEntry->iImage == 0)
pSiteMapEntry->iImage = (BYTE)m_sitemap.GetImageNumber(pSiteMapEntry);
if (pSiteMapEntry->iImage < IMAGE_OPEN_FOLDER_NEW)
pSiteMapEntry->iImage++;
}
}
// Set the correct image
Tree_SetImage(m_hwndTree, pSiteMapEntry->iImage, tvi.hItem);
}
}
break;
case TVN_SELCHANGING:
m_hitemCurHighlight = pnmhdr->itemNew.hItem;
break;
case TVN_SELCHANGED:
m_hitemCurHighlight = pnmhdr->itemNew.hItem;
break;
case NM_CLICK:
/*
* We want a single click to open a topic. We already process
* the case where the selection changes, and we jump if it does.
* However, the user may click an existing selection, in which
* case we want to jump (because the jump may have failed when
* the item was first selected. However, we need to post the
* message so that the treeview control will finish processing
* the click (which could result in a selection change.
*/
if (!m_fSuppressJump) {
ASSERT(::IsValidWindow(m_hwndTree)) ;
TV_HITTESTINFO ht;
GetCursorPos(&ht.pt);
ScreenToClient(m_hwndTree, &ht.pt);
W_TreeView_HitTest(m_hwndTree, &ht);
if (ht.flags & TVHT_ONITEMBUTTON)
break; // just clicking the button, so ignore
TV_ITEMW tvi;
tvi.hItem = ht.hItem;
if (!tvi.hItem)
break; // probably ENTER with no selection
m_hitemCurHighlight = tvi.hItem;
tvi.mask = TVIF_PARAM;
W_TreeView_GetItem(m_hwndTree, &tvi);
pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)tvi.lParam);
PostMessage(FindMessageParent(m_hwndTree), WM_COMMAND, ID_TV_SINGLE_CLICK,
(LPARAM) W_TreeView_GetSelection(m_hwndTree));
}
break;
case TVN_ITEMEXPANDINGA:
case TVN_ITEMEXPANDINGW:
{
if (m_fHack) {
m_fHack = FALSE;
break;
}
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)pnmhdr->itemNew.lParam);
// if click on vacant area of TOC Tree view there is no sitemap entry.
if ( pSiteMapEntry == NULL )
break;
// REVIEW: need to update this to support multiple images
// for multiple levels, and also to support "new" images
if (pnmhdr->action & TVE_EXPAND) {
if ( !(pnmhdr->itemNew.state & TVIS_EXPANDED) )
{
if (pSiteMapEntry->iImage == 0)
pSiteMapEntry->iImage = (BYTE)m_sitemap.GetImageNumber(pSiteMapEntry);
if (pSiteMapEntry->iImage < IMAGE_OPEN_FOLDER_NEW)
pSiteMapEntry->iImage++;
}
else
break;
}
else {
ASSERT(pnmhdr->action & TVE_COLLAPSE);
ASSERT(pSiteMapEntry->iImage);
if ( pnmhdr->itemNew.state & TVIS_EXPANDED )
{
if ( (pSiteMapEntry->iImage>1) && (pSiteMapEntry->iImage <= IMAGE_OPEN_FOLDER_NEW) )
pSiteMapEntry->iImage--;
}
else
break;
}
// Set the correct image
ASSERT(::IsValidWindow(m_hwndTree)) ;
Tree_SetImage(m_hwndTree, pSiteMapEntry->iImage, pnmhdr->itemNew.hItem);
}
break;
case TVN_KEYDOWN:
TV_KEYDOWN* ptvkd;
ptvkd = (TV_KEYDOWN*)pnmhdr;
if ( ptvkd->wVKey != VK_F10 )
break;
else if ( GetKeyState(VK_SHIFT) >= 0 )
break;
else
{
ht.pt.x = ht.pt.y = 0;
ClientToScreen(m_hwndTree, &ht.pt);
goto sim_rclick;
}
break;
case NM_RCLICK:
{
GetCursorPos(&ht.pt);
ScreenToClient(m_hwndTree, &ht.pt);
W_TreeView_HitTest(m_hwndTree, &ht);
if ( ht.hItem )
W_TreeView_Select(m_hwndTree, ht.hItem, TVGN_CARET);
ClientToScreen(m_hwndTree, &ht.pt);
sim_rclick:
HMENU hmenu = CreatePopupMenu();
if (!hmenu)
break;
ASSERT(::IsValidWindow(m_hwndTree)) ;
// NOTICE: Changes here must be reflected in the binary toc verison of this menu
if (!(m_dwStyles & TVS_SINGLEEXPAND)) {
HxAppendMenu(hmenu, MF_STRING, ID_EXPAND_ALL, GetStringResource(IDS_EXPAND_ALL));
HxAppendMenu(hmenu, MF_STRING, ID_CONTRACT_ALL, GetStringResource(IDS_CONTRACT_ALL));
}
if ((m_phh == NULL) || (m_phh && m_phh->m_pCIExpContainer))
HxAppendMenu(hmenu, MF_STRING, ID_PRINT, GetStringResource(IDS_PRINT));
ASSERT( m_pInfoType );
// populate the InfoType member object of the CToc
if ( !m_pInfoType )
{
if (m_phh && m_phh->m_phmData && m_phh->m_phmData->m_pdInfoTypes )
{ // load from the global IT store
m_pInfoType = new CInfoType;
m_pInfoType->CopyTo( m_phh->m_phmData );
// if there are info type bits set by the API assign them here
if ( m_phh->m_phmData->m_pAPIInfoTypes &&
m_pInfoType->AnyInfoTypes(m_phh->m_phmData->m_pAPIInfoTypes) )
{
memcpy(m_pInfoType->m_pInfoTypes,
m_phh->m_phmData->m_pAPIInfoTypes,
m_pInfoType->InfoTypeSize() );
}
}else
{
// no global IT's; load from the .hhc IT store
m_pInfoType = new CInfoType;
*m_pInfoType = m_sitemap;
}
}
else
{
// Set the infotypes bits to set all the types
}
// If there are infotypes add the "customize" option to the popup menu
if (m_pInfoType && m_pInfoType->HowManyInfoTypes() && m_pInfoType->GetFirstHidden() != 1)
HxAppendMenu(hmenu, MF_STRING, ID_CUSTOMIZE_INFO_TYPES,
GetStringResource(IDS_CUSTOMIZE_INFO_TYPES));
if (IsHelpAuthor(FindMessageParent(m_hwndTree))) {
AppendMenu(hmenu, MF_SEPARATOR, 0, 0);
HxAppendMenu(hmenu, MF_STRING, ID_VIEW_ENTRY, pGetDllStringResource(IDS_VIEW_ENTRY));
if (NoRun() == FALSE)
HxAppendMenu(hmenu, MF_STRING, ID_JUMP_URL, GetStringResource(IDS_JUMP_URL));
}
#ifdef _DEBUG
HxAppendMenu(hmenu, MF_STRING, ID_VIEW_MEMORY,
"Debug: memory usage...");
#endif
TrackPopupMenu(hmenu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
ht.pt.x, ht.pt.y, 0, FindMessageParent(m_hwndTree), NULL);
DestroyMenu(hmenu);
return TRUE;
}
break;
case NM_CUSTOMDRAW:
return OnCustomDraw((LPNMTVCUSTOMDRAW) pnmhdr);
}
return FALSE;
}
// This is the message handler for the Tree View containing the Table of Contents.
LRESULT CToc::TreeViewMsg(NM_TREEVIEW* pnmhdr)
{
if ( !m_fBinaryTOC )
return OnSiteMapTVMsg( pnmhdr );
else
return OnBinaryTOCTVMsg ( pnmhdr );
}
BOOL (STDCALL *pResetTocAppearance)(HWND hwndParent, HHA_TOC_APPEARANCE* pappear);
LRESULT CToc::OnCommand(HWND /*hwnd*/, UINT id, UINT uNotifiyCode, LPARAM lParam)
{
if ( m_fBinaryTOC )
return OnBinTOCContentsCommand(id, uNotifiyCode, lParam);
else
return OnSiteMapContentsCommand(id, uNotifiyCode, lParam);
}
LRESULT CToc::OnSiteMapContentsCommand(UINT id, UINT uNotifyCode, LPARAM lParam)
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
switch (id) {
case ID_EXPAND_ALL:
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
m_hitemCurHighlight = W_TreeView_GetSelection(m_hwndTree);
CHourGlass hourglass;
SendMessage(m_hwndTree, WM_SETREDRAW, FALSE, 0);
for (int pos = 1; pos <= m_sitemap.CountStrings(); pos++) {
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(pos);
// If it is not a topic, and the book is closed
TV_ITEMW tvi;
tvi.hItem = m_phTreeItem[pos];
tvi.mask = TVIF_STATE;
W_TreeView_GetItem(m_hwndTree, &tvi);
if (!pSiteMapEntry->IsTopic() && !(tvi.state & TVIS_EXPANDED)) {
m_fHack = TRUE; // ignore expansion notice
W_TreeView_Expand(m_hwndTree, m_phTreeItem[pos], TVE_EXPAND);
if (pSiteMapEntry->iImage < IMAGE_OPEN_FOLDER_NEW)
pSiteMapEntry->iImage++;
Tree_SetImage(m_hwndTree, pSiteMapEntry->iImage, m_phTreeItem[pos]);
}
}
SendMessage(m_hwndTree, WM_SETREDRAW, TRUE, 0);
if (m_hitemCurHighlight) {
m_fSuppressJump = TRUE;
m_fHack = TRUE; // ignore expansion notice
W_TreeView_Select(m_hwndTree, m_hitemCurHighlight, TVGN_FIRSTVISIBLE);
W_TreeView_SelectItem(m_hwndTree, m_hitemCurHighlight);
m_fSuppressJump = FALSE;
}
}
m_fHack = FALSE; // process expansion/contraction normally
return 0;
case ID_CONTRACT_ALL:
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
m_hitemCurHighlight = W_TreeView_GetSelection(m_hwndTree);
SendMessage(m_hwndTree, WM_SETREDRAW, FALSE, 0);
for (int pos = 1; pos <= m_sitemap.CountStrings(); pos++) {
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(pos);
// If it is not a topic, and the book is open
TV_ITEMW tvi;
tvi.hItem = m_phTreeItem[pos];
tvi.mask = TVIF_STATE;
W_TreeView_GetItem(m_hwndTree, &tvi);
if (!pSiteMapEntry->IsTopic() && (tvi.state & TVIS_EXPANDED)) {
m_fHack = TRUE; // ignore contraction notice
W_TreeView_Expand(m_hwndTree, m_phTreeItem[pos], TVE_COLLAPSE);
if (pSiteMapEntry->iImage <= IMAGE_OPEN_FOLDER_NEW)
pSiteMapEntry->iImage--;
Tree_SetImage(m_hwndTree, pSiteMapEntry->iImage, m_phTreeItem[pos]);
}
}
SendMessage(m_hwndTree, WM_SETREDRAW, TRUE, 0);
}
m_fHack = FALSE; // process expansion/contraction normally
return 0;
#ifndef CHIINDEX
case ID_PRINT:
{
if (m_phh) {
if (m_phh->OnTrackNotifyCaller(HHACT_PRINT))
break;
m_phh->OnPrint();
break;
}
CPrint prt(GetParent(m_hwndTree));
prt.SetAction(PRINT_CUR_HEADING);
if (!prt.DoModal())
break;
int action = prt.GetAction();
ASSERT(m_phhctrl);
PrintTopics(action, this,
m_phhctrl->m_pWebBrowserApp, m_phhctrl->m_hwndHelp);
}
return 0;
#endif
case ID_CUSTOMIZE_INFO_TYPES:
{
if ( m_phh && m_phh->m_phmData->m_pTitleCollection->m_pSubSets->GetTocSubset() )
m_phh->m_phmData->m_pTitleCollection->m_pSubSets->m_cur_Set = m_phh->m_phmData->m_pTitleCollection->m_pSubSets->GetTocSubset(); // set this so the wizard knows which subset to load the combo box with.
#if 0 // enable for subset filtering
if (ChooseInformationTypes(m_pInfoType, &(this->m_sitemap),
m_hwndTree, m_phhctrl, m_phh)) {
#else
if (ChooseInformationTypes(m_pInfoType, &(this->m_sitemap),
m_hwndTree, m_phhctrl)) {
#endif
if (m_phh)
m_phh->UpdateInformationTypes();
else {
HWND hwndParent = GetParent(m_hwndTree);
DestroyWindow(m_hwndTree);
// Destroying the TreeView control, make sure we no longer point to it as a valid
// subclassed window.
if (NULL != lpfnlTreeViewWndProc)
{
lpfnlTreeViewWndProc = NULL;
}
Create(hwndParent);
InitTreeView();
}
}
}
break;
case ID_VIEW_ENTRY:
{
TV_ITEMW tvi;
tvi.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvi.hItem)
return 0; // no current selection
tvi.mask = TVIF_PARAM;
W_TreeView_GetItem(m_hwndTree, &tvi);
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)tvi.lParam);
DisplayAuthorInfo(m_pInfoType, &(this->m_sitemap), pSiteMapEntry, FindMessageParent(m_hwndTree), m_phhctrl);
}
return 0;
case ID_JUMP_URL:
{
char szDstUrl[INTERNET_MAX_URL_LENGTH];
CStr cszCurUrl;
if (m_phhctrl)
m_phhctrl->m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
else
m_phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
if (doJumpUrl(GetParent(m_hwndTree), cszCurUrl, szDstUrl) && szDstUrl[0]) {
if (m_phhctrl) {
CWStr cwJump(szDstUrl);
HlinkSimpleNavigateToString(cwJump, NULL,
NULL, m_phhctrl->GetIUnknown(), NULL, NULL, 0, NULL);
}
else {
ChangeHtmlTopic(szDstUrl, GetParent(m_hwndTree));
}
}
}
break;
#ifdef _DEBUG
case ID_VIEW_MEMORY:
OnReportMemoryUsage();
return 0;
#endif
case ID_TV_SINGLE_CLICK:
{
TV_ITEMW tvi;
tvi.mask = TVIF_PARAM;
if (m_hitemCurHighlight == 0 )
break;
tvi.hItem = m_hitemCurHighlight;
W_TreeView_GetItem(m_hwndTree, &tvi);
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)tvi.lParam);
// if (pSiteMapEntry->fShortCut) {
if (pSiteMapEntry->pUrls) {
m_fIgnoreNextSelChange = TRUE;
m_fSuspendSync = TRUE;
if (pSiteMapEntry->fSendEvent && m_phhctrl)
m_phhctrl->SendEvent(m_sitemap.GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
else {
SaveCurUrl(); // so we can restore our state
JumpToUrl(m_pOuter, m_hwndTree, pSiteMapEntry,
m_pInfoType, &(this->m_sitemap), NULL);
}
}
if (m_phh)
{
m_phh->m_hwndControl = m_hwndTree;
}
}
break;
}
return 0;
}
BOOL CToc::Synchronize(LPCSTR pszURL)
{
HRESULT hr;
CTreeNode* pSyncNode, *pCurNode;
if (m_phh && m_phh->curNavType != HHWIN_NAVTYPE_TOC) {
m_fSyncOnActivation = TRUE;
return TRUE; // don't sync if we're not the active tab
}
ASSERT(::IsValidWindow(m_hwndTree)) ;
if (m_fBinaryTOC)
{
BOOL bSynced = FALSE;
CPointerList hier;
LISTITEM *pItem;
ASSERT(m_phh->m_phmData);
ASSERT(!IsBadReadPtr(m_phh->m_phmData, sizeof(CHmData)));
hr = m_phh->m_phmData->m_pTitleCollection->Sync(&hier, pszURL);
if ( SUCCEEDED(hr) )
{
TV_ITEMW hCur;
hCur.hItem = W_TreeView_GetRoot(m_hwndTree);
pItem = hier.First();
pSyncNode = (CTreeNode *)pItem->pItem;
while (hCur.hItem && pSyncNode)
{
hCur.mask = TVIF_PARAM | TVIF_IMAGE;
if (W_TreeView_GetItem(m_hwndTree, &hCur) == FALSE)
break;
pCurNode = (CTreeNode *)hCur.lParam;
if (pSyncNode->Compare(pCurNode) == TRUE)
{
pItem = hier.Next(pItem);
if (pItem == NULL)
{
// just found it
bSynced = TRUE;
break;
}
// found a parent node, expand and find next item
if (pCurNode->m_Expanded == FALSE)
{
if (HandleExpanding(&hCur, m_hwndTree, TVE_EXPAND, &m_fSuspendSync) == FALSE)
break;
if (W_TreeView_Expand(m_hwndTree, hCur.hItem, TVE_EXPAND) == FALSE)
break;
}
hCur.hItem = W_TreeView_GetChild(m_hwndTree, hCur.hItem);
pSyncNode = (CTreeNode *)pItem->pItem;
}
else
hCur.hItem = W_TreeView_GetNextSibling(m_hwndTree, hCur.hItem);
}
if (bSynced == TRUE)
{
W_TreeView_SelectItem(m_hwndTree, hCur.hItem);
}
// clean up memory
for (pItem = hier.First(); pItem; )
{
if (pItem->pItem)
delete pItem->pItem;
pItem = hier.Next(pItem);
}
return bSynced;
}
return FALSE;
}
//
// sitmap syncing code...
//
if (m_fSuspendSync) {
m_fSuspendSync = FALSE;
return TRUE;
}
TCHAR szUrl[MAX_URL];
PSTR pszUrl = szUrl;
if (IsEmptyString(pszURL)) // Avoid crash.
{
return FALSE ;
}
strcpy(pszUrl, pszURL);
PSTR pszSep = strstr(pszUrl, txtDoubleColonSep);
if (pszSep)
strcpy(pszUrl, pszSep + 2);
m_hitemCurHighlight = W_TreeView_GetSelection(m_hwndTree);
TV_ITEMW tvi;
if (m_hitemCurHighlight) {
tvi.mask = TVIF_PARAM;
tvi.hItem = m_hitemCurHighlight;
W_TreeView_GetItem(m_hwndTree, &tvi);
}
else
tvi.lParam = 0;
BOOL fFoundMatch = FALSE;
ConvertBackSlashToForwardSlash(pszUrl);
if (IsCompiledURL(pszUrl)) {
PSTR psz = strstr(pszUrl, txtDoubleColonSep);
ASSERT(psz);
pszUrl = psz + 2;
}
if (pszUrl[0] == '/' && pszUrl[1] != '/')
pszUrl++; // remove the root directive
PSTR pszUrlBookMark = StrChr(pszUrl, '#');
if (pszUrlBookMark)
*pszUrlBookMark++ = '\0';
CStr cszSiteUrl;
// Start from our current position and go forward
for (int pos = (int)tvi.lParam + 1; pos <= m_sitemap.CountStrings(); pos++) {
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(pos);
for (int i = 0; i < pSiteMapEntry->cUrls; i++) {
SITE_ENTRY_URL* pUrl = m_sitemap.GetUrlEntry(pSiteMapEntry, i);
if (pUrl->urlPrimary) {
cszSiteUrl = m_sitemap.GetUrlString(pUrl->urlPrimary);
PSTR pszSiteUrl = cszSiteUrl.psz;
ConvertBackSlashToForwardSlash(pszSiteUrl);
// Bug 2362 we are syncing to a htm file where the same file and path exist
// in two or more other merged chms we could sync to the wrong one. This is
// an acceptable trade off to the reams of changes require to fully fix the bug
PSTR pszSep = strstr(pszSiteUrl, txtDoubleColonSep);
if (pszSep)
strcpy(pszSiteUrl, pszSep + 2);
if (pszSiteUrl[0] == '/' && pszSiteUrl[1] != '/')
pszSiteUrl++; // remove the root directive
PSTR pszSiteBookMark = StrChr(pszSiteUrl, '#');
if (pszSiteBookMark)
*pszSiteBookMark++ = '\0';
if (lstrcmpi(pszUrl, pszSiteUrl) == 0) {
// If both URLS have bookmarks, then they must match
if (pszSiteBookMark && pszUrlBookMark) {
if (lstrcmpi(pszSiteBookMark, pszUrlBookMark) != 0)
continue;
}
fFoundMatch = TRUE;
break;
}
}
}
if (fFoundMatch)
break;
}
// Start from current position - 1, and go backwards
if (!fFoundMatch) {
for (pos = (int)tvi.lParam; pos > 1; pos--) {
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(pos);
for (int i = 0; i < pSiteMapEntry->cUrls; i++) {
SITE_ENTRY_URL* pUrl = m_sitemap.GetUrlEntry(pSiteMapEntry, i);
if (pUrl->urlPrimary) {
cszSiteUrl = m_sitemap.GetUrlString(pUrl->urlPrimary);
PSTR pszSiteUrl = cszSiteUrl.psz;
ConvertBackSlashToForwardSlash(pszSiteUrl);
// Bug 2362 we are syncing to a htm file where the same file and path exist
// in two or more other merged chms we could sync to the wrong one. This is
// an acceptable trade off to the reams of changes require to fully fix the bug
PSTR pszSep = strstr(pszSiteUrl, txtDoubleColonSep);
if (pszSep)
strcpy(pszSiteUrl, pszSep + 2);
if (pszSiteUrl[0] == '/' && pszSiteUrl[1] != '/')
pszSiteUrl++; // remove the root directive
PSTR pszSiteBookMark = StrChr(pszSiteUrl, '#');
if (pszSiteBookMark)
*pszSiteBookMark++ = '\0';
if (lstrcmpi(pszUrl, pszSiteUrl) == 0) {
// If both URLS have bookmarks, then they must match
if (pszSiteBookMark && pszUrlBookMark) {
if (lstrcmpi(pszSiteBookMark, pszUrlBookMark) != 0)
continue;
}
fFoundMatch = TRUE;
break;
}
}
}
if (fFoundMatch)
break;
}
}
if (fFoundMatch) {
m_fSuppressJump = TRUE;
if (m_phTreeItem)
{
W_TreeView_SelectItem(m_hwndTree, m_phTreeItem[pos]);
// For an unknown reason (we suspect a bug in the common control)
// the treeview control does not always paint properly under Thai
// this situation. This code forces a repaint (corrects the
// problem). See HH Bug #5581.
//
if(g_langSystem == LANG_THAI && !g_fSysWinNT)
InvalidateRect(GetParent(m_hwndTree), NULL, FALSE);
}
m_fSuppressJump = FALSE;
}
return fFoundMatch;
}
DWORD CToc::OnCustomDraw(LPNMTVCUSTOMDRAW pnmcdrw)
{
switch (pnmcdrw->nmcd.dwDrawStage) {
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
if (m_sitemap.m_clrBackground != (COLORREF) -1 && !(pnmcdrw->nmcd.uItemState & CDIS_SELECTED))
pnmcdrw->clrTextBk = m_sitemap.m_clrBackground;
if (m_sitemap.m_clrForeground != (COLORREF) -1 && !(pnmcdrw->nmcd.uItemState & CDIS_SELECTED))
pnmcdrw->clrText = m_sitemap.m_clrForeground;
// SetBkMode(pnmcdrw->nmcd.hdc, TRANSPARENT);
break;
}
return CDRF_DODEFAULT;
}
LRESULT WINAPI TreeViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_CHAR: //Process this message to avoid beeps.
if ((wParam == VK_RETURN) || (wParam == VK_TAB))
return 0;
return W_DelegateWindowProc(lpfnlTreeViewWndProc, hwnd, msg, wParam, lParam);
case WM_KEYDOWN:
if (wParam == VK_MULTIPLY)
return 0;
break;
case WM_SYSKEYDOWN:
if ( wParam == VK_LEFT || wParam == VK_RIGHT || wParam == VK_UP || wParam == VK_DOWN )
{
return TRUE;
}
break;
case WM_ERASEBKGND:
{
CToc* pThis = (CToc*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
ASSERT(pThis);
if (pThis && pThis->m_hbmpBackGround) {
RECT rc;
HDC hdc = (HDC) wParam;
GetClientRect(hwnd, &rc);
// GetClipBox(hdc, &rc);
CPalDC dc(pThis->m_hbmpBackGround);
HPALETTE hpalTmp = NULL;
if (pThis->m_hpalBackGround) {
hpalTmp = SelectPalette(hdc,
pThis->m_hpalBackGround, FALSE);
RealizePalette(hdc);
}
for (int left = 0; left <= rc.right; left += pThis->m_cxBackBmp) {
for (int top = 0; top <= rc.bottom; top += pThis->m_cyBackBmp) {
BitBlt((HDC) wParam, left, top, pThis->m_cxBackBmp,
pThis->m_cyBackBmp, dc,
0, 0, SRCCOPY);
}
}
if (hpalTmp)
SelectPalette(hdc, hpalTmp, FALSE);
}
else if (pThis && pThis->m_hbrBackGround) {
RECT rc;
GetClipBox((HDC) wParam, &rc);
FillRect((HDC) wParam, &rc, pThis->m_hbrBackGround);
return TRUE;
}
else
break;
}
return TRUE;
}
return W_DelegateWindowProc(lpfnlTreeViewWndProc, hwnd, msg, wParam, lParam);
}
void CToc::SaveCurUrl(void)
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
TV_ITEMW tvi;
tvi.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvi.hItem)
return; // no current selection
tvi.mask = TVIF_PARAM;
W_TreeView_GetItem(m_hwndTree, &tvi);
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry((int)tvi.lParam);
ASSERT(pSiteMapEntry);
SITE_ENTRY_URL* pUrl = m_sitemap.GetUrlEntry(pSiteMapEntry, 0);
if (pUrl) { // a book/folder may not have an URL to save
if (pUrl->urlPrimary)
m_cszCurUrl = m_sitemap.GetUrlString(pUrl->urlPrimary);
else
m_cszCurUrl = m_sitemap.GetUrlString(pUrl->urlSecondary);
}
}
BOOL HandleExpanding(TVITEMW* pTvi, HWND hwndTreeView, UINT action, BOOL *pSync)
{
CTreeNode* pNode;
ASSERT(::IsValidWindow(hwndTreeView)) ;
if (! (pNode = (CTreeNode *)pTvi->lParam) ) // A pointer into the binary TOC; a CTreeNode
return FALSE;
int iImage = pTvi->iImage;
if (action & TVE_EXPAND)
{
if (pNode->m_Expanded == TRUE)
return TRUE;
pNode->m_Expanded = TRUE;
AddChildren(pTvi, hwndTreeView); // Add the items below the expanding parent
iImage++;
}
else
{
*pSync = FALSE;
pNode->m_Expanded = FALSE;
ASSERT(action & TVE_COLLAPSE);
DeleteChildren(pTvi, hwndTreeView);
if ( iImage )
iImage--;
}
// Set the correct image for the expanding/contracting node
TV_ITEMW tvinfo;
ZeroMemory(&tvinfo, sizeof(tvinfo));
tvinfo.hItem = pTvi->hItem;
tvinfo.iImage = tvinfo.iSelectedImage = iImage;
tvinfo.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
W_TreeView_SetItem(hwndTreeView, &tvinfo);
return TRUE;
}
LRESULT CToc::OnBinaryTOCTVMsg( NM_TREEVIEW *pnmhdr )
{
CTreeNode* pNode;
TV_ITEMW tvItem;
char szTempURL[MAX_URL];
TV_DISPINFO* pdi;
TV_HITTESTINFO ht;
switch(pnmhdr->hdr.code) {
case TVN_GETDISPINFOA: // Tree view wants to draw an item.
case TVN_GETDISPINFOW:
pdi = (TV_DISPINFO*)pnmhdr;
pNode = (CTreeNode *)pdi->item.lParam; // This is a pointer into the binary TOC it is a CTreeNode of some type
if (! pNode )
break;
tvItem.mask = 0;
if( pdi->item.mask & TVIF_CHILDREN )
{
tvItem.cChildren = (pNode->HasChildren())?1:0;
tvItem.mask |= TVIF_CHILDREN;
}
if (pdi->item.mask & TVIF_TEXT)
{
if ( pnmhdr->hdr.code == TVN_GETDISPINFOW )
{
if ( !SUCCEEDED(pNode->GetTopicName((WCHAR*)pdi->item.pszText, pdi->item.cchTextMax)) )
_wcsncpy((WCHAR*)pdi->item.pszText, GetStringResourceW(IDS_UNTITLED), pdi->item.cchTextMax);
}
else
{
if ( !SUCCEEDED(pNode->GetTopicName(pdi->item.pszText, pdi->item.cchTextMax)) )
lstrcpy(pdi->item.pszText, GetStringResource(IDS_UNTITLED));
}
}
break;
case TVN_DELETEITEMA:
case TVN_DELETEITEMW:
break;
case NM_RETURN:
case NM_DBLCLK:
ASSERT(::IsValidWindow(m_hwndTree)) ;
tvItem.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvItem.hItem)
break; // probably ENTER with no selection
tvItem.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN ; // Get the pointer into the Binary TOC stored in the Tree View
W_TreeView_GetItem(m_hwndTree, &tvItem);
pNode = (CTreeNode *)tvItem.lParam;
if (pNode && pNode->GetURL(szTempURL, sizeof(szTempURL)) )
{
m_fSuspendSync = TRUE;
if ( m_phhctrl )
{
m_phhctrl->SendEvent( szTempURL );
return NULL;
}
UpdateTOCSlot(pNode);
ChangeHtmlTopic(szTempURL, m_hwndTree);
if (m_phh)
{
m_phh->m_hwndControl = m_hwndTree;
}
}
// The treeview does not automatically expand the node with the enter key.
// so we do it here.
if ( !g_fIE3 && pnmhdr->hdr.code == NM_RETURN && pNode->HasChildren() )
{
if ( tvItem.state & TVIS_EXPANDED )
{
if (HandleExpanding(&tvItem, m_hwndTree,TVE_COLLAPSE , &m_fSuspendSync))
W_TreeView_Expand( m_hwndTree, tvItem.hItem, TVE_COLLAPSE );
}
else
{
if (HandleExpanding(&tvItem, m_hwndTree,TVE_EXPAND , &m_fSuspendSync))
W_TreeView_Expand( m_hwndTree, tvItem.hItem, TVE_EXPAND );
}
}
break;
case TVN_SELCHANGING:
m_hitemCurHighlight = pnmhdr->itemNew.hItem;
break;
case TVN_SELCHANGED:
m_hitemCurHighlight = pnmhdr->itemNew.hItem;
break;
case NM_CLICK:
/*
* We want a single click to open a topic. We already process
* the case where the selection changes, and we jump if it does.
* However, the user may click an existing selection, in which
* case we want to jump (because the jump may have failed when
* the item was first selected. However, we need to post the
* message so that the treeview control will finish processing
* the click (which could result in a selection change.
*/
if (!m_fSuppressJump)
{
TV_HITTESTINFO ht;
GetCursorPos(&ht.pt);
ASSERT(::IsValidWindow(m_hwndTree)) ;
ScreenToClient(m_hwndTree, &ht.pt);
W_TreeView_HitTest(m_hwndTree, &ht);
if (ht.flags & TVHT_ONITEMBUTTON)
break; // just clicking the button, so ignore
tvItem.hItem = ht.hItem;
if (!tvItem.hItem)
break; // probably ENTER with no selection
tvItem.mask = TVIF_PARAM; // Get the pointer into the Binary TOC stored in the Tree View
W_TreeView_GetItem(m_hwndTree, &tvItem);
pNode = (CTreeNode *)tvItem.lParam;
if (pNode && pNode->GetURL(szTempURL, sizeof(szTempURL)) )
{
m_fSuspendSync = TRUE;
if ( m_phhctrl )
{
m_phhctrl->SendEvent( szTempURL );
return NULL;
}
UpdateTOCSlot(pNode);
ChangeHtmlTopic(szTempURL, GetParent(m_hwndTree));
if (m_phh)
{
m_phh->m_hwndControl = m_hwndTree;
}
}
#if 0
W_TreeView_Select(m_hwndTree, ht.hItem, TVGN_CARET);
tvItem.mask = TVIF_PARAM; // Get the pointer into the binary TOC stored in the Tree View.
W_TreeView_GetItem(m_hwndTree, &tvItem);
// pSiteMapEntry = m_sitemap.GetSiteMapEntry(tvItem.lParam);
PostMessage(FindMessageParent(m_hwndTree), WM_COMMAND, ID_TV_SINGLE_CLICK,
(LPARAM) W_TreeView_GetSelection(m_hwndTree));
#endif
}
break;
case TVN_ITEMEXPANDINGA:
case TVN_ITEMEXPANDINGW:
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
SendMessage(m_hwndTree, WM_SETREDRAW, FALSE, 0);
TV_ITEMW * pitem = (TV_ITEMW *)&pnmhdr->itemNew;
HandleExpanding(pitem, m_hwndTree, pnmhdr->action, &m_fSuspendSync);
}
break;
case TVN_ITEMEXPANDEDA:
case TVN_ITEMEXPANDEDW:
{
SendMessage(m_hwndTree, WM_SETREDRAW, TRUE, 0);
}
break;
case TVN_KEYDOWN:
TV_KEYDOWN* ptvkd;
ptvkd = (TV_KEYDOWN*)pnmhdr;
if ( ptvkd->wVKey != VK_F10 )
break;
else if ( GetKeyState(VK_SHIFT) >= 0 )
break;
else
{
ht.pt.x = ht.pt.y = 0;
ClientToScreen(m_hwndTree, &ht.pt);
goto sim_rclick;
}
break;
case NM_RCLICK:
{
GetCursorPos(&ht.pt);
ScreenToClient(m_hwndTree, &ht.pt);
W_TreeView_HitTest(m_hwndTree, &ht);
if ( ht.hItem )
W_TreeView_Select(m_hwndTree, ht.hItem, TVGN_CARET);
ClientToScreen(m_hwndTree, &ht.pt);
sim_rclick:
HMENU hmenu = CreatePopupMenu();
if (!hmenu)
break;
if (!(m_dwStyles & TVS_SINGLEEXPAND)) {
if (m_phh->m_phmData->m_pTitleCollection->IsSingleTitle()) // no expand all for collections
HxAppendMenu(hmenu, MF_STRING, ID_EXPAND_ALL, GetStringResource(IDS_EXPAND_ALL));
HxAppendMenu(hmenu, MF_STRING, ID_CONTRACT_ALL, GetStringResource(IDS_CONTRACT_ALL));
}
if (m_phh->m_pCIExpContainer)
HxAppendMenu(hmenu, MF_STRING, ID_PRINT, GetStringResource(IDS_PRINT));
ASSERT( m_pInfoType );
// populate the InfoType member object of the CToc
if ( !m_pInfoType )
{
if (m_phh && m_phh->m_phmData && m_phh->m_phmData->m_pdInfoTypes )
{ // load from the global IT store
m_pInfoType = new CInfoType;
m_pInfoType->CopyTo( m_phh->m_phmData );
// if there are info type bits set by the API assign them here
if ( m_phh->m_phmData->m_pAPIInfoTypes &&
m_pInfoType->AnyInfoTypes(m_phh->m_phmData->m_pAPIInfoTypes))
{
memcpy(m_pInfoType->m_pInfoTypes,
m_phh->m_phmData->m_pAPIInfoTypes,
m_pInfoType->InfoTypeSize() );
}
}else
{
// no global IT's; load from the .hhc IT store
m_pInfoType = new CInfoType;
*m_pInfoType = m_sitemap;
}
}
else
{
// Set the infotypes bits to set all the types
}
#if 0 // not in 1.1b
// If there are infotypes add the "customize" option to the popup menu
if (m_pInfoType && m_pInfoType->HowManyInfoTypes() && m_pInfoType->GetFirstHidden() != 1)
HxAppendMenu(hmenu, MF_STRING, ID_CUSTOMIZE_INFO_TYPES, GetStringResource(IDS_CUSTOMIZE_INFO_TYPES));
#endif
ASSERT(::IsValidWindow(m_hwndTree)) ;
if (NoRun() == FALSE)
{
AppendMenu(hmenu, MF_SEPARATOR, 0, 0);
HxAppendMenu(hmenu, MF_STRING, ID_JUMP_URL, GetStringResource(IDS_JUMP_URL));
}
// AppendMenu(hmenu, MF_STRING, ID_VIEW_ENTRY, pGetDllStringResource(IDS_VIEW_ENTRY));
#ifdef _DEBUG
HxAppendMenu(hmenu, MF_STRING, ID_VIEW_MEMORY, "Debug: memory usage...");
#endif
TrackPopupMenu(hmenu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
ht.pt.x, ht.pt.y, 0, FindMessageParent(m_hwndTree), NULL);
DestroyMenu(hmenu);
return TRUE;
}
break;
case NM_CUSTOMDRAW:
return OnCustomDraw((LPNMTVCUSTOMDRAW) pnmhdr);
}
return FALSE;
}
void CToc::UpdateTOCSlot(CTreeNode* pNode)
{
DWORD dwSlot = 0;
CTreeNode* pTmpNode, *pTmpNode2;
CExTitle* pTitle;
//
// What a damn hack I've had to put in below. Somehow I had to get a slot number for these nodes in order to get
// topic centricity working 100% correctly. Should we ever decide to to the binary TOC UI code right we really
// should only store slots in the tree control and we could do away with all the silly new and deletes on tree
// nodes. oh well...
//
if (m_phh && m_phh->m_phmData && m_phh->m_phmData->m_pTitleCollection )
{
if ( (pTmpNode = m_phh->m_phmData->m_pTitleCollection->GetPrev(pNode)) )
{
if ( (pTmpNode2 = m_phh->m_phmData->m_pTitleCollection->GetNextTopicNode(pTmpNode, &dwSlot)) )
{
if ( dwSlot && pTmpNode2->GetObjType() == EXNODE)
{
if ( (pTitle = ((CExNode*)pTmpNode2)->GetTitle()) )
m_phh->m_phmData->m_pTitleCollection->SetTopicSlot(dwSlot,((CExNode*)pTmpNode2)->m_Node.dwOffsTopic, pTitle);
}
delete pTmpNode2;
}
delete pTmpNode;
}
}
}
// Public class member called to refresh the TOC view.
//
void CToc::Refresh(void)
{
HTREEITEM hNode;
TVITEMW Tvi;
if (! m_hwndTree )
return;
if ( m_fBinaryTOC )
{
//
// First, free all the CTreeNodes...
//
hNode = W_TreeView_GetRoot(m_hwndTree);
while ( hNode )
{
FreeChildrenAllocations(m_hwndTree, hNode);
hNode = W_TreeView_GetNextSibling(m_hwndTree, hNode);
}
Tvi.hItem = hNode;
Tvi.mask = TVIF_PARAM;
if ( W_TreeView_GetItem(m_hwndTree, &Tvi) )
{
if ( Tvi.lParam )
delete ((CTreeNode *)Tvi.lParam);
}
//
// Second, delete the items (visual elements) from the CTreeControl
//
W_TreeView_DeleteAllItems(m_hwndTree);
//
// Lastly, reload the root.
//
LoadFirstLevel(m_pBinTOCRoot, m_hwndTree, &m_tiFirstVisible);
}
else
{
HWND hwndParent = GetParent(m_hwndTree);
DestroyWindow(m_hwndTree);
// Destroying the TreeView control, make sure we no longer point to it as a valid
// subclassed window.
if (NULL != lpfnlTreeViewWndProc)
{
lpfnlTreeViewWndProc = NULL;
}
Create(hwndParent);
InitTreeView();
}
}
// Helper function for adding the first level to a tree view.
void LoadFirstLevel( CTreeNode *pRoot, HWND hwndTreeView, HTREEITEM *m_tiFirstVisible )
{
CTreeNode *pTempNode = pRoot->GetFirstChild();
ASSERT(::IsValidWindow(hwndTreeView)) ;
CHourGlass wait;
while (pTempNode != NULL )
{
*m_tiFirstVisible = AddNode(pTempNode, TVI_ROOT, hwndTreeView);
pTempNode = pTempNode->GetNextSibling();
}
}
// Helper functions for adding all the children to a parent node in a tree view.
//
HTREEITEM AddTitleChildren(CTreeNode *pNode, HTREEITEM hParent, HWND hwndTreeView)
{
CTreeNode *pTempNode;
HTREEITEM hItem = NULL;
CHourGlass wait;
pTempNode = pNode->GetFirstChild();
while (pTempNode != NULL )
{
hItem = AddNode(pTempNode, hParent, hwndTreeView);
pTempNode = pTempNode->GetNextSibling();
}
return hItem;
}
HTREEITEM AddNode(CTreeNode *pNode, HTREEITEM hParent, HWND hwndTreeView)
{
if (pNode->GetObjType() == EXTITLENODE)
{
return AddTitleChildren(pNode, hParent, hwndTreeView);
}
TV_INSERTSTRUCTW tcAdd;
unsigned uType;
tcAdd.hInsertAfter = TVI_LAST;
tcAdd.hParent = hParent;
uType = pNode->GetType();
if ( uType == TOPIC )
if (pNode->IsNew())
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 11;
else
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 10;
else if ( uType == CONTAINER )
if (pNode->IsNew())
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 2;
else
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 0;
else
if (pNode->IsNew())
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 2;
else
tcAdd.item.iImage = tcAdd.item.iSelectedImage = 0;
tcAdd.item.hItem = NULL;
tcAdd.item.lParam = (LONG_PTR)pNode;
tcAdd.item.cChildren = (pNode->HasChildren())?1:0;
tcAdd.item.pszText = LPSTR_TEXTCALLBACKW;
tcAdd.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM;
return W_TreeView_InsertItem(hwndTreeView, &tcAdd);
}
void AddChildren( TVITEMW* pTvi, HWND hwndTreeView )
{
CTreeNode *pNode;
CTreeNode *pTempNode;
TV_ITEM tvItem;
HTREEITEM hItem;
ASSERT(::IsValidWindow(hwndTreeView)) ;
if (! (pNode = (CTreeNode*)pTvi->lParam) )
return;
tvItem.hItem = pTvi->hItem;
if (!tvItem.hItem)
return;
CHourGlass wait;
pTempNode = pNode->GetFirstChild();
// Before we add. Delete the dummy kid.
//
if ( (hItem = W_TreeView_GetChild(hwndTreeView, pTvi->hItem)) )
W_TreeView_DeleteItem(hwndTreeView, hItem);
while (pTempNode != NULL )
{
AddNode(pTempNode, pTvi->hItem, hwndTreeView);
pTempNode = pTempNode->GetNextSibling();
}
}
void FreeChildrenAllocations(HWND hwndTreeView, HTREEITEM ti)
{
HTREEITEM tiChild;
CTreeNode *pCurNode;
TV_ITEMW hCur;
if ( IsValidWindow(hwndTreeView) )
{
while ((tiChild = W_TreeView_GetChild(hwndTreeView, ti)) != NULL)
{
ZeroMemory(&hCur, sizeof(TV_ITEM));
hCur.hItem = tiChild;
hCur.mask = TVIF_PARAM;
if (W_TreeView_GetItem(hwndTreeView, &hCur) == FALSE)
continue;
FreeChildrenAllocations(hwndTreeView, tiChild);
if ((hCur.mask & TVIF_PARAM) &&hCur.lParam)
{
pCurNode = (CTreeNode *)hCur.lParam;
delete pCurNode;
}
W_TreeView_DeleteItem(hwndTreeView, tiChild);
}
}
}
void DeleteChildren( TVITEMW* pTvi, HWND hwndTreeView )
{
TV_INSERTSTRUCTW tcAdd;
CHourGlass wait;
ASSERT(::IsValidWindow(hwndTreeView)) ;
FreeChildrenAllocations(hwndTreeView, pTvi->hItem);
//
// After we've deleted, add the dummk kid back.
//
ZeroMemory(&tcAdd, sizeof(TV_INSERTSTRUCT));
tcAdd.hInsertAfter = TVI_LAST;
tcAdd.hParent = pTvi->hItem;
W_TreeView_InsertItem(hwndTreeView, &tcAdd);
}
// This is the Contents Command Handler for the Binary TOC
LRESULT CToc::OnBinTOCContentsCommand(UINT id, UINT uNotifyCode, LPARAM lParam )
{
ASSERT(::IsValidWindow(m_hwndTree)) ;
switch (id)
{
case ID_EXPAND_ALL:
{
m_hitemCurHighlight = W_TreeView_GetSelection(m_hwndTree);
CTreeNode* pNode;
TV_ITEMW tvItem;
HTREEITEM hNext;
DWORD dwCurLevel = 0;
HTREEITEM hParents[50];
tvItem.hItem = W_TreeView_GetRoot(m_hwndTree);
CHourGlass wait;
while ( tvItem.hItem)
{
tvItem.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN ; // Get the pointer into the Binary TOC stored in the Tree View
W_TreeView_GetItem(m_hwndTree, &tvItem);
pNode = (CTreeNode *)tvItem.lParam;
if (pNode->HasChildren() == FALSE)
goto GetNext;
if (pNode->m_Expanded == TRUE)
goto GetNext;
pNode->m_Expanded = TRUE;
AddChildren(&tvItem, m_hwndTree); // Add the items below the expanding parent
W_TreeView_Expand( m_hwndTree, tvItem.hItem, TVE_EXPAND );
// Set the correct image for the expanding/contracting node
tvItem.iImage++;
tvItem.iSelectedImage++;
tvItem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
W_TreeView_SetItem(m_hwndTree, &tvItem);
GetNext:
if (hNext = W_TreeView_GetChild(m_hwndTree, tvItem.hItem))
{
hParents[dwCurLevel] = tvItem.hItem;
tvItem.hItem = hNext;
dwCurLevel++;
}
else if (hNext = W_TreeView_GetNextSibling(m_hwndTree, tvItem.hItem))
tvItem.hItem = hNext;
else
{
// go up the parent tree
while (TRUE)
{
dwCurLevel--;
if (dwCurLevel == -1)
{
tvItem.hItem = NULL;
break;
}
else
{
if (hNext = W_TreeView_GetNextSibling(m_hwndTree, hParents[dwCurLevel]))
{
tvItem.hItem = hNext;
break;
}
}
}
}
}
if (m_hitemCurHighlight)
{
m_fSuppressJump = TRUE;
W_TreeView_Select(m_hwndTree, m_hitemCurHighlight,
TVGN_FIRSTVISIBLE);
W_TreeView_SelectItem(m_hwndTree, m_hitemCurHighlight);
m_fSuppressJump = FALSE;
}
}
return 0;
case ID_CONTRACT_ALL:
{
CHourGlass wait;
SendMessage(m_hwndTree, WM_SETREDRAW, FALSE, 0);
CTreeNode* pNode;
TV_ITEMW tvItem;
HTREEITEM hNext;
tvItem.hItem = m_hitemCurHighlight = W_TreeView_GetRoot(m_hwndTree);
while ( tvItem.hItem)
{
tvItem.mask = TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN ; // Get the pointer into the Binary TOC stored in the Tree View
W_TreeView_GetItem(m_hwndTree, &tvItem);
pNode = (CTreeNode *)tvItem.lParam;
if (pNode->HasChildren() == FALSE)
goto GetNextSibling;
if (pNode->m_Expanded == FALSE)
goto GetNextSibling;
pNode->m_Expanded = FALSE;
DeleteChildren(&tvItem, m_hwndTree);
W_TreeView_Expand( m_hwndTree, tvItem.hItem, TVE_COLLAPSE );
// Set the correct image for the expanding/contracting node
tvItem.iImage--;
tvItem.iSelectedImage--;
tvItem.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
W_TreeView_SetItem(m_hwndTree, &tvItem);
GetNextSibling:
if (hNext = W_TreeView_GetNextSibling(m_hwndTree, tvItem.hItem))
tvItem.hItem = hNext;
else
tvItem.hItem = NULL;
}
if (m_hitemCurHighlight)
{
m_fSuppressJump = TRUE;
W_TreeView_Select(m_hwndTree, m_hitemCurHighlight,
TVGN_FIRSTVISIBLE);
W_TreeView_SelectItem(m_hwndTree, m_hitemCurHighlight);
m_fSuppressJump = FALSE;
}
m_fHack = FALSE; // process expansion/contraction normally
}
SendMessage(m_hwndTree, WM_SETREDRAW, TRUE, 0);
return 0;
#if 1
case ID_CUSTOMIZE_INFO_TYPES:
{
if (m_phh->m_phmData->m_pTitleCollection->m_pSubSets->GetTocSubset())
m_phh->m_phmData->m_pTitleCollection->m_pSubSets->m_cur_Set = m_phh->m_phmData->m_pTitleCollection->m_pSubSets->GetTocSubset(); // set this so the wizard knows which subset to load the combo box with.
#if 0
if (ChooseInformationTypes(m_pInfoType, &(this->m_sitemap), m_hwndTree, m_phhctrl, m_phh)) {
#else
if (ChooseInformationTypes(m_pInfoType, &(this->m_sitemap), m_hwndTree, m_phhctrl)) {
#endif
if (m_phh)
m_phh->UpdateInformationTypes();
else {
HWND hwndParent = GetParent(m_hwndTree);
DestroyWindow(m_hwndTree);
// Destroying the TreeView control, make sure we no longer point to it as a valid
// subclassed window.
if (NULL != lpfnlTreeViewWndProc)
{
lpfnlTreeViewWndProc = NULL;
}
Create(hwndParent);
InitTreeView();
}
}
}
break;
#endif
#ifndef CHIINDEX
case ID_PRINT:
{
TV_ITEM tvi;
tvi.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvi.hItem)
return 0; // no current selection
if (m_phh) {
if (m_phh->OnTrackNotifyCaller(HHACT_PRINT))
break;
m_phh->OnPrint();
break;
}
CPrint prt(GetParent(m_hwndTree));
prt.SetAction(PRINT_CUR_HEADING);
if (!prt.DoModal())
break;
int action = prt.GetAction();
ASSERT(m_phhctrl);
PrintTopics(action, this,
m_phhctrl->m_pWebBrowserApp, m_phhctrl->m_hwndHelp);
}
return 0;
#endif
#if 0
case ID_VIEW_ENTRY:
{
TV_ITEM tvi;
tvi.hItem = W_TreeView_GetSelection(m_hwndTree);
if (!tvi.hItem)
return 0; // no current selection
tvi.mask = TVIF_PARAM;
W_TreeView_GetItem(m_hwndTree, &tvi);
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(tvi.lParam);
DisplayAuthorInfo(&(this->m_sitemap), pSiteMapEntry, FindMessageParent(m_hwndTree), m_phhctrl);
}
return 0;
#endif
case ID_JUMP_URL:
{
char szDstUrl[INTERNET_MAX_URL_LENGTH];
CStr cszCurUrl;
if (m_phhctrl)
m_phhctrl->m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
else
m_phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszCurUrl);
if (doJumpUrl(GetParent(m_hwndTree), cszCurUrl, szDstUrl)) {
if (m_phhctrl) {
CWStr cwJump(szDstUrl);
HlinkSimpleNavigateToString(cwJump, NULL,
NULL, m_phhctrl->GetIUnknown(), NULL, NULL, 0, NULL);
}
else {
ChangeHtmlTopic(szDstUrl, GetParent(m_hwndTree));
}
}
}
break;
#ifdef _DEBUG
case ID_VIEW_MEMORY:
OnReportMemoryUsage();
return 0;
#endif
#if 0
case ID_TV_SINGLE_CLICK:
{
TV_ITEM tvi;
tvi.mask = TVIF_PARAM;
tvi.hItem = m_hitemCurHighlight;
W_TreeView_GetItem(m_hwndTree, &tvi);
SITEMAP_ENTRY* pSiteMapEntry = m_sitemap.GetSiteMapEntry(tvi.lParam);
// if (pSiteMapEntry->fShortCut) {
if (pSiteMapEntry->pUrls) {
m_fIgnoreNextSelChange = TRUE;
m_fSuspendSync = TRUE;
if (pSiteMapEntry->fSendEvent && m_phhctrl)
m_phhctrl->SendEvent(m_sitemap.GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
else {
SaveCurUrl(); // so we can restore our state
JumpToUrl(m_pOuter, m_hwndTree, pSiteMapEntry, &(this->m_sitemap), NULL);
}
if (m_phh)
{
m_phh->m_hwndControl = m_hwndTree;
}
}
}
break;
#endif
}
return 0;
}
///////////////////////////////////////////////////////////
//
// INavUI Interface Implementation
//
///////////////////////////////////////////////////////////
//
// OnNotify
//
LRESULT
CToc::OnNotify(HWND /*hwnd*/, WPARAM /*wParam*/, LPARAM lParam)
{
if (::IsValidWindow(m_hwndTree))
{
#ifdef _DEBUG
BOOL f = TreeView_GetUnicodeFormat(m_hwndTree);
#endif
TreeViewMsg((NM_TREEVIEW*) lParam);
}
return 1;
}
///////////////////////////////////////////////////////////
//
// SetDefaultFocus
//
void
CToc::SetDefaultFocus()
{
if (::IsValidWindow(m_hwndTree))
{
if (m_fSyncOnActivation) // Move this to the new activation function.
{
//PostMessage(GetParent(GetParent(m_hwndTree)), WM_COMMAND, IDTB_SYNC, 0); // Verify: This was a post message.
// HH Bug 2160: Sending the IDTB_SYNC message causes the TOC tab to get selected.
// We don't want to select the TOC tab, but mark this thing as needing to be sync'ed.
if (m_phh && m_phh->m_pCIExpContainer && m_phh->m_pCIExpContainer->m_pWebBrowserApp)
{
CStr cszUrl;
m_phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl);
if (!cszUrl.IsEmpty())
{
m_fSyncOnActivation = FALSE;
Synchronize(cszUrl);
}
}
}
SetFocus(m_hwndTree );
}
}
///////////////////////////////////////////////////////////
//
// Other Classes
//
///////////////////////////////////////////////////////////
//
// CJumpUrl
//
class CJumpUrl : public CDlg
{
public:
CJumpUrl(HWND hwndParent, PCSTR pszCurUrl) : CDlg(hwndParent, IDDLG_JUMP_URL) {
m_pszCurUrl = pszCurUrl;
}
BOOL OnBeginOrEnd();
void OnEditChange(UINT id);
PCSTR m_pszCurUrl;
CStr m_cszJumpUrl;
};
BOOL doJumpUrl(HWND hwndParent, PCSTR pszCurUrl, PSTR pszDstUrl)
{
CJumpUrl jump(hwndParent, pszCurUrl);
if (jump.DoModal()) {
strcpy(pszDstUrl, jump.m_cszJumpUrl);
return TRUE;
}
else
return FALSE;
}
void CJumpUrl::OnEditChange(UINT id)
{
if (id == IDEDIT_JUMP_URL)
{
m_cszJumpUrl.GetText(*this, IDEDIT_JUMP_URL);
if (m_cszJumpUrl.psz[0])
{
EnableWindow(IDOK, TRUE);
}
else
{
EnableWindow(IDOK, FALSE);
}
}
}
BOOL CJumpUrl::OnBeginOrEnd()
{
if (m_fInitializing) {
SetWindowText(IDEDIT_CUR_URL, m_pszCurUrl);
SendMessage(IDEDIT_JUMP_URL, WM_SETFONT, (WPARAM)_Resource.GetUIFont(), 0);
EnableWindow(IDOK, FALSE);
}
else {
m_cszJumpUrl.GetText(*this, IDEDIT_JUMP_URL);
if (!StrChr(m_cszJumpUrl, CH_COLON) && m_pszCurUrl && strstr(m_pszCurUrl, "::")) {
CStr csz(m_pszCurUrl);
PSTR psz = strstr(csz, "::");
ASSERT(psz);
psz += 2;
*psz = '\0';
if (m_cszJumpUrl.psz[0] != CH_FORWARDSLASH && m_cszJumpUrl.psz[0] != CH_BACKSLASH)
csz += "/";
csz += m_cszJumpUrl.psz;
m_cszJumpUrl = csz.psz;
}
}
return TRUE;
}