// Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved. // Precompiled header #include "header.h" #include "state.h" #include "cctlww.h" #ifdef _DEBUG #undef THIS_FILE static const char THIS_FILE[] = __FILE__; #endif /////////////////////////////////////////////////////////// // // Includes // #include "secwin.h" // Header for this file. #include "hha_strtable.h" #include "contain.h" #include "highlite.h" #include "resource.h" // needed for subset picker combo control ID. #include "subset.h" // Needed to dealing with CStructucturalSubset object. // Advanced Search UI header. #include "adsearch.h" #include "search.h" // Bookmarks Nav Pane #include "bookmark.h" // Custom NavPane #include "custmtab.h" // Sizebar class #include "sizebar.h" #define ACCESS_KEY '&' static const char txtAccessKey[] = "&"; BOOL HxInsertMenuItem(HMENU, UINT, BOOL, MENUITEMINFOA *); /////////////////////////////////////////////////////////// // // Globals // // Pointer to global array of window types. CHHWinType** pahwnd = NULL; AUTO_CLASS_COUNT_CHECK( CHHWinType ); /////////////////////////////////////////////////////////// // // Function Implementation // /*************************************************************************** FUNCTION: GetCurrentCollection PURPOSE: Returns the currect collection PARAMETERS: None. RETURNS: Pointer to the currect collection (CExCollection) COMMENTS: This function returns the current collection based on the current active window and window type. Use this function anytime you need a pointer to the currect active collection when you can assume that the collection is already loaded. MODIFICATION DATES: 15-Sept-1997 [paulti] 29-April-1998 [mikecole] As per agreement of all hhctrl devs I am adding a .CHM filespec argument to this function. Since it is possible for a single task to utilize hhctrl services on multiple CExCollections we will distinguish CExCollections from one another by using a .CHM filespec. ***************************************************************************/ CExCollection* GetCurrentCollection( HWND hwnd, LPCSTR lpszChmFilespec ) { CExCollection* pCExCol; PSTR psz; TCHAR szFN[MAX_PATH]; TCHAR szFN2[MAX_PATH]; int i = 0; szFN[0] = '\0'; if ( lpszChmFilespec ) { // // First, we need to normalize the filespec. This thing can come to us in any number of // forms, it could be a URL, it could be an unqualified filename, a fully qualified path... // if ( psz = stristr(lpszChmFilespec, txtDefExtension) ) { while ( *psz != ' ' && *psz != '/' && *psz != '\\' && *psz != '@' && *psz != '\0' && *psz != ':' && (psz != lpszChmFilespec) ) { psz = CharPrev(lpszChmFilespec, psz); i++; if(IsDBCSLeadByte(*CharNext(psz))) i++; } if ( psz != lpszChmFilespec ) psz++; else i++; lstrcpyn(szFN, psz, i); } // // Next, see if the filespec matches a single title .CHM or and merged .CHMs of a single title .CHM. // if ( szFN[0] ) { for (int i = 0; i < g_cHmSlots; i++) { if ( g_phmData[i] && g_phmData[i]->m_pTitleCollection && g_phmData[i]->m_pTitleCollection->IsSingleTitle() ) { // // Search title list for a match. // CExTitle* pTitle; pCExCol = g_phmData[i]->m_pTitleCollection; pTitle = pCExCol->GetFirstTitle(); while ( pTitle ) { _splitpath((LPCSTR)pTitle->GetContentFileName(), NULL, NULL, szFN2, NULL); if (! lstrcmpi(szFN, szFN2) ) return g_phmData[i]->m_pTitleCollection; pTitle = pTitle->GetNext(); } } } } } // // Last resort... // if ( g_pCurrentCollection ) return g_pCurrentCollection; else if ( g_phmData && g_phmData[0] ) return g_phmData[0]->m_pTitleCollection; else return NULL; // Ohhh, very bad! } /*************************************************************************** FUNCTION: GetCurrentURL PURPOSE: Returns the currect URL PARAMETERS: None. RETURNS: TRUE if found with pcszCurrentURL filed in, otherwise FALSE. COMMENTS: This function returns the current URL based on the current active window and window type. MODIFICATION DATES: 10-Dec-1997 [paulti] ***************************************************************************/ BOOL GetCurrentURL( CStr* pcszCurrentURL, HWND hwnd ) { ASSERT(pahwnd); CHHWinType* phh = NULL; BOOL bFound = FALSE; // if anyone can find a guarenteed way to get the current // URL please modify the code below [paulti] if( !hwnd ) hwnd = GetActiveWindow(); phh = FindHHWindowIndex(hwnd); if( phh && phh->m_pCIExpContainer && phh->m_pCIExpContainer->m_pWebBrowserApp ) { phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL( pcszCurrentURL ); bFound = TRUE; } return bFound; } HFONT CHHWinType::GetContentFont() { if ( m_phmData ) { CExTitle* pTitle = m_phmData->m_pTitleCollection->GetMasterTitle(); return (pTitle->GetInfo()->GetContentFont()); } else return _Resource.GetUIFont(); // This would be highly unusual! } HFONT CHHWinType::GetAccessableContentFont() { if ( m_phmData ) { CExTitle* pTitle = m_phmData->m_pTitleCollection->GetMasterTitle(); return (pTitle->GetInfo()->GetAccessableContentFont()); } else return _Resource.GetUIFont(); // This would be highly unusual! } INT CHHWinType::GetContentCharset() { if ( m_phmData ) { CExTitle* pTitle = m_phmData->m_pTitleCollection->GetMasterTitle(); return (pTitle->GetInfo()->GetTitleCharset()); } else return ANSI_CHARSET; // This would be highly unusual! } UINT CHHWinType::GetCodePage(void) { if ( m_phmData ) { CExTitle* pTitle = m_phmData->m_pTitleCollection->GetMasterTitle(); return (pTitle->GetInfo()->GetCodePage()); } else return 0; // This would be highly unusual! } /*************************************************************************** FUNCTION: CHHWinType::SetString PURPOSE: Set a window type string PARAMETERS: pszSrcString ppszDst RETURNS: COMMENTS: If string is non-NULL and non-empty, frees any previous string memory and allocates and copies the string. MODIFICATION DATES: 09-Sep-1997 [ralphw] ***************************************************************************/ void CHHWinType::SetString(PCSTR pszSrcString, PSTR* ppszDst) { if (!pszSrcString) return; CStr csz ; if (IsUniCodeStrings()) csz = (WCHAR*) pszSrcString; else csz = pszSrcString; if (csz.IsNonEmpty()) { if (*ppszDst) lcFree(*ppszDst); csz.TransferPointer(ppszDst); } } /*************************************************************************** FUNCTION: CHHWinType::SetUrl PURPOSE: Set a window type URL PARAMETERS: pszSrcString ppszDst RETURNS: COMMENTS: If string is non-NULL and non-empty, frees any previous string memory and allocates and copies the string. If the string contains a compiled HTML filename, then the URL is converted into a full path. MODIFICATION DATES: 09-Sep-1997 [ralphw] ***************************************************************************/ void CHHWinType::SetUrl(PCSTR pszSrcString, PSTR* ppszDst) { if (!pszSrcString) return; CStr csz; if (IsUniCodeStrings()) csz = (WCHAR*) pszSrcString; else csz = pszSrcString; if (csz.IsNonEmpty()) { if (*ppszDst) lcFree(*ppszDst); CStr cszFull; if (IsCompiledHtmlFile(csz, &cszFull)) cszFull.TransferPointer(ppszDst); else csz.TransferPointer(ppszDst); } } void CHHWinType::SetTypeName(HH_WINTYPE* phhWinType) { SetString(phhWinType->pszType, (PSTR*) &pszType); if (pszType && *pszType == '>') strcpy((PSTR) pszType, pszType + 1); } /********************************************************** FUNCTION SetJump1 NOTES The button caption pszJump1 can be empty. The URL cannot. ***********************************************************/ void CHHWinType::SetJump1(HH_WINTYPE* phhWinType) { if (!(fsToolBarFlags & HHWIN_BUTTON_JUMP1) || (phhWinType->pszUrlJump1 == NULL)) return; SetString(phhWinType->pszJump1, (PSTR*) &pszJump1); SetUrl(phhWinType->pszUrlJump1, (PSTR*) &pszUrlJump1); } /********************************************************** FUNCTION SetJump2 NOTES The button caption pszJump1 can be empty. The URL cannot. ***********************************************************/ void CHHWinType::SetJump2(HH_WINTYPE* phhWinType) { if (!(fsToolBarFlags & HHWIN_BUTTON_JUMP2) || (phhWinType->pszUrlJump2 == NULL)) return; SetString(phhWinType->pszJump2, (PSTR*) &pszJump2); SetUrl(phhWinType->pszUrlJump2, (PSTR*) &pszUrlJump2); } /********************************************************** FUNCTION SetTabOrder NOTES ***********************************************************/ void CHHWinType::SetTabOrder(HH_WINTYPE* phhWinType) { // REVIEW: We need to be able to loop true this array and find tabs. // This means that we need some way to determine the upper most array entry. // This is harder in the user defined case...[14 Jan 98] if (IsValidMember(HHWIN_PARAM_TABORDER)) memcpy(tabOrder, phhWinType->tabOrder, sizeof(tabOrder)); else { for (int j = HH_TAB_FAVORITES + 1; j < HH_TAB_CUSTOM_FIRST; j++) tabOrder[j] = -1; // clear empty slots tabOrder[HH_TAB_CONTENTS] = HH_TAB_CONTENTS; tabOrder[HH_TAB_INDEX] = HH_TAB_INDEX; tabOrder[HH_TAB_SEARCH] = HH_TAB_SEARCH; tabOrder[HH_TAB_HISTORY] = HH_TAB_HISTORY; tabOrder[HH_TAB_FAVORITES] = HH_TAB_FAVORITES; #ifdef __TEST_CUSTOMTAB__ tabOrder[HH_TAB_AUTHOR] = HH_TAB_AUTHOR; // hha.dll supplied tab #endif // Setup the default tab order for the custom tabs. for (int i = HH_TAB_CUSTOM_FIRST; i <= HH_TAB_CUSTOM_LAST; i++) tabOrder[i] = (BYTE)i; // This member is now valid. Mark it as such. fsValidMembers |= HHWIN_PARAM_TABORDER ; } } ////////////////////////////////////////////////////////////////////////// // // // DWORD CHHWinType::GetStyles() const { DWORD style = NULL ; if (IsValidMember(HHWIN_PARAM_STYLES)) { style = dwStyles ; } if (!IsProperty(HHWIN_PROP_NODEF_STYLES)) { style |= DEFAULT_STYLE ; } if (!IsProperty(HHWIN_PROP_NOTITLEBAR)) { style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ; } return style ; } void CHHWinType::GetClientRect(RECT* prc) { ::GetClientRect(hwndHelp, prc); if (IsValidWindow(hwndToolBar)) { RECT rc; ::GetWindowRect(hwndToolBar, &rc); prc->top += RECT_HEIGHT(rc); } } void CHHWinType::CalcHtmlPaneRect(void) { ::GetClientRect(hwndHelp, &rcHTML); // the total size of the help window if (IsValidWindow(hwndToolBar)) { ::GetWindowRect(hwndToolBar, &rcToolBar); rcHTML.top += RECT_HEIGHT(rcToolBar); if (m_fNotesWindow) { int height = RECT_HEIGHT(rcNotes); CopyRect(&rcNotes, &rcHTML); if (!height) height = DEFAULT_NOTES_HEIGHT; rcNotes.bottom = rcNotes.top + height; rcHTML.top = rcNotes.bottom; if (IsExpandedNavPane()) rcNotes.left += RECT_WIDTH(rcNav); } } if (IsExpandedNavPane() && !IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { if( hwndNavigation ) ::GetClientRect(hwndNavigation, &rcNav); if (m_pSizeBar) { rcHTML.left += m_pSizeBar->Width() + RECT_WIDTH(rcNav); } else { rcHTML.left += RECT_WIDTH(rcNav); } } rcNav.top = m_fNotesWindow ? rcNotes.top : rcHTML.top; if ( m_hWndSSCB ) rcNav.top += m_iSSCBHeight; rcNav.bottom = rcHTML.bottom; } // Wrap the toolbar void CHHWinType::WrapTB() { extern SHORT g_tbRightMargin; extern SHORT g_tbLeftMargin; int cRows, cButtons; RECT btnRc; int btnWidth=0; int btnspace; int btnsperrow; cButtons = (int)SendMessage(hwndToolBar, TB_BUTTONCOUNT, 0, 0); if (cButtons == 0) { ASSERT(cButtons != 0) ; // Should never happen. return ; } if (fsToolBarFlags & HHWIN_BUTTON_EXPAND) cButtons--; ::GetWindowRect(hwndHelp, &rcWindowPos); for ( int i=0; (btnWidth==0)&&(i RECT_HEIGHT(rcToolBar)/RECT_HEIGHT(btnRc) ) { WPARAM wParam = MAKEWPARAM( cRows, TRUE); SendMessage(hwndToolBar, TB_SETROWS, wParam, (LPARAM)&rcToolBar); } ::GetClientRect(hwndToolBar, &rcToolBar); rcToolBar.bottom = rcToolBar.top + cRows*RECT_HEIGHT(btnRc); rcToolBar.right = RECT_WIDTH(rcWindowPos); MoveWindow(hwndToolBar, rcToolBar.top+g_tbLeftMargin, rcToolBar.left, RECT_WIDTH(rcToolBar)-(g_tbLeftMargin+g_tbRightMargin), RECT_HEIGHT(rcToolBar), TRUE); } void CHHWinType::ToggleExpansion(bool bNotify /*=true*/) { if (!IsValidWindow(GetHwnd())) { return ; } if (bNotify) { // Review: Should we check the return value? [dalero: 21 Sep 98] OnTrackNotifyCaller(IsExpandedNavPane() ? HHACT_CONTRACT : HHACT_EXPAND) ; } RECT rc; if (RECT_WIDTH(rcNav) <= 0) { rcNav.right = (iNavWidth ? iNavWidth : DEFAULT_NAV_WIDTH); } if (fNotExpanded) { fNotExpanded = FALSE; // now expanding if (IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { if (IsValidWindow(hwndHTML) ) { ShowWindow(hwndHTML, SW_HIDE); } } else { // normal tri-pane window // Expand the window to the left to make room ::GetWindowRect(GetHwnd(), &rc); rc.left -= RECT_WIDTH(rcNav) + m_pSizeBar->Width() ; GetWorkArea(); // Multiple Monitor support. if (rc.left < g_rcWorkArea.left) { rc.left = g_rcWorkArea.left; } /* BUG 3463 --- the MoveWindow call below was not sending a WM_SIZE message, when RECT_WIDTH(rc) > the width of the screen. Adjusting the width fixes this issue.nn */ // Don't make the window wider than the screen width. if (rc.right > g_rcWorkArea.right) { rc.right = g_rcWorkArea.right; } // create a size bar window between the Nav pane and the HTML pane CreateSizeBar(); // Moved because the function below resizes... if (!m_fLockSize) { MoveWindow(GetHwnd(), rc.left, rc.top, RECT_WIDTH(rc), RECT_HEIGHT(rc), TRUE); } } CreateOrShowNavPane(); if (GetToolBarHwnd()) { SendMessage(GetToolBarHwnd(), TB_HIDEBUTTON, IDTB_EXPAND, TRUE); SendMessage(GetToolBarHwnd(), TB_HIDEBUTTON, IDTB_CONTRACT, FALSE); SendMessage(GetToolBarHwnd(), TB_ENABLEBUTTON, IDTB_CONTRACT, TRUE); } } else { fNotExpanded = TRUE; DestroySizeBar(); if ( m_hWndST ) ShowWindow(m_hWndST, SW_HIDE); if ( m_hWndSSCB ) ShowWindow(m_hWndSSCB, SW_HIDE); if (IsValidWindow(hwndNavigation)) { ShowWindow(hwndNavigation, SW_HIDE); } if (IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { ShowWindow(hwndHTML, SW_SHOW); } else { ::GetWindowRect(GetHwnd(), &rc); if (!m_fLockSize) rc.left += RECT_WIDTH(rcNav) + m_pSizeBar->Width() ; // make sure we are not going off the screen Bug 6611 GetWorkArea(); // Multiple Monitor support. if (rc.left > g_rcWorkArea.right) { int min = GetSystemMetrics(SM_CXHTHUMB); rc.left = g_rcWorkArea.right - min*2; } MoveWindow(GetHwnd(), rc.left, rc.top, RECT_WIDTH(rc), RECT_HEIGHT(rc), TRUE); } if (GetToolBarHwnd()) { SendMessage(GetToolBarHwnd(), TB_HIDEBUTTON, IDTB_CONTRACT, TRUE); SendMessage(GetToolBarHwnd(), TB_HIDEBUTTON, IDTB_EXPAND, FALSE); SendMessage(GetToolBarHwnd(), TB_ENABLEBUTTON, IDTB_EXPAND, TRUE); } } } void CHHWinType::CreateSizeBar( void ) { if (!m_pSizeBar && IsValidWindow(GetHTMLHwnd())) { m_pSizeBar = new CSizeBar ; ASSERT(m_pSizeBar) ; m_pSizeBar->Create(this) ; } } void CHHWinType::DestroySizeBar( void ) { if (m_pSizeBar) { delete m_pSizeBar ; m_pSizeBar = NULL ; } } void CHHWinType::CreateOrShowNavPane(void) { if (IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) rcNav.right = rcHTML.right; if (!IsValidWindow(hwndNavigation)/* && !IsProperty(HHWIN_PROP_NO_TOOLBAR)*/) { rcNav.left = 0; if (RECT_WIDTH(rcNav) <= 0) { rcNav.right = (iNavWidth ? iNavWidth : DEFAULT_NAV_WIDTH); } CalcHtmlPaneRect(); // // Create the structural subset picker combo if necessary. // if (m_phmData && // BUG 5214 m_phmData->m_sysflags.fDoSS && ! m_phmData->m_pTitleCollection->IsSingleTitle() ) { HFONT hFont, hFontOld; TEXTMETRIC tm; HDC hDC; RECT rc; hFont = _Resource.GetAccessableUIFont(); // GetUIFont(); hDC = GetDC(NULL); hFontOld = (HFONT)SelectObject(hDC, hFont); GetTextMetrics(hDC, &tm); SelectObject(hDC, hFontOld); ReleaseDC(NULL, hDC); rcNav.top += 5; m_iSSCBHeight = 5; if ( (m_hWndST = CreateWindow("STATIC", GetStringResource(IDS_SUBSET_UI), WS_CHILD , rcNav.left + 6, rcNav.top, RECT_WIDTH(rcNav) - 8, tm.tmHeight, GetHwnd(), NULL, _Module.GetModuleInstance(), NULL)) ) { SendMessage(m_hWndST, WM_SETFONT, (WPARAM)hFont, 0L); rcNav.top += tm.tmHeight + 2; m_iSSCBHeight += tm.tmHeight + 2; rc.left = rcNav.left + 6; rc.top = rcNav.top; rc.right = rcNav.right - 10; rc.bottom = rcNav.top + tm.tmHeight + 10; if(g_bWinNT5) { SetWindowTextW(m_hWndST,GetStringResourceW(IDS_SUBSET_UI)); } m_hWndSSCB = CreateWindow("COMBOBOX", NULL, (WS_CHILD | CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL), rc.left, rc.top, RECT_WIDTH(rc), RECT_HEIGHT(rc) + 80, GetHwnd(), (HMENU)IDC_SS_PICKER, _Module.GetModuleInstance(), NULL); SendMessage(m_hWndSSCB, WM_SETFONT, (WPARAM)GetAccessableContentFont(), 0L); rcNav.top += tm.tmHeight + 11; m_iSSCBHeight += tm.tmHeight + 11; ShowWindow(m_hWndST, SW_SHOW); ShowWindow(m_hWndSSCB, SW_SHOW); // // Populate the combo. // if ( m_phmData->m_pTitleCollection->m_pSSList ) { CStructuralSubset* pSSSel = NULL, *pSS = NULL; while ( pSS = m_phmData->m_pTitleCollection->m_pSSList->GetNextSubset(pSS) ) { if (! pSS->IsEmpty() ) // Don't put "new" here. { if(g_bWinNT5) { CExTitle *pTitle = m_phmData->m_pTitleCollection->GetFirstTitle(); DWORD cp; if(pSS->IsEntire() == TRUE) cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT)); else cp = CodePageFromLCID((pTitle->GetInfo())->GetLanguage()); DWORD dwSize = (DWORD)(sizeof(WCHAR) * strlen(pSS->GetName())) + 4; WCHAR *pwcString = (WCHAR *) lcMalloc(dwSize); if(pwcString) { MultiByteToWideChar(cp, MB_PRECOMPOSED, pSS->GetName(), -1, pwcString, dwSize); SendMessageW(m_hWndSSCB, CB_ADDSTRING, 0, (LPARAM)pwcString); lcFree(pwcString); } } else { SendMessage(m_hWndSSCB, CB_ADDSTRING, 0, (LPARAM)pSS->GetName()); } } if ( pSS->IsTOC() ) pSSSel = pSS; } // Select as appropiate... // if (! pSSSel ) pSSSel = m_phmData->m_pTitleCollection->m_pSSList->GetEC(); if(g_bWinNT5 && pSSSel->IsEntire()) { // This code special cases the selection of the "Entire Collection" subset in the combobox. // WCHAR pszUnicodeSubsetName[MAX_SS_NAME_LEN]; pszUnicodeSubsetName[0] = 0; // Get the UI language codepage // DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT)); // convert subset name to Unicode using UI codepage // MultiByteToWideChar(cp, MB_PRECOMPOSED, pSSSel->GetName(), -1, pszUnicodeSubsetName, sizeof(pszUnicodeSubsetName)); // select the subset in the combobox // SendMessageW(m_hWndSSCB, CB_SELECTSTRING, -1, (LPARAM)pszUnicodeSubsetName); } else SendMessage(m_hWndSSCB, CB_SELECTSTRING, -1, (LPARAM)pSSSel->GetName()); m_phmData->m_pTitleCollection->m_pSSList->SetFTS(pSSSel); m_phmData->m_pTitleCollection->m_pSSList->SetF1(pSSSel); m_phmData->m_pTitleCollection->m_pSSList->SetTOC(pSSSel); pSSSel->SelectAsTOCSubset(m_phmData->m_pTitleCollection); } } } // // Create the HH CHILD window on which the SysTabCtrl32 window will sit. //txtHtmlHelpChildWindowClass hwndNavigation = W_CreateWindow(L"HH Child", NULL, WS_CHILD, rcNav.left, rcNav.top, RECT_WIDTH(rcNav), RECT_HEIGHT(rcNav), GetHwnd(), NULL, _Module.GetModuleInstance(), NULL); // How many tabs do we have? int cTabs = GetValidNavPaneCount(); if (cTabs > 1) { // Remove the non-existant tabs from the tab order. int max = HH_MAX_TABS ; for (int i = 0; i < max; i++) // Don't have to move last if invalid So don't add 1 to HH_MAX_TABS { if (!IsValidNavPane(tabOrder[i])) { // Collapse the array. MemMove(&tabOrder[i], &tabOrder[i + 1], max - i); // Decrement the count so we do this index again. i-- ; max-- ; } } // Now create the tab. m_pTabCtrl = new CTabControl(hwndNavigation, tabpos, this); } ResizeWindow(this); } if (!IsProperty(HHWIN_PROP_NO_TOOLBAR)) ShowWindow(hwndNavigation, SW_SHOW); if (m_pTabCtrl) ShowWindow(m_pTabCtrl->hWnd(), SW_SHOW); if ( m_hWndST ) ShowWindow(m_hWndST, SW_SHOW); if ( m_hWndSSCB ) ShowWindow(m_hWndSSCB, SW_SHOW); //Validate the current nav pane. if (!IsValidNavPane(curNavType)) { // The current nav pane doesn't exist. Pick another. curNavType = GetValidNavPane() ; if (curNavType < 0) { ASSERT(0) ; // Should never happen. return; // hopeless... } } // Create the nav pane if needed. CreateNavPane(curNavType) ; // Show the pane. if (m_aNavPane[curNavType]) { if (curNavType != 0 && m_pTabCtrl) TabCtrl_SetCurSel(m_pTabCtrl->hWnd(), GetTabIndexFromNavPaneIndex(curNavType)); m_aNavPane[curNavType]->ShowWindow() ; // BUG HH 16685 - The current tab is now persisted. So we come along and // create this new tab. However, resize is never called. So, we will call // resize here to make sure that we resize the window. m_aNavPane[curNavType]->ResizeWindow() ; } if ( m_pSizeBar ) m_pSizeBar->ResizeWindow(); } void CHHWinType::CreateOrShowHTMLPane(void) { if (!IsValidWindow(hwndNavigation)) hwndHTML = CreateWindow(txtHtmlHelpChildWindowClass, NULL, WS_CHILD | WS_CLIPCHILDREN, rcHTML.left, rcHTML.top, RECT_WIDTH(rcHTML), RECT_HEIGHT(rcHTML), GetHwnd(), NULL, _Module.GetModuleInstance(), NULL); ShowWindow(hwndHTML, SW_SHOW); } void CHHWinType::CreateToc(void) { if (IsEmptyString(pszToc)) return; TCHAR szPath[MAX_URL]; if (!ConvertToCacheFile(pszToc, szPath)) { AuthorMsg(IDS_CANT_OPEN, pszToc); strcpy(szPath, pszToc); } CToc* ptoc = new CToc(NULL, NULL, this); m_aNavPane[HH_TAB_CONTENTS] = ptoc ; ptoc->SetTabPos(tabpos); ptoc->SetPadding(TAB_PADDING); ptoc->ReadFile(szPath); // populate the InfoType member object of the CToc if ( !ptoc->m_pInfoType ) { if (ptoc->m_phh && ptoc->m_phh->m_phmData && ptoc->m_phh->m_phmData->m_pdInfoTypes ) { // load from the global IT store ptoc->m_pInfoType = new CInfoType; ptoc->m_pInfoType->CopyTo( ptoc->m_phh->m_phmData ); #if 0 // for subset testing purposes #include "csubset.h" CSubSets *pSubSets = new CSubSets( ptoc->m_pInfoType->InfoTypeSize(), ptoc->m_pInfoType, TRUE ); pSubSets->CopyTo( ptoc->m_phh->m_phmData ); #endif } else { // no global IT's; load from the .hhc IT store ptoc->m_pInfoType = new CInfoType; *ptoc->m_pInfoType = ptoc->m_sitemap; } } ptoc->SetStyles(WS_EX_CLIENTEDGE, ptoc->m_sitemap.m_tvStyles == (DWORD) -1 ? DEFAULT_TOC_STYLES : ptoc->m_sitemap.m_tvStyles); ptoc->Create((m_pTabCtrl ? m_pTabCtrl->hWnd() : (IsValidWindow(hwndNavigation) ? hwndNavigation : hwndHelp))); ptoc->m_fHack = FALSE; ptoc->InitTreeView(); } void CHHWinType::UpdateInformationTypes(void) { if ( m_aNavPane[HH_TAB_CONTENTS] ) { m_aNavPane[HH_TAB_CONTENTS]->Refresh(); if (IsProperty(HHWIN_PROP_AUTO_SYNC) && IsExpandedNavPane()) { CStr cszUrl; m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl); m_aNavPane[HH_TAB_CONTENTS]->Synchronize(cszUrl); } // Next/Prev command UI updates... // UpdateCmdUI(); } if ( m_aNavPane[HH_TAB_INDEX] && curNavType == HHWIN_NAVTYPE_INDEX ) m_aNavPane[HH_TAB_INDEX]->Refresh(); } void CHHWinType::UpdateCmdUI(void) { HMENU hMenu; BOOL bEnable, ptoc; ptoc = (m_aNavPane[HH_TAB_CONTENTS] != NULL); if ( IsValidWindow(hwndToolBar) ) { if ( hwndHelp ) hMenu = GetMenu(hwndHelp); // // Does TOCNext or TOCPrev need to be enabled/disabled ? // if ( (fsToolBarFlags & HHWIN_BUTTON_TOC_PREV) || (fsToolBarFlags & HHWIN_BUTTON_TOC_NEXT) || hMenu ) { bEnable = ptoc ? OnTocPrev(FALSE) : FALSE ; // If no TOC, disable. if ( fsToolBarFlags & HHWIN_BUTTON_TOC_PREV ) SendMessage(hwndToolBar, TB_ENABLEBUTTON, IDTB_TOC_PREV, bEnable); if ( hMenu ) EnableMenuItem(hMenu, IDTB_TOC_PREV, (MF_BYCOMMAND | (bEnable?MF_ENABLED:MF_GRAYED))); bEnable = ptoc ? OnTocNext(FALSE) : FALSE; // If no TOC, disable. if ( fsToolBarFlags & HHWIN_BUTTON_TOC_NEXT ) SendMessage(hwndToolBar, TB_ENABLEBUTTON, IDTB_TOC_NEXT, bEnable); if ( hMenu ) EnableMenuItem(hMenu, IDTB_TOC_NEXT, (MF_BYCOMMAND | (bEnable?MF_ENABLED:MF_GRAYED))); } if (NoRun() == TRUE) { if (hMenu) EnableMenuItem(hMenu, HHM_JUMP_URL, MF_BYCOMMAND|MF_GRAYED); } } } /////////////////////////////////////////////////////////// // // CreateIndex // void CHHWinType::CreateIndex(void) { if (IsEmptyString(pszIndex)) return; TCHAR szPath[MAX_URL]; if (!ConvertToCacheFile(pszIndex, szPath)) { AuthorMsg(IDS_CANT_OPEN, pszIndex); strcpy(szPath, pszIndex); } if (!m_aNavPane[HH_TAB_INDEX]) { CIndex* pIndex = new CIndex(NULL, NULL, this); m_aNavPane[HH_TAB_INDEX] = pIndex ; pIndex->SetPadding(TAB_PADDING); pIndex->SetTabPos(tabpos); pIndex->ReadIndexFile(szPath); // A CIndex function, but not a INavUI function. } m_aNavPane[HH_TAB_INDEX]->Create(GetTabCtrlHwnd()); } /////////////////////////////////////////////////////////// // // CreateSearchTab // void CHHWinType::CreateSearchTab(void) { if (! m_phmData || !m_phmData->m_pTitleCollection->m_pFullTextSearch) return; // no compiled information if (!m_aNavPane[HH_TAB_SEARCH]) { if (IsProperty(HHWIN_PROP_TAB_ADVSEARCH)) { //---Create the Advanced Search Navigation Pane. m_aNavPane[HH_TAB_SEARCH] = new CAdvancedSearchNavPane(this); } else { //---Create the simple Search Navigation Pane. m_aNavPane[HH_TAB_SEARCH] = new CSearch(this); } m_aNavPane[HH_TAB_SEARCH]->SetPadding(TAB_PADDING); m_aNavPane[HH_TAB_SEARCH]->SetTabPos(tabpos); } m_aNavPane[HH_TAB_SEARCH]->Create(GetTabCtrlHwnd()); } /////////////////////////////////////////////////////////// // // CreateBookmarksTab // void CHHWinType::CreateBookmarksTab() { if (!m_aNavPane[HH_TAB_FAVORITES]) { CBookmarksNavPane* p= new CBookmarksNavPane(this); m_aNavPane[HH_TAB_FAVORITES] = p; p->SetPadding(TAB_PADDING); p->SetTabPos(tabpos); } m_aNavPane[HH_TAB_FAVORITES]->Create(GetTabCtrlHwnd()); } /////////////////////////////////////////////////////////// // // CreatesCustomTab - Creates a tab defined by the client. // void CHHWinType::CreateCustomTab(int iPane, LPCOLESTR pszProgId) { // REVIEW: The lines marked with [chm] assume that the information can be found in the chm file. if (!m_aNavPane[iPane]) { CCustomNavPane* p= new CCustomNavPane(this); m_aNavPane[iPane] = p; p->SetPadding(TAB_PADDING); p->SetTabPos(tabpos); p->SetControlProgId(pszProgId); //[chm] We could also use the GUID instead/in addition. } m_aNavPane[iPane]->Create(GetTabCtrlHwnd()); } /////////////////////////////////////////////////////////// // // Destructor // CHHWinType::~CHHWinType() { CloseWindow(); } extern BOOL g_fThreadCall; extern HWND g_hwndApi; // // This member can be called from DllMain at process detach time. Note that this is only a partial cleanup but // it's the best we can do at process detach time. // // void CHHWinType::ProcessDetachSafeCleanup() { if (m_pTabCtrl) { delete m_pTabCtrl; m_pTabCtrl = NULL; } // Get rid of the sizebar. DestroySizeBar() ; if (m_ptblBtnStrings) { delete m_ptblBtnStrings; m_ptblBtnStrings = NULL; } } void CHHWinType::CloseWindow() { // Save the state.. SaveState() ; // Things we can cleanup a process shutdown. ProcessDetachSafeCleanup() ; // Things we cleanup when we are reloading the nav panes. ReloadCleanup() ; // Free here and not in ReloadCleanup. CHECK_AND_FREE( pszHome ); CHECK_AND_FREE( pszCustomTabs ); CHECK_AND_FREE( pszType ); CHECK_AND_FREE( pszCaption ); if (m_pCIExpContainer) { m_pCIExpContainer->ShutDown(); // This call WILL end up doing the delete m_pCIExpContainer; m_pCIExpContainer = NULL; } if ( m_phmData && !m_phmData->Release() ) // Cleanup ChmData { // // Find this instance of the ChmData in the global array, null out it's entry and clean this one up. // for (int n = 0; n < g_cHmSlots; n++) { if ( g_phmData && (g_phmData[n] == m_phmData) ) { g_phmData[n] = NULL; } } } m_phmData = NULL; if (IsProperty(HHWIN_PROP_POST_QUIT)) { PostQuitMessage(0); } // Null out our window from the window list. for (int i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] != NULL && pahwnd[i]->hwndHelp == hwndHelp) { pahwnd[i] = NULL ; } } curNavType = 0; hwndHelp = NULL; // Do other windows exist? for (i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] != NULL && pahwnd[i]->hwndHelp != NULL) { // If other windows exist exit. return ; } } for(int j=0; i< c_NUMNAVPANES; i++) { if ( m_aNavPane[j] ) { delete m_aNavPane[j]; m_aNavPane[j] = NULL; } } if ( m_pTabCtrl ) { delete m_pTabCtrl; m_pTabCtrl = NULL; } if ( m_pSizeBar ) { delete m_pSizeBar; m_pSizeBar = NULL; } if (m_hAccel) { DestroyAcceleratorTable(m_hAccel) ; m_hAccel = NULL ; } if( m_hMenuOptions ) { DestroyMenu( m_hMenuOptions ); m_hMenuOptions = NULL; } if( m_hImageListGray ) { ImageList_Destroy( m_hImageListGray ); m_hImageListGray = NULL; } if( m_hImageList ) { ImageList_Destroy( m_hImageList ); m_hImageList = NULL; } if( hwndToolBar ) { DestroyWindow( hwndToolBar ); hwndToolBar = NULL; } // If we got here, all windows have been closed DeleteAllHmData(); #ifdef _CHECKMEM_ON_CLOSEWINDOW_ _CrtMemDumpAllObjectsSince(&m_MemState) ; #endif if (g_fThreadCall && g_hwndApi) PostQuitMessage(0); } //////////////////////////////////////////////////////////////// // // ReloadCleanUp --- This is the things we have to clean up before we reload the nav pane. // void CHHWinType::ReloadCleanup() { // Delete all of the navigation panes. for(int j = 0 ; j < c_NUMNAVPANES ; j++) { if (m_aNavPane[j]) { delete m_aNavPane[j] ; m_aNavPane[j] = NULL ; } } CHECK_AND_FREE( pszToc ); CHECK_AND_FREE( pszIndex ); CHECK_AND_FREE( pszFile ); CHECK_AND_FREE( pszJump1 ); CHECK_AND_FREE( pszJump2 ); CHECK_AND_FREE( pszUrlJump1 ); CHECK_AND_FREE( pszUrlJump2 ); // Don't free this here. Because we need to keep this around. // CHECK_AND_FREE( pszHome ); //CHECK_AND_FREE( pszCustomTabs ); //CHECK_AND_FREE( pszType ); //CHECK_AND_FREE( pszCaption ); } void CHHWinType::SaveState() { WINDOW_STATE wstate; WINDOWPLACEMENT winPlace; wstate.cbStruct = sizeof(wstate); winPlace.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(GetHwnd(), &winPlace); if (winPlace.showCmd == SW_SHOWMINIMIZED) { wstate.rcPos = winPlace.rcNormalPosition; } else { ::GetWindowRect(GetHwnd(), &wstate.rcPos); } wstate.iNavWidth = rcNav.right; wstate.fHighlight = (m_phmData&&m_phmData->m_pTitleCollection->m_pSearchHighlight)?m_phmData->m_pTitleCollection->m_pSearchHighlight->m_bHighlightEnabled:TRUE; wstate.fLockSize = m_fLockSize; wstate.fNoToolBarText = m_fNoToolBarText; wstate.curNavType = curNavType; wstate.fNotExpanded = fNotExpanded; if( m_phmData ) { CState* pstate = m_phmData->m_pTitleCollection->GetState(); if (SUCCEEDED(pstate->Open(GetTypeName(), STGM_WRITE))) { pstate->Write(&wstate, sizeof(wstate)); pstate->Close(); } } } int CHHWinType::CreateToolBar(TBBUTTON* pabtn) { // create a dropdown menu for the options button to display int cMenuItems=0; const int MENUITEMSTRINGLEN = 80; CStr cszMenuItem; m_hMenuOptions = CreatePopupMenu(); cszMenuItem.ReSize(MENUITEMSTRINGLEN); ASSERT(!IsProperty(HHWIN_PROP_NO_TOOLBAR)); if (m_ptblBtnStrings) delete m_ptblBtnStrings; m_ptblBtnStrings = new CTable(256); // room for 256 bytes int cButtons = 0; MENUITEMINFO mii; ZERO_STRUCTURE ( mii ); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE|MIIM_STATE|MIIM_ID|MIIM_SUBMENU|MIIM_CHECKMARKS; mii.fType = MFT_STRING; if (fsToolBarFlags & HHWIN_BUTTON_EXPAND) { pabtn[cButtons].iBitmap = 12; pabtn[cButtons].idCommand = IDTB_EXPAND; pabtn[cButtons].fsState = (IsExpandedNavPane() ? TBSTATE_HIDDEN : TBSTATE_ENABLED); pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_EXPAND)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_EXPAND) { pabtn[cButtons].iBitmap = 13; pabtn[cButtons].idCommand = IDTB_CONTRACT; pabtn[cButtons].fsState = (IsExpandedNavPane() ? TBSTATE_ENABLED : TBSTATE_HIDDEN); pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_CONTRACT)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_SYNC) { if (!IsEmptyString(pszToc)) { pabtn[cButtons].iBitmap = 9; pabtn[cButtons].idCommand = IDTB_SYNC; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_SYNC)); cButtons++; } } if (fsToolBarFlags & HHWIN_BUTTON_TOC_PREV) { pabtn[cButtons].iBitmap = 14; pabtn[cButtons].idCommand = IDTB_TOC_PREV; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_TOC_PREV)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_TOC_NEXT) { pabtn[cButtons].iBitmap = 8; pabtn[cButtons].idCommand = IDTB_TOC_NEXT; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_TOC_NEXT)); cButtons++; } if (g_fBiDi) { if (fsToolBarFlags & HHWIN_BUTTON_FORWARD) { pabtn[cButtons].iBitmap = 0; pabtn[cButtons].idCommand = IDTB_FORWARD; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_FORWARD)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_BACK) { pabtn[cButtons].iBitmap = 1; pabtn[cButtons].idCommand = IDTB_BACK; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_BACK)); cButtons++; } } else { if (fsToolBarFlags & HHWIN_BUTTON_BACK) { pabtn[cButtons].iBitmap = 0; pabtn[cButtons].idCommand = IDTB_BACK; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_BACK)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_FORWARD) { pabtn[cButtons].iBitmap = 1; pabtn[cButtons].idCommand = IDTB_FORWARD; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_FORWARD)); cButtons++; } } if (fsToolBarFlags & HHWIN_BUTTON_STOP) { pabtn[cButtons].iBitmap = 2; pabtn[cButtons].idCommand = IDTB_STOP; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_STOP)); cButtons++; } if ( fsToolBarFlags & HHWIN_BUTTON_REFRESH) { pabtn[cButtons].iBitmap = 3; pabtn[cButtons].idCommand = IDTB_REFRESH; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_REFRESH)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_HOME) { if (pszHome) { pabtn[cButtons].iBitmap = 4; pabtn[cButtons].idCommand = IDTB_HOME; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_HOME)); cButtons++; } } if (fsToolBarFlags & HHWIN_BUTTON_BROWSE_FWD) { if (pszHome) { pabtn[cButtons].iBitmap = 14; pabtn[cButtons].idCommand = IDTB_BROWSE_FWD; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_BROWSE_FWD)); cButtons++; } } if (fsToolBarFlags & HHWIN_BUTTON_BROWSE_BCK) { if (pszHome) { pabtn[cButtons].iBitmap = 8; pabtn[cButtons].idCommand = IDTB_BROWSE_BACK; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_BROWSE_BACK)); cButtons++; } } if (fsToolBarFlags & HHWIN_BUTTON_ZOOM) { pabtn[cButtons].iBitmap = 16; // BUGBUG: We need a zoom glyph in toolb16g.bmp pabtn[cButtons].idCommand = IDTB_ZOOM; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_ZOOM)); cButtons++; } if ( fsToolBarFlags & HHWIN_BUTTON_PRINT) { pabtn[cButtons].iBitmap = 7; pabtn[cButtons].idCommand = IDTB_PRINT; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_PRINT)); cButtons++; } //--- hard-coded menu CTable tblMenus(8 * 1024); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.hSubMenu = NULL; mii.hbmpChecked = NULL; // bitmap tp display when checked mii.hbmpUnchecked = NULL; // bitmap to display when not checked mii.dwItemData = NULL; // data associated with the menu item mii.wID = IDTB_CONTRACT; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_HIDE); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen(mii.dwTypeData); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); if (fsToolBarFlags & HHWIN_BUTTON_SYNC) { if (!IsEmptyString(pszToc)) { mii.wID = IDTB_SYNC; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_SYNC); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen(mii.dwTypeData); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); } } mii.wID = IDTB_BACK; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_BACK); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen(mii.dwTypeData); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); mii.wID = IDTB_FORWARD; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_FORWARD); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); if (pszHome) { mii.wID = IDTB_HOME; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_HOME); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); } mii.wID = IDTB_STOP; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_STOP); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); mii.wID = IDTB_REFRESH; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_REFRESH); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); mii.wID = HHM_OPTIONS; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_IE_OPTIONS); // the string to display for the menu item tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); mii.fMask = MIIM_TYPE; mii.fType = MFT_SEPARATOR; HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); // Now restore the mast and type mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; mii.fType = MFT_STRING; BOOL fSeperatorNeeded = FALSE; /* * At this point, we need to add any custom Jump buttons, and to do * that we need to know all of the hard-coded menu items so that we can * adjust the accelerators as needed. */ if ((fsToolBarFlags & HHWIN_BUTTON_JUMP1 && pszJump1) || (fsToolBarFlags & HHWIN_BUTTON_JUMP2 && pszJump2)) { tblMenus.AddString(GetStringResource(IDS_OPTION_CUSTOMIZE)); tblMenus.AddString(GetStringResource(IDS_OPTION_PRINT)); if (!g_fIE3 && m_phmData && m_phmData->m_pTitleCollection && m_phmData->m_pTitleCollection->m_pSearchHighlight) tblMenus.AddString(GetStringResource(IDS_OPTION_HILITING_OFF)); } if (fsToolBarFlags & HHWIN_BUTTON_JUMP1 && pszJump1) { mii.wID = IDTB_JUMP1; // Menu Item ID cszMenuItem = "&1 "; cszMenuItem += pszJump1; tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); fSeperatorNeeded = TRUE; } if (fsToolBarFlags & HHWIN_BUTTON_JUMP2 && pszJump2) { mii.wID = IDTB_JUMP2; // Menu Item ID cszMenuItem = "&2 "; cszMenuItem += pszJump2; tblMenus.AddString(cszMenuItem.psz); mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); fSeperatorNeeded = TRUE; } if (fSeperatorNeeded) { mii.fMask = MIIM_TYPE; mii.fType = MFT_SEPARATOR; HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); // Now restore the mast and type mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID; mii.fType = MFT_STRING; } if (m_phmData && m_phmData->m_pInfoType && m_phmData->m_pInfoType->HowManyInfoTypes() > 0) { mii.wID = IDTB_CUSTOMIZE; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_CUSTOMIZE); // the string to display for the menu item mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); } mii.wID = IDTB_PRINT; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_PRINT); // the string to display for the menu item mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); // --- end fixed menu if (!g_fIE3 && m_phmData && m_phmData->m_pTitleCollection && m_phmData->m_pTitleCollection->m_pSearchHighlight) { // Add search term hiliting to the options menu. mii.wID = IDTB_HILITE; // Menu Item ID cszMenuItem = GetStringResource(IDS_OPTION_HILITING_OFF); // the string to display for the menu item mii.dwTypeData = cszMenuItem.psz; mii.cch = (DWORD)strlen( mii.dwTypeData ); // length of the string. HxInsertMenuItem(m_hMenuOptions, cMenuItems++, TRUE, &mii); } if ( fsToolBarFlags & HHWIN_BUTTON_OPTIONS && cMenuItems) { pabtn[cButtons].iBitmap = 10; pabtn[cButtons].idCommand = IDTB_OPTIONS; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].fsStyle = TBSTYLE_DROPDOWN; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_OPTIONS)); if ( cMenuItems ) pabtn[cButtons].dwData = (DWORD_PTR)m_hMenuOptions; cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_NOTES) { pabtn[cButtons].iBitmap = 11; pabtn[cButtons].idCommand = IDTB_NOTES; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_NOTES)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_CONTENTS) { pabtn[cButtons].iBitmap = 15; pabtn[cButtons].idCommand = IDTB_CONTENTS; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_CONTENTS)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_INDEX) { pabtn[cButtons].iBitmap = 16; pabtn[cButtons].idCommand = IDTB_INDEX; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_INDEX)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_SEARCH) { pabtn[cButtons].iBitmap = 5; pabtn[cButtons].idCommand = IDTB_SEARCH; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_SEARCH)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_HISTORY) { pabtn[cButtons].iBitmap = 19; pabtn[cButtons].idCommand = IDTB_HISTORY; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_HISTORY)); cButtons++; } if (fsToolBarFlags & HHWIN_BUTTON_FAVORITES) { pabtn[cButtons].iBitmap = 6; pabtn[cButtons].idCommand = IDTB_FAVORITES; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(GetStringResource(IDTB_FAVORITES)); cButtons++; } if ((fsToolBarFlags & HHWIN_BUTTON_JUMP1) && !(IsProperty(HHWIN_PROP_MENU))) { pabtn[cButtons].iBitmap = 17; pabtn[cButtons].idCommand = IDTB_JUMP1; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(pszJump1 ? pszJump1 : ""); cButtons++; } if ((fsToolBarFlags & HHWIN_BUTTON_JUMP2) && !(IsProperty(HHWIN_PROP_MENU))) { pabtn[cButtons].iBitmap = 18; pabtn[cButtons].idCommand = IDTB_JUMP2; pabtn[cButtons].fsState = TBSTATE_ENABLED; pabtn[cButtons].iString = cButtons; m_ptblBtnStrings->AddString(pszJump2 ? pszJump2 : ""); cButtons++; } return cButtons; } // No longer used, but we'll keep in around awhile just in case /* static void FixDupMenuAccelerator(const CTable* ptbl, PSTR pszMenu) { int i; PSTR pszOrg; PSTR pszTmp = StrChr(pszMenu, ACCESS_KEY); if (!pszTmp) { MoveMemory(pszMenu + 1, pszMenu, strlen(pszMenu) + 1); *pszMenu = ACCESS_KEY; pszTmp = pszMenu; } pszOrg = pszTmp; SHORT ch = VkKeyScan((BYTE) CharLower((LPSTR) pszTmp[1])); for (i = 1; i <= ptbl->CountStrings(); i++) { // check for a duplicate accelerator key PCSTR psz = StrChr(ptbl->GetPointer(i), ACCESS_KEY); if (VkKeyScan((BYTE) CharLower((LPSTR) psz[1])) == ch) { strcpy(pszTmp, pszTmp + 1); // remove the accelerator pszTmp++; if (!*pszTmp) { // End of string, nothing we can do MoveMemory(pszOrg + 1, pszOrg, strlen(pszOrg) + 1); *pszOrg = ACCESS_KEY; return; } else { MoveMemory(pszTmp + 1, pszTmp, strlen(pszTmp) + 1); *pszTmp = ACCESS_KEY; ch = VkKeyScan((BYTE) CharLower((LPSTR) pszTmp[1])); i = 0; // start over } } } } */ #ifndef TCS_FLATBUTTONS #define TCS_FLATBUTTONS 0x0008 #endif ////////////////////////////////////////////////////////////////////////////////// // // IsValidTab(int iTab) --- Index returned from tabOrder. // BOOL CHHWinType::IsValidNavPane(int iTab) { //REVIEW:: Assumes that the tabs have not been re-ordered! BOOL bResult = FALSE ; // We only have valid tabs if we are a TRI_PANE. if (IsProperty(HHWIN_PROP_TRI_PANE)) { switch(iTab) { case HH_TAB_CONTENTS: if (!IsEmptyString(pszToc) && tabOrder[HH_TAB_CONTENTS] != 255) bResult = TRUE ; break; case HH_TAB_INDEX: if (!IsEmptyString(pszIndex) && tabOrder[HH_TAB_INDEX] != 255) bResult = TRUE ; break; case HH_TAB_SEARCH: if ((fsWinProperties & HHWIN_PROP_TAB_SEARCH) /*&& m_phmData && m_phmData->m_sysflags.fFTI*/) { //BUGBUG: m_phmdata isn't always valid when we are getting called. See HH_SET_WIN_TYPE bResult = TRUE ; } break; case HH_TAB_HISTORY: if (fsWinProperties & HHWIN_PROP_TAB_HISTORY) bResult = TRUE ; break; case HH_TAB_FAVORITES: if (fsWinProperties & HHWIN_PROP_TAB_FAVORITES) bResult = TRUE ; break; #ifdef __TEST_CUSTOMTAB__ case HH_TAB_AUTHOR: return IsHelpAuthor(GetHwnd()); #endif default: if (iTab >= HH_TAB_CUSTOM_FIRST && iTab <= HH_TAB_CUSTOM_LAST) { if (fsWinProperties & (HHWIN_PROP_TAB_CUSTOM1 << (iTab - HH_TAB_CUSTOM_FIRST))) { bResult = TRUE; } } } } return bResult; } ////////////////////////////////////////////////////////////////////////////////// // // GetValidNavPane --- Returns the index of the first valid tab it finds. -1 if no valid tabs. // int CHHWinType::GetValidNavPane() { for (int i = 0 ; i < HH_MAX_TABS+1 ; i++) { if (IsValidNavPane(i)) { return i; } } return -1 ; } ////////////////////////////////////////////////////////////////////////////////// // // GetNavPaneCount --- Counts the number of valid navigation panes // int CHHWinType::GetValidNavPaneCount() { int count = 0 ; for (int i = 0 ; i < HH_MAX_TABS+1 ; i++) { if (IsValidNavPane(i)) { count++; } } return count; } void CHHWinType::OnNavigateComplete(LPCTSTR pszUrl) { // Update the Bookmark pane if it exists. if (curNavType == HH_TAB_FAVORITES && m_aNavPane[HH_TAB_FAVORITES]) { // Here we are synchronizing the current topic edit control in the bookmarks pane // witht he current topic. m_aNavPane[HH_TAB_FAVORITES]->Synchronize(NULL) ; } // Get a pointer to the toc if it exists. CToc* ptoc = NULL ; if (m_aNavPane[HH_TAB_CONTENTS]) { ptoc = reinterpret_cast(m_aNavPane[HH_TAB_CONTENTS]) ; // HACKHACK: Should use dynamic cast, but no RTTI. } // // Check if zooming is supported on this page. // if ( IsValidWindow(hwndToolBar) ) { if ( IsProperty(HHWIN_PROP_MENU) || fsToolBarFlags & HHWIN_BUTTON_ZOOM ) { HRESULT hr = GetZoomMinMax(); if( fsToolBarFlags & HHWIN_BUTTON_ZOOM ) { if ( hr == S_OK ) SendMessage(hwndToolBar, TB_ENABLEBUTTON, IDTB_ZOOM, TRUE); else SendMessage(hwndToolBar, TB_ENABLEBUTTON, IDTB_ZOOM, FALSE); } } } if (idNotify) { HHN_NOTIFY hhcomp; hhcomp.hdr.hwndFrom = hwndHelp; hhcomp.hdr.idFrom = idNotify; hhcomp.hdr.code = HHN_NAVCOMPLETE; hhcomp.pszUrl = pszUrl; if (IsWindow(hwndCaller)) { SendMessage(hwndCaller, WM_NOTIFY, idNotify, (LPARAM) &hhcomp); } } } // NOTE - call the following in your OnNavigateComplete event handler to update the minmax. Do not do // it when you navigate, do it when the control fires the OnNavigate event - by then you // should be able to get the minmax stuff. //*************************************************************************** // // Member: CHHWinType:::GetZoomMinMax // // Synopsis: sets m_iZoomMin, and Most - gets called whenever we // navigate to a document. Note that many document types // do not support Zoom, and so this fails. This is OK, // and expected. // // Returns: HRESULT // //*************************************************************************** HRESULT CHHWinType::GetZoomMinMax(void) { VARIANT vararg; HRESULT hr; ::VariantInit(&vararg); V_VT(&vararg) = VT_I4; V_I4(&vararg) = 0; m_iZoom = m_iZoomMin = m_iZoomMax = 0; hr = m_pCIExpContainer->m_pIE3CmdTarget->Exec(0, OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, 0, &vararg); #if 0 if (hr) { OLECMDTEXT oct; OLECMD olecmd; olecmd.cmdID = OLECMDID_ZOOM; olecmd.cmdf = 0; hr = m_pCIExpContainer->m_pIE3CmdTarget->QueryStatus(NULL, 1, &olecmd, &oct); } #endif if (hr) return hr; if (VT_I4 == V_VT(&vararg)) m_iZoom = V_I4(&vararg); ::VariantClear(&vararg); V_VT(&vararg) = VT_I4; V_I4(&vararg) = 0; hr = m_pCIExpContainer->m_pIE3CmdTarget->Exec(0, OLECMDID_GETZOOMRANGE, OLECMDEXECOPT_DONTPROMPTUSER, 0, &vararg); if (hr) return hr; if (VT_I4 == V_VT(&vararg)) { // I looked at the IE code for this - this cast is necessary. m_iZoomMin = (INT)(SHORT)LOWORD(V_I4(&vararg)); m_iZoomMax = (INT)(SHORT)HIWORD(V_I4(&vararg)); } return hr; } //*************************************************************************** // // Member: CHHWinType::ZoomIn // // Synopsis: Zooms in one - whenever we navigate to a new document, // we get the zoom range for that document. ZoomIn will // cycle thru that zoom range, from small to large, wrapping // back to smallest again. // // Returns: nothing, fails quietly (by design). // //*************************************************************************** void CHHWinType::ZoomIn(void) { INT iZoomNew = m_iZoom + 1; if (iZoomNew > m_iZoomMax) iZoomNew = m_iZoomMin; Zoom(iZoomNew); } //*************************************************************************** // // Member: CHHWinType::ZoomOut // // Synopsis: Zooms out one - whenever we navigate to a new document, // we get the zoom range for that document. ZoomOut will // cycle thru that zoom range, from large to small, wrapping // back to largest again. // // Returns: nothing, fails quietly (by design). // //*************************************************************************** void CHHWinType::ZoomOut(void) { INT iZoomNew = m_iZoom - 1; if (iZoomNew < m_iZoomMin) iZoomNew = m_iZoomMax; Zoom(iZoomNew); } //*************************************************************************** // // Member: CHHWinType::_Zoom // // Synopsis: helper function that manages zoomin and zoomout. // // Arguments: [iZoom] -- value for new zoom. // // Requires: iZoom needs to be in a valid range for the current docobj. // current docobj must support IOleCommandTarget // it will fail if current docobj doesn't respond to // OLECMDID_ZOOM. // // Returns: HRESULT // //*************************************************************************** HRESULT CHHWinType::Zoom(int iZoom) { HRESULT hr; VARIANTARG varIn; VARIANTARG varOut; // initialize the argument to Exec. ::VariantInit(&varIn); V_VT(&varIn) = VT_I4; V_I4(&varIn) = iZoom; // init the out variant. This probably isn't necessary, but // doesn't hurt - it's defensive as opposed to passing 0. // ::VariantInit(&varOut); hr = m_pCIExpContainer->m_pIE3CmdTarget->Exec(0, OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &varIn, &varOut); if (SUCCEEDED(hr)) m_iZoom = iZoom; return hr; } //*************************************************************************** // // Member: CHHWinType::OnNext // // Synopsis: Executes a next in TOC navigation. // // Arguments: bDoJump - BOOL value indicates weather to execute a jump or not. // // Returns: BOOL - TRUE on success, FALSE on failure. // //*************************************************************************** BOOL CHHWinType::OnTocNext(BOOL bDoJump) { CExTitle *pTitle= NULL; CStr cszUrl; char szURL[MAX_URL]; CTreeNode* pTreeNode = NULL, *pTocNext = NULL, *pTocKid = NULL; CToc* pToc = NULL; DWORD dwSlot; BOOL bReturn = FALSE; if ( !m_phmData || !m_phmData->m_pTitleCollection ) return FALSE; if (! SUCCEEDED(m_phmData->m_pTitleCollection->GetCurrentTocNode(&pTreeNode)) ) { m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl); if (cszUrl.psz != NULL) { strcpy(szURL, cszUrl); if ( SUCCEEDED(m_phmData->m_pTitleCollection->URL2ExTitle(szURL, &pTitle)) ) pTitle->GetURLTreeNode(szURL, &pTreeNode); } } if ( pTreeNode ) { if ( pTocNext = m_phmData->m_pTitleCollection->GetNextTopicNode(pTreeNode, &dwSlot) ) { // Ok now we can execute the jump and sync! // if ( bDoJump ) { pTocNext->GetURL(szURL, sizeof(szURL)); m_phmData->m_pTitleCollection->URL2ExTitle(szURL, &pTitle); m_phmData->m_pTitleCollection->SetTopicSlot(dwSlot, ((CExNode*)pTocNext)->m_Node.dwOffsTopic, pTitle); ChangeHtmlTopic(szURL, *this); if (! IsProperty(HHWIN_PROP_AUTO_SYNC) && (pToc = (CToc*)m_aNavPane[HH_TAB_CONTENTS]) ) pToc->Synchronize(szURL); } delete pTocNext; bReturn = TRUE; } delete pTreeNode; } return bReturn; } //*************************************************************************** // // Member: CHHWinType::OnPrev // // Synopsis: Executes a previous in TOC navigation. // // Arguments: bDoJump - BOOL value indicates weather to execute a jump or not. // // Returns: BOOL - TRUE on success, FALSE on failure. // //*************************************************************************** BOOL CHHWinType::OnTocPrev(BOOL bDoJump) { CExTitle *pTitle = NULL; CStr cszUrl; char szURL[MAX_URL]; CTreeNode* pTreeNode = NULL, *pTocPrev = NULL; CToc* pToc = NULL; DWORD dwSlot; BOOL bReturn = FALSE; if ( !m_phmData || !m_phmData->m_pTitleCollection ) return FALSE; if (! SUCCEEDED(m_phmData->m_pTitleCollection->GetCurrentTocNode(&pTreeNode)) ) { m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl); if (cszUrl.psz != NULL) { strcpy(szURL, cszUrl); if ( SUCCEEDED(m_phmData->m_pTitleCollection->URL2ExTitle(szURL, &pTitle)) ) pTitle->GetURLTreeNode(szURL, &pTreeNode); } } if ( pTreeNode ) { // We have the TOC node, now get it's next. // if ( pTocPrev = m_phmData->m_pTitleCollection->GetPrev(pTreeNode, &dwSlot) ) { // // Ok now, we can execute the jump and sync! // if ( bDoJump ) { pTocPrev->GetURL(szURL, sizeof(szURL)); m_phmData->m_pTitleCollection->URL2ExTitle(szURL, &pTitle); m_phmData->m_pTitleCollection->SetTopicSlot(dwSlot, ((CExNode*)pTocPrev)->m_Node.dwOffsTopic, pTitle); ChangeHtmlTopic(szURL, *this); if (! IsProperty(HHWIN_PROP_AUTO_SYNC) && (pToc = (CToc*)m_aNavPane[HH_TAB_CONTENTS]) ) pToc->Synchronize(szURL); } bReturn = TRUE; delete pTocPrev; } delete pTreeNode; } return bReturn; } /*************************************************************************** FUNCTION: FindWindowType PURPOSE: Find whether the window type exists and has already created a window PARAMETERS: pszType -- window type to look for. hwndCaller -- who the caller is pszOwnerFile -- CHM file which defines this window type. RETURNS: -1 if window type not found, or found but no window created position in pahwnd if window found COMMENTS: MODIFICATION DATES: 27-Feb-1996 [ralphw] 27-Apr-1998 [dalero] Added pszOwnerFile parameter ***************************************************************************/ CHHWinType* FindWindowType(PCSTR pszType, HWND hwndCaller, LPCTSTR pszOwnerFile) { if (IsEmptyString(pszType)) { return NULL; } // Skip window separator if present. if (*pszType == WINDOW_SEPARATOR) { pszType++; if (IsEmptyString(pszType)) { return NULL; } } // We ignore the owner file if the file is URL or the window type is global. bool bIgnoreOwnerFile = IsGlobalWinType(pszType) || IsHttp(pszOwnerFile) ; if (!bIgnoreOwnerFile ) { // If its not global, we need a filename. if (IsEmptyString(pszOwnerFile)) { return NULL ; } } for (int i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] && pahwnd[i]->pszType != NULL && lstrcmpi(pszType, pahwnd[i]->pszType) == 0) { // Found the window type. // If its a global window type, we are done. if (bIgnoreOwnerFile) { break ; } else { // Call IsCompiledHtmlFile to get the filename into a consistant format. CStr cszCompiled(pszOwnerFile); if (NormalizeFileName(cszCompiled)) { // Is this window type in the correct CHM file. ASSERT(pahwnd[i]->GetOwnerFile()); if (pahwnd[i]->GetOwnerFile() && lstrcmpi(cszCompiled, pahwnd[i]->GetOwnerFile()) == 0) { break; } } } } } if (i >= g_cWindowSlots) { return NULL; } //REVIEW: 28-Apr-98 [dalero] This seems dangerous... if (hwndCaller) { pahwnd[i]->hwndCaller = hwndCaller; // In case it changed } return pahwnd[i]; } /*************************************************************************** FUNCTION: FindOrCreateWindowSlot PURPOSE: Find whether the window type exists and create it if not. PARAMETERS: pszType -- window type to look for. hwndCaller -- who the caller is pszOwnerFile -- the file which defines this window type. if pszType has the GLOBAL_WINDOWTYPE_PREFIX, the pszOwnerFile is not used. RETURNS: Return a pointer to the window type. May be an empty one just created. COMMENTS: MODIFICATION DATES: 27 Apr 98 [DaleRo] Added pszOwnerFile parameter ***************************************************************************/ CHHWinType* FindOrCreateWindowSlot(LPCTSTR pszType, LPCTSTR pszOwnerFile) { ASSERT(pahwnd != NULL) ; // pszType cannot be NULL or emptry. if (IsEmptyString(pszType)) { return NULL; } // Skip window type pointer if present. if (*pszType == WINDOW_SEPARATOR) { pszType++; if (IsEmptyString(pszType)) { return NULL ; } } // We ignore the owning file if... bool bIgnoreOwnerFile = IsGlobalWinType(pszType) // Its a global window type || IsHttp(pszOwnerFile); // or an Http address. Ideally, the window type has been registered to a particular chm... const char* pOwner = ""; // Empty string is stored in the cases where we ignore wintypes... CHHWinType will copy... CStr cszOwner(pszOwnerFile); if (!bIgnoreOwnerFile) { // If its not a global window type, it must have a valid file. if (!NormalizeFileName(cszOwner)) { return NULL ; } // pOwner is NULL if its a global wintype. Its non-null otherwise. pOwner = cszOwner; } // Check to see if this window type already exists. CHHWinType* phh = FindWindowType(pszType, NULL, cszOwner); if (phh) { return phh; } // The window type did not exist. So, find an empty slot to put it in. for (int i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] == NULL) { break; } } // Allocate more space for the array if we are out of room. if (i >= g_cWindowSlots) { g_cWindowSlots += 5; CHHWinType** paNew = (CHHWinType**) lcReAlloc(pahwnd, g_cWindowSlots * sizeof(CHHWinType*)); memset( paNew + (g_cWindowSlots-5), 0, 5 * sizeof(CHHWinType*) ); if (paNew == NULL) { OOM(); return FALSE; } pahwnd = paNew; } // Create the new window type object. Note that it is not initialized. pahwnd[i] = new CHHWinType(pOwner); return pahwnd[i]; } /*************************************************************************** FUNCTION: FindCurWindow PURPOSE: Find a current window displayed PARAMETERS: RETURNS: COMMENTS: This function is random. It picks the first window displayed. Depending on how HHCTRL has been called any window could be first. MODIFICATION DATES: 09-Nov-1997 [ralphw] 03-Mar-1998 [dalero] ***************************************************************************/ CHHWinType* FindCurWindow() { ASSERT(pahwnd != NULL) ; for (int i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] != NULL) { return pahwnd[i]; } } return NULL; } /////////////////////////////////////////////////////////// // // Delete all of the CHHWinType structures for this process. // void DeleteWindows() { ASSERT(pahwnd != NULL) ; for (int i = 0; i < g_cWindowSlots; i++) { if (pahwnd[i] != NULL) { CHHWinType* phh = pahwnd[i] ; //pahwnd[i] = NULL ; --- Set to null in the destructor... if (IsWindow(phh->hwndHelp)) { DestroyWindow(phh->hwndHelp) ; } else { delete phh ; } } } } /////////////////////////////////////////////////////////// // // Functions which operate on the m_aNavPane array. // /////////////////////////////////////////////////////////// // // CreateNavPane // static const WCHAR txtAuthorTab[] = L"HHAuthorTab.CustPane"; void CHHWinType::CreateNavPane(int iPane) { // Is this a valid pane number? if (iPane > c_NUMNAVPANES || iPane < 0) { ASSERT(0) ; return ; } // Has pane already been created? if (m_aNavPane[iPane]) { return ; // Already created. } // Create the pane. switch(iPane) { case HHWIN_NAVTYPE_TOC: CreateToc(); break ; case HHWIN_NAVTYPE_INDEX: CreateIndex(); break ; case HHWIN_NAVTYPE_SEARCH: CreateSearchTab(); break; case HHWIN_NAVTYPE_FAVORITES: CreateBookmarksTab() ; break ; #if 0 case HHWIN_NAVTYPE_HISTORY: //CreateHistoryTab(); ItDoesntWork() ; break ; #endif #ifdef __TEST_CUSTOMTAB__ case HHWIN_NAVTYPE_AUTHOR: CreateCustomTab(iPane, txtAuthorTab); break; #endif default: if (iPane < HH_MAX_TABS+1 && iPane >= HHWIN_NAVTYPE_CUSTOM_FIRST) { // We have a custom tab. EXTENSIBLE_TAB* pExtTab = GetExtTab(iPane - HH_TAB_CUSTOM_FIRST); if (pExtTab) { CWStr cwsz(pExtTab->pszProgId); CreateCustomTab(iPane, cwsz); } } else { ASSERT_COMMENT(0, "illegal tab index"); } } } /*************************************************************************** FUNCTION: doSelectTab PURPOSE: changes the current navigation tab PARAMETERS: RETURNS: TODO COMMENTS: MODIFICATION DATES: 27-Feb-1996 [ralphw] 09-Nov-1997 [ralphw] Moved to CHHWinType ***************************************************************************/ void CHHWinType::doSelectTab(int newTabIndex) { if ( newTabIndex < 0 ) return ; // Make sure we have tabs before we switch or toggle. if (!IsValidNavPane(curNavType)) return ; // make sure the nav pane is shown if (IsExpandedNavPane() == FALSE) ToggleExpansion(); // // 4/10/98 Bug 4701 - I've moved the m_pTabCtrl == NULL check to after the ToggleExpansion() call // done above because it's legitimate to have a NULL m_pTabCtrl pointer if we get to this code and the // nav pane has never been shown. The ToggleExpansion() call will instantiate m_pTabCtrl if the nav // pane is hidden and has never been shown. // if ( m_pTabCtrl == NULL ) return; // REVIEW: This is null when there isn't an FTS. See BUG 462 in RAID database. // Get the index of the currently selected tab. int oldTabIndex = GetCurrentNavPaneIndex() ; // Only change the tab if its not the current one. if (oldTabIndex != newTabIndex) { // This code was copied from WM_NOTIFY in wndproc.cpp. This should become common. ASSERT(curNavType >= 0 && curNavType < c_NUMNAVPANES) ; // Hide the current tab. if (m_aNavPane[curNavType]) { m_aNavPane[curNavType]->HideWindow(); } // Code throughout HHCtrl assumes that HH_NAVTYPE_* == HH_TAB_*. // but doesn't assert it anywhere. So I'm going to assert it here. ASSERT(HHWIN_NAVTYPE_SEARCH == HH_TAB_SEARCH) ; ASSERT(HHWIN_NAVTYPE_TOC == HH_TAB_CONTENTS) ; ASSERT(HHWIN_NAVTYPE_INDEX == HH_TAB_INDEX); ASSERT(HHWIN_NAVTYPE_FAVORITES == HH_TAB_FAVORITES); #ifdef _INTERNAL ASSERT(HHWIN_NAVTYPE_HISTORY == HH_TAB_HISTORY); #endif // Select the new navigation method. curNavType = newTabIndex; // Select the new current tab. int iNewTabCtrlIndex = GetTabIndexFromNavPaneIndex(newTabIndex) ; ASSERT(iNewTabCtrlIndex >= 0) ; int iRet = TabCtrl_SetCurSel(m_pTabCtrl->hWnd(), iNewTabCtrlIndex) ; ASSERT(iRet >= 0) ; ASSERT(tabOrder[iRet] == oldTabIndex) ; //REVIEW: If I've ever seen a use for virtual functions... // Create the new pane for the new current tab if necessary. CreateNavPane(newTabIndex) ; if (m_aNavPane[newTabIndex]) { m_aNavPane[newTabIndex]->ResizeWindow(); m_aNavPane[newTabIndex]->ShowWindow(); } // Update the tab window ::UpdateWindow(m_pTabCtrl->hWnd()) ; } //if if (m_aNavPane[newTabIndex]) m_aNavPane[newTabIndex]->SetDefaultFocus(); if ( m_pCIExpContainer ) m_pCIExpContainer->UIDeactivateIE(); // shdocvw is loosing focus need to uideactivate here. } /////////////////////////////////////////////////////////////////////////////// // // Restore if minimzied window, and set focus to the window // void CHHWinType::SetActiveHelpWindow(void) { if (IsIconic(*this)) ShowWindow(*this, SW_RESTORE); SetForegroundWindow(*this); // SetFocus(*this); } /////////////////////////////////////////////////////////////////////////////// // // Finds the currently selected tab in the tab control. It then looks in the // tabOrder array to find out the index into the array of nav panes for this control. // int CHHWinType::GetCurrentNavPaneIndex() { if( !m_pTabCtrl ) return -1; // REVIEW: All of this mapping between tabctrl index and nav pane index should be // hidden inside of the tabctrl... int index = -1 ; if (m_pTabCtrl && IsWindow(m_pTabCtrl->hWnd())) { index = (int)::SendMessage(m_pTabCtrl->hWnd(), TCM_GETCURSEL, 0, 0); index = tabOrder[index] ; } return index ; } /////////////////////////////////////////////////////////////////////////////// // // Finds the index of the tab on the tabctrl which co-responds to a particular // nav pane. // int CHHWinType::GetTabIndexFromNavPaneIndex(int iNavPaneIndex) { for(int i = 0 ; i < HH_MAX_TABS+1 ; i++) { //REVIEW: Not all of these entries are valid. Possible to get a bogus hit. See reorder tab. if( tabOrder[i] == iNavPaneIndex) { return i ; } } return -1 ; } /////////////////////////////////////////////////////////////////////////////// // // Translate the accelerators for the tabs. These are not in the global accelerator table. // bool CHHWinType::ManualTranslateAccelerator(char iChar) { CHAR ch = ToLower(iChar) ; // The Options menu button. if (ch == _Resource.TabCtrlKeys(ACCEL_KEY_OPTIONS) && GetToolBarHwnd()) { PostMessage( GetHwnd(), WM_COMMAND, IDTB_OPTIONS, 0); return true; } /* else if() // When adding in new cases, make sure not to eat a key. If you UI doesn't exist. // Let someone else have the key. */ else { // Handle the tab accelerator keys for (int i= 0 ; i < HH_MAX_TABS+1 ; i++) { if (ch == _Resource.TabCtrlKeys(i) && IsValidNavPane(i)) { doSelectTab(i) ; return true ; } } // Handle the nav panes accelerator keys if (m_aNavPane[curNavType]) { if (m_aNavPane[curNavType]->ProcessMenuChar(GetHwnd(),ch) ) { if ( m_pCIExpContainer ) m_pCIExpContainer->UIDeactivateIE(); // shdocvw is loosing focus need to uideactivate here. return true ; } } } return false ; } /////////////////////////////////////////////////////////////////////////////// // // Dynamically build an accelerator table for this window... // bool CHHWinType::DynamicTranslateAccelerator(MSG* pMsg) { bool bReturn = false ; if (IsWindow(GetHwnd())) { if (!m_hAccel) { // Get the static accelerators table; HACCEL hAccelStatic = _Resource.AcceleratorTable() ; // Get number of accelerator table entries. int cStaticAccelEntries = CopyAcceleratorTable(hAccelStatic, NULL, 0); // Add on the options menu and the tabs... int cAccelEntries = cStaticAccelEntries + HH_MAX_TABS + 2 ; // Allocate structure to hold accelerator table. ACCEL* accel = new ACCEL[cAccelEntries] ; if (!accel) return false ; // Copy the table into the structure: CopyAcceleratorTable(hAccelStatic, accel, cStaticAccelEntries ) ; // Add on dynamic accelerators. int index = cStaticAccelEntries; // Add on options menu. if (fsToolBarFlags & HHWIN_BUTTON_OPTIONS) { accel[index].fVirt = FALT | FNOINVERT | FVIRTKEY ; accel[index].key = (WORD)ToUpper(_Resource.TabCtrlKeys(ACCEL_KEY_OPTIONS)) ; accel[index].cmd = IDTB_OPTIONS ; index++ ; } // Add on accelerators for each tab. for (int i= 0 ; i < HH_MAX_TABS+1 ; i++) { if (IsValidNavPane(i)) { accel[index].fVirt = FALT | FNOINVERT | FVIRTKEY; accel[index].key = (WORD)ToUpper(_Resource.TabCtrlKeys(i)) ; accel[index].cmd = IDC_SELECT_TAB_FIRST + i ; index++ ; } } // Create the accelerator table. m_hAccel = CreateAcceleratorTable(accel, index) ; // Cleanup delete [] accel ; } bReturn = (TranslateAccelerator(GetHwnd(), m_hAccel, pMsg) != 0 ) ; } if (bReturn) { DBWIN("--- Translated Accelerator ---") ; } return bReturn ; } /////////////////////////////////////////////////////////////////////////////// // // Stolen from System.cpp...readsystemfiles. Should be shared. // LPSTR _MakeItFullPath(LPCTSTR name, CHmData* phmData) { LPSTR pszReturn = NULL ; CStr csz(name) ; if (csz.IsNonEmpty()) { if (!stristr(csz, txtDoubleColonSep) && !stristr(csz, txtFileHeader) && !stristr(csz, txtHttpHeader)) { CStr cszCompiledFile ; cszCompiledFile = phmData->GetCompiledFile(); cszCompiledFile += txtSepBack; cszCompiledFile += csz.psz; //Transfer pointer. pszReturn = cszCompiledFile.psz ; cszCompiledFile.psz = NULL ; } else { // Transfer pointer. pszReturn = csz.psz ; csz.psz = NULL ; } } return pszReturn ; } /////////////////////////////////////////////////////////////////////////////// // // Kills all of the nav panes and then re-fills them with the new CHM data. // bool CHHWinType::ReloadNavData(CHmData* phmdata) { if (!phmdata) return false; //--- Do we have valid data? char* pszTocNew = NULL ; char* pszIndexNew = NULL ; // Only if we currently have a TOC, will we get the new toc. if (IsNonEmptyString(pszToc)) { pszTocNew = _MakeItFullPath(phmdata->GetDefaultToc(), phmdata) ; } // Only if we currently have an INDEX, will we get the new index. if (IsNonEmptyString(pszIndex)) { pszIndexNew = _MakeItFullPath(phmdata->GetDefaultIndex(), phmdata) ; } // CHM doesn't have a default TOC or CHM which we need. So look up one in the default window type. if ((IsNonEmptyString(pszToc) && IsEmptyString(pszTocNew)) || (IsNonEmptyString(pszIndex) && IsEmptyString(pszIndexNew))) { CHECK_AND_FREE(pszTocNew) ; CHECK_AND_FREE(pszIndexNew) ; // Office Beta work around: Less attempt looking in the default window type. if (IsNonEmptyString(phmdata->GetDefaultWindow())) { CHHWinType* pDefWinTypeNew = FindWindowType(phmdata->GetDefaultWindow(), NULL, phmdata->GetCompiledFile()) ; if (pDefWinTypeNew) { if (IsNonEmptyString(pszToc)) { pszTocNew = _MakeItFullPath(pDefWinTypeNew->pszToc, phmdata) ; } if (IsNonEmptyString(pszIndex)) { pszIndexNew = _MakeItFullPath(pDefWinTypeNew->pszIndex, phmdata) ; } } } // If we still aren't in sync, fail. if ((IsNonEmptyString(pszToc) && IsEmptyString(pszTocNew)) || (IsNonEmptyString(pszIndex) && IsEmptyString(pszIndexNew))) { CHECK_AND_FREE(pszTocNew) ; CHECK_AND_FREE(pszIndexNew) ; return false ; } } //--- Kill all nav panes and cleanup other infomation ReloadCleanup() ; //--- Clean up some more stuff... //--- Start re-initializing... m_phmData = phmdata; pszToc = pszTocNew ; pszIndex = pszIndexNew ; pszFile = lcStrDup(phmdata->GetDefaultHtml()); //_MakeItFullPath(phmdata->m_pszDefHtml, phmdata); //TODO: I think we need to get a window name to read from....ick pszJump1 = NULL; pszJump2 = NULL; pszUrlJump1 = NULL; pszUrlJump2 = NULL; //--- Okay, lets start up the first current tab... if (IsExpandedNavPane()) { // We have a naviation pane which we need to re-create. fNotExpanded = TRUE ; // Force a re-creation. ToggleExpansion(false) ; } return true ; } ////////////////////////////////////////////////////////////////////////// // // Restores the focus to the ctrl which had it focus during the last WM_ACTIVATE. // bool CHHWinType::RestoreCtrlWithFocus() { if (m_hwndLastFocus) { SetFocus(m_hwndLastFocus) ; m_hwndLastFocus = NULL ; return true ; } else { return false ; } } ////////////////////////////////////////////////////////////////////////// // // Saves hwnd of ctrl with focus during WM_ACTVIATE (INACTIVATE). // void CHHWinType::SaveCtrlWithFocus() { m_hwndLastFocus = GetFocus() ; } ////////////////////////////////////////////////////////////////////////// // // GetExtTabCount // int CHHWinType::GetExtTabCount() { // If we have an original, pre-reload navdata ChmData. Use that to get the custom tab information. if (m_phmDataOrg) return m_phmDataOrg->GetExtTabCount(); else if (m_phmData) return m_phmData->GetExtTabCount(); // Review: Will this ever happen? else return 0; } ////////////////////////////////////////////////////////////////////////// // // GetExtTab // EXTENSIBLE_TAB* CHHWinType::GetExtTab(int pos) { if (m_phmDataOrg) return m_phmDataOrg->GetExtTab(pos); else if (m_phmData) return m_phmData->GetExtTab(pos); // Review:: will this ever happen? else return NULL; } /////////////////////////////////////////////////////////////////////////////// // MUI support // // This InsertMenuItem wrapper will translate the MENUITEMINFOA structure // to a MENUITEMINFOW and call InsertMenuItemW when running under Windows 2000. // BOOL HxInsertMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition, MENUITEMINFOA *lpmii) { if(g_bWinNT5 && (lpmii->fMask | MIIM_TYPE) && lpmii->fType == MFT_STRING) { DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT)); DWORD dwSize = (sizeof(WCHAR) * lpmii->cch) + 4; WCHAR *pwcString = (WCHAR *) lcMalloc(dwSize); if(!pwcString || !(lpmii->cch)) return FALSE; MultiByteToWideChar(cp, MB_PRECOMPOSED, lpmii->dwTypeData, -1, pwcString, dwSize); lpmii->dwTypeData = (CHAR *) pwcString; lpmii->cch = wcslen((WCHAR *)lpmii->dwTypeData); BOOL ret = InsertMenuItemW(hMenu, uItem, fByPosition, (LPMENUITEMINFOW) lpmii); lcFree(pwcString); return ret; } else { return InsertMenuItem(hMenu, uItem, fByPosition, lpmii); } }