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