// 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 #include "htmlhelp.h" #include "secwin.h" #include "cpaldc.h" #include "cprint.h" #include #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; }