WindowsXP-SP1/enduser/stuff/hhctrl/chistory.cpp

370 lines
11 KiB
C++

// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
#include "header.h"
#include "hha_strtable.h"
#include "strtable.h"
#include "hhctrl.h"
#include "resource.h"
#include "chistory.h"
#include "secwin.h"
#ifdef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__;
#endif
#define BOX_HEIGHT 24
#define DEF_BUTTON_WIDTH 70
LRESULT WINAPI EditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
extern WNDPROC lpfnlEditWndProc;
CHistory::CHistory(PCSTR pszPastHistory)
: m_hwndResizeToParent(NULL)
{
if (pszPastHistory)
m_cszPastHistory = pszPastHistory;
m_hfont = NULL;
m_fSelectionChange = FALSE;
m_padding = 2; // padding to put around the Index
m_NavTabPos = HHWIN_NAVTAB_TOP; //BUGBUG: If the navpos is different this is broken.
m_fModified = FALSE;
}
CHistory::~CHistory()
{
if (m_hfont)
DeleteObject(m_hfont);
}
BOOL CHistory::Create(HWND hwndParent)
{
RECT rcParent, rcChild;
// Save the hwndParent for ResizeWindow.
m_hwndResizeToParent = hwndParent ;
// Note: GetParentSize will return hwndNavigation if hwndParent is the
// tab ctrl.
hwndParent = GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
CopyRect(&rcChild, &rcParent);
rcChild.bottom = rcChild.top + BOX_HEIGHT;
m_hwndEditBox = CreateWindowEx(WS_EX_CLIENTEDGE, "edit", "",
WS_CHILD | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, rcChild.left, rcChild.top,
RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), hwndParent,
(HMENU) IDEDIT_INDEX, _Module.GetModuleInstance(), NULL);
if (!m_hwndEditBox)
return FALSE;
rcChild.bottom = rcParent.bottom - 2;
rcChild.top = rcChild.bottom - BOX_HEIGHT;
m_hwndDisplayButton = CreateWindow("button",
GetStringResource(IDS_ENGLISH_DISPLAY),
WS_CHILD | WS_TABSTOP, rcChild.left, rcChild.top,
RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), hwndParent,
(HMENU) IDBTN_DISPLAY, _Module.GetModuleInstance(), NULL);
if (!m_hwndDisplayButton) {
DestroyWindow(m_hwndEditBox);
return FALSE;
}
// +2 for border, +BOX_HEIGHT for edit box, +5 for spacing.
rcChild.top = rcParent.top + 2 + BOX_HEIGHT + 5;
rcChild.bottom = rcParent.bottom - (2 + BOX_HEIGHT + 5);
m_hwndListBox = CreateWindowEx(WS_EX_CLIENTEDGE, "listbox",
"", WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VSCROLL |
LBS_NOTIFY,
rcChild.left, rcChild.top, RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild),
hwndParent, (HMENU) IDLB_INDEX, _Module.GetModuleInstance(), NULL);
if (!m_hwndListBox) {
DestroyWindow(m_hwndDisplayButton);
DestroyWindow(m_hwndEditBox);
return FALSE;
}
// Use a more readable font
SendMessage(m_hwndListBox, WM_SETFONT,
m_hfont ? (WPARAM) m_hfont : (WPARAM) _Resource.GetUIFont(), FALSE);
SendMessage(m_hwndEditBox, WM_SETFONT,
m_hfont ? (WPARAM) m_hfont : (WPARAM) _Resource.GetUIFont(), FALSE);
SendMessage(m_hwndDisplayButton, WM_SETFONT,
m_hfont ? (WPARAM) m_hfont : (WPARAM) _Resource.GetUIFont(), FALSE);
// Sub-class the edit box
if (lpfnlEditWndProc == NULL)
lpfnlEditWndProc = (WNDPROC) GetWindowLongPtr(m_hwndEditBox, GWLP_WNDPROC);
SetWindowLongPtr(m_hwndEditBox, GWLP_WNDPROC, (LONG_PTR) EditProc);
FillListBox();
return TRUE;
}
void CHistory::HideWindow(void)
{
::ShowWindow(m_hwndEditBox, SW_HIDE);
::ShowWindow(m_hwndListBox, SW_HIDE);
::ShowWindow(m_hwndDisplayButton, SW_HIDE);
}
void CHistory::ShowWindow(void)
{
::ShowWindow(m_hwndEditBox, SW_SHOW);
::ShowWindow(m_hwndListBox, SW_SHOW);
::ShowWindow(m_hwndDisplayButton, SW_SHOW);
}
void CHistory::ResizeWindow()
{
ASSERT(::IsValidWindow(m_hwndDisplayButton)) ;
// Resize to fit the client area of the parent.
HWND hwndParent = m_hwndResizeToParent ; // Use the original window.
ASSERT(::IsValidWindow(hwndParent)) ;
RECT rcParent, rcChild;
GetParentSize(&rcParent, hwndParent, m_padding, m_NavTabPos);
CopyRect(&rcChild, &rcParent);
rcChild.bottom = rcChild.top + BOX_HEIGHT;
MoveWindow(m_hwndEditBox, rcChild.left,
rcChild.top, RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), TRUE);
rcChild.bottom = rcParent.bottom - 2;
rcChild.top = rcChild.bottom - BOX_HEIGHT;
rcChild.left = rcChild.right - DEF_BUTTON_WIDTH;
MoveWindow(m_hwndDisplayButton, rcChild.left,
rcChild.top, RECT_WIDTH(rcChild), RECT_HEIGHT(rcChild), TRUE);
// +2 for border, +BOX_HEIGHT for edit box, +5 for spacing.
rcChild.top = rcParent.top + 2 + BOX_HEIGHT + 5;
rcChild.bottom = rcParent.bottom - (2 + BOX_HEIGHT + 5);
MoveWindow(m_hwndListBox, rcParent.left,
rcChild.top, RECT_WIDTH(rcParent), RECT_HEIGHT(rcChild), TRUE);
}
void CHistory::FillListBox(BOOL fReset)
{
// BUGBUG: do we need this?
}
// This function has the lookup code, so we want it as fast as possible
LRESULT CHistory::OnCommand(HWND /*hwnd*/, UINT id, UINT uNotifiyCode, LPARAM /*lParam*/)
{
#if 0
CStr cszKeyword;
int pos;
SITEMAP_ENTRY* pSiteMapEntry;
int i;
switch (id) {
case IDEDIT_INDEX:
{
if (uNotifiyCode != EN_CHANGE)
return 0;
if (m_fSelectionChange) {
m_fSelectionChange = FALSE;
return 0;
}
CStr cszKeyword(m_hwndEditBox);
if (!*cszKeyword.psz)
return 0;
/*
* REVIEW: This could be sped up by having a first character
* lookup, ala the RTF tokens in lex.cpp (hcrtf). Putting this
* in the thread would also improve user responsiveness.
*/
for (i = 1; i <= CountStrings(); i++) {
pSiteMapEntry = GetSiteMapEntry(i);
ASSERT_COMMENT(pSiteMapEntry->GetKeyword(), "Index entry added without a keyword");
/*
* Unless the user specifically requested it, we don't
* allow the keyboard to be used to get to anything other
* then first level entries.
*/
if (!g_fNonFirstKey && pSiteMapEntry->GetLevel() > 1)
continue;
// BUGBUG: isSameString is not lcid aware
if (isSameString(pSiteMapEntry->GetKeyword(), cszKeyword)) {
SendMessage(m_hwndListBox, LB_SETCURSEL, i - 1, 0);
break;
}
}
}
return 0;
case IDLB_INDEX:
switch (uNotifiyCode) {
case LBN_SELCHANGE:
if ((pos = SendMessage(m_hwndListBox,
LB_GETCURSEL, 0, 0L)) == LB_ERR)
return 0;
pSiteMapEntry = GetSiteMapEntry(pos + 1);
m_fSelectionChange = TRUE; // ignore EN_CHANGE
SetWindowText(m_hwndEditBox, pSiteMapEntry->GetKeyword());
m_fSelectionChange = FALSE; // ignore EN_CHANGE
return 0;
case LBN_DBLCLK:
PostMessage(FindMessageParent(m_hwndListBox), WM_COMMAND,
MAKELONG(IDBTN_DISPLAY, BN_CLICKED), 0);
return 0;
}
return 0;
case IDBTN_DISPLAY:
if (uNotifiyCode == BN_CLICKED) {
if ((pos = SendMessage(m_hwndListBox,
LB_GETCURSEL, 0, 0L)) == LB_ERR)
return 0;
CStr cszKeyword(m_hwndEditBox);
pSiteMapEntry = GetSiteMapEntry(pos + 1);
#ifdef _DEBUG
PCSTR pszKeyword = pSiteMapEntry->GetKeyword();
#endif
int cbKeyword = strlen(cszKeyword);
if (strlen(pSiteMapEntry->GetKeyword()) < cbKeyword ||
CompareString(g_lcidSystem, NORM_IGNORECASE,
pSiteMapEntry->GetKeyword(), cbKeyword,
cszKeyword, cbKeyword) != 2) {
MsgBox(IDS_NO_SUCH_KEYWORD);
SetFocus(m_hwndEditBox);
return 0;
}
if (pSiteMapEntry->fSeeAlso) {
/*
* A See Also entry simply jumps to another location
* in the Index.
*/
SetWindowText(m_hwndEditBox,
GetUrlString(pSiteMapEntry->pUrls->urlPrimary));
return 0;
}
// If we have one or more titles, then give the user
// a choice of what to jump to.
if (pSiteMapEntry->cUrls > 1) {
CHistoryTopics dlgTopics(
m_phhctrl ? m_phhctrl->m_hwnd : FindMessageParent(m_hwndEditBox),
pSiteMapEntry, this);
if (m_phhctrl)
m_phhctrl->ModalDialog(TRUE);
int fResult = dlgTopics.DoModal();
if (m_phhctrl)
m_phhctrl->ModalDialog(FALSE);
if (fResult)
JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, this, dlgTopics.m_pUrl);
SetFocus(m_hwndEditBox);
return 0;
}
JumpToUrl(m_pOuter, m_hwndListBox, pSiteMapEntry, this, NULL);
SetFocus(m_hwndEditBox);
}
return 0;
case ID_VIEW_ENTRY:
{
if ((pos = SendMessage(m_hwndListBox,
LB_GETCURSEL, 0, 0L)) == LB_ERR)
return 0;
pSiteMapEntry = GetSiteMapEntry(pos + 1);
DisplayAuthorInfo(this, pSiteMapEntry, FindMessageParent(m_hwndListBox), m_phhctrl);
}
return 0;
#ifdef _DEBUG
case ID_VIEW_MEMORY:
OnReportMemoryUsage();
return 0;
#endif
}
#endif // 0
return 0;
}
void CHHWinType::CreateHistoryTab(void)
{
#ifdef _DEBUG
CHistory* pHistory = new CHistory(NULL);
m_aNavPane[HH_TAB_HISTORY] = pHistory ;
pHistory->SetPadding(10);
pHistory->SetTabPos(tabpos);
pHistory->Create((m_pTabCtrl ? m_pTabCtrl->hWnd() : hwndNavigation));
#endif
}
void CHHWinType::AddToHistory(PCSTR pszTitle, PCSTR pszUrl)
{
#ifndef _DEBUG
return;
#else
if (!m_aNavPane[HH_TAB_HISTORY])
return;
CHistory* pHistory = (CHistory*)m_aNavPane[HH_TAB_HISTORY]; //HACKHACK: Needs dynamic_cast.
CDlgListBox lb;
lb.m_hWnd = pHistory->m_hwndListBox;
int lbpos = (int)lb.FindString(pszTitle);
if (lbpos == LB_ERR) {
/*
* OnTitleChange gets called before we have the real title, so the
* title may actually change. If so, we want to delete the previous
* title and the new one.
*/
int pos = pHistory->m_tblHistory.IsStringInTable(pszUrl);
if (pos > 0) {
INT_PTR cbItems = lb.GetCount();
ASSERT(cbItems != LB_ERR);
for (int i = 0; i < cbItems; i++) {
if (pos == lb.GetItemData(i))
break;
}
if (i < cbItems)
lb.DeleteString(i);
if (IsProperty(HHWIN_PROP_CHANGE_TITLE))
SetWindowText(*this, pszTitle);
}
else
pos = pHistory->m_tblHistory.AddString(pszUrl);
int lbpos = (int)lb.AddString(pszTitle);
lb.SetItemData(lbpos, pos);
}
else {
if (IsProperty(HHWIN_PROP_CHANGE_TITLE))
SetWindowText(*this, pszTitle);
}
lb.SetCurSel(lbpos);
#endif
}