Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2945 lines
88 KiB

// find.cpp : implementation file
//
#include "stdafx.h"
//#include <ctl3d.h>
#include "memex.h"
#include "ftsrch.h"
#include "ftsiface.h"
#include "TxDBase.h"
#include "wordbase.h"
#include "filebase.h"
#include "find.h"
#include "findopti.h"
#include "displayh.h"
// REVIEW: why are you pulling in ctype.h? Almost never works with non-English
#include "ctype.h" //rmk
#include "ftslex.h" //rmk
#include "dict.h"
#include "vector.h"
#include "query.h"
#include "dialogs.h"
#include "CSHelp.h"
#include "ftsrchlp.h"
#include "abrtsrch.h"
// #include "Except.h" // included in stdafx.h
extern BOOL IsAPrefix(PWCHAR pbStringL, UINT cbStringL, PWCHAR pbStringR, UINT cbStringR);
extern BOOL IsASuffix(PWCHAR pbStringL, UINT cbStringL, PWCHAR pbStringR, UINT cbStringR);
extern BOOL IsASubstring(PWCHAR pbStringL, UINT cbStringL, PWCHAR pbStringR, UINT cbStringR);
extern HFONT GetDefaultFont();
char acMap[] = {1,0,2,3}; // Maps combo box indices into the string match conditions.
static WNDPROC m_dpOldProc;
/////////////////////////////////////////////////////////////////////////////
#define CB_QUERY_MAX 256
// int WGetWindowText(HWND hwndEditBox, PWCHAR pwText, int cwText)
// Wide char version of GetWindowText API that resolves system dependencies
//
int WGetWindowText(HWND hwndEditBox, PWCHAR pwText, int cwText)
{
if (uOpSys == WINNT) // On NT use the API
return GetWindowTextW(hwndEditBox, pwText, cwText);
else
{ // otherwise get the text and
int cText; // convert it to WideChar
char szText[CB_QUERY_MAX];
cText = ::GetWindowText(hwndEditBox, szText, CB_QUERY_MAX);
return MultiByteToWideChar(GetACP(), 0, szText, cText, pwText, cwText);
}
}
BOOL CFind::RegisterWndClass(HINSTANCE hInstance)
{
PSZ szName = "FtsrchFind";
WNDCLASS wndcls;
// see if the class already exists
if (::GetClassInfo(hInstance, szName, &wndcls)) return TRUE;
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
wndcls.lpfnWndProc = DefDlgProc;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = DLGWINDOWEXTRA;
wndcls.hInstance = hInstance;
wndcls.hIcon = NULL;
wndcls.hCursor = hcurArrow;
wndcls.hbrBackground = NULL;
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = szName;
return ::RegisterClass(&wndcls);
}
// Find creator
CFind* CFind::NewFind(HINSTANCE hInst, UINT idTemplate, HWND hOwner, CTextSet **papts,
UINT cts, UINT ctsSlots, CTokenCollection *ptkc, CTitleCollection *ptlc
)
{
CFind *pFind= NULL;
__try
{
pFind= New CFind;
pFind->InitialFind(hInst, idTemplate, hOwner, papts, cts, ctsSlots, ptkc, ptlc);
}
__finally
{
if (_abnormal_termination() && pFind)
{
delete pFind; pFind= NULL;
}
}
::hwndMain= pFind->GetHWnd();
return pFind;
}
// Constructor for the Find dialog.
CFind::CFind()
{
m_hDlg = NULL;
m_hwndFocus = NULL;
m_hInst = NULL;
m_hFont = NULL;
m_serial = 0; // validity count for hiliers
m_fExitPending = 0; // mfcc
m_fDoneSearching = 0; // mfcc
m_hTopicsFound = NULL;
m_hWordsFound = NULL;
m_hwndEditBox = NULL;
m_rbgTopics = 0;
m_iLookFor = ALL_WORDS;
m_iWordsThat = BEGIN_WITH;
m_iWordsThatLast = BEGIN_WITH;
m_iTokenStart = 0;
m_iStart = 0;
m_iEnd = 0;
m_iDirtyFactor = 0;
m_uiTimeOut = 450; // Default to 450ms timeout.
// The SetTimeOut public member function
// can change the timeout on the fly.
m_fIgnoreSelectionChanges = FALSE;
m_fDeferredSearch = FALSE;
m_bAutoSearch = TRUE;
m_uiClearStatus = 0;
m_pWordBase = NULL;
m_pfs = NULL;
m_papts = NULL;
m_cts = 0;
m_ctsSlots = 0;
m_ptkc = NULL;
m_ptlc = NULL;
m_pwcLastQuery = NULL;
m_cfiActive = 0;
m_cfiAllocated = 0;
m_ptdContext = NULL;
m_ptlTermPatterns = NULL;
m_pflArticles = NULL;
m_pisWordSet = NULL;
m_pisArticleSet = NULL;
m_pisArticleSubset = NULL;
m_ppisPhraseFilter = NULL;
m_pRankDialog = NULL;
m_fFromSimilarTopics = FALSE;
m_cMaxToFind = 200; // max number of documents to retrieve from a relevance feedback search
m_OptionDlgPos.x= REALLY_OFFSCREEN;
m_OptionDlgPos.y= REALLY_OFFSCREEN;
}
// Initialer for the Find dialog
void CFind::InitialFind(HINSTANCE hInst, UINT idTemplate, HWND hOwner, CTextSet **papts, UINT cts, UINT ctsSlots,
CTokenCollection *ptkc, CTitleCollection *ptlc
)
{
RECT rct;
m_hInst = hInst;
m_papts = papts;
m_cts = cts;
m_ctsSlots = ctsSlots;
m_ppisPhraseFilter = (CIndicatorSet **) VAlloc(TRUE, ctsSlots * sizeof(CIndicatorSet *));
AttachRef(m_ptkc, ptkc);
AttachRef(m_ptlc, ptlc);
m_pwcLastQuery = m_awcQueryPair;
ZeroMemory(m_apfi, C_TERMS_MAX * sizeof(PFragInfo));
AttachRef(m_pflArticles, CFileList::NewFileList(m_ptlc));
AttachRef(m_ptlTermPatterns, New CTokenList);
// Read Values from Regitry for setup
HKEY hkPerUser;
LONG lResult;
BOOL bReadData = FALSE;
LPTSTR pbString = (LPTSTR) _alloca(MAX_QUERY_STRING);
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, SZ_REGISTRY_KEY, 0, KEY_READ, &hkPerUser);
if (lResult == ERROR_SUCCESS) // have we already registered the data?
{
bReadData = TRUE;
}
else
{
DWORD dwDis;
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, SZ_REGISTRY_KEY, 0,
"Application Per-User Data", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL, &hkPerUser, &dwDis);
if (lResult == ERROR_SUCCESS)
{
if (dwDis == REG_OPENED_EXISTING_KEY)
{
bReadData = TRUE;
}
else RegCloseKey(hkPerUser); // we just created it for the first time!
}
}
if (bReadData == TRUE)
{
DWORD dwType,dwSize;
dwSize = sizeof(m_OptionDlgPos.x);
lResult = RegQueryValueEx(hkPerUser, SZ_OPTION_X, NULL, (LPDWORD) &dwType, (LPBYTE) &m_OptionDlgPos.x, (LPDWORD) &dwSize);
dwSize = sizeof(m_OptionDlgPos.y);
lResult = RegQueryValueEx(hkPerUser,SZ_OPTION_Y, NULL,(LPDWORD) &dwType,(LPBYTE) &m_OptionDlgPos.y, (LPDWORD) &dwSize);
dwSize = sizeof(m_iLookFor);
lResult = RegQueryValueEx(hkPerUser,SZ_HOW_TO_SEARCH, NULL,(LPDWORD) &dwType,(LPBYTE) &m_iLookFor, (LPDWORD) &dwSize);
dwSize = sizeof(m_bAutoSearch);
lResult = RegQueryValueEx(hkPerUser,SZ_WHEN_TO_SEARCH, NULL,(LPDWORD) &dwType,(LPBYTE) &m_bAutoSearch, (LPDWORD) &dwSize);
dwSize = sizeof(m_uiTimeOut);
lResult = RegQueryValueEx(hkPerUser,SZ_WHEN_DELAY,NULL,(LPDWORD) &dwType,(LPBYTE) &m_uiTimeOut, (LPDWORD) &dwSize);
dwSize = sizeof(m_iWordsThat);
lResult = RegQueryValueEx(hkPerUser,SZ_WORDS_TO_SHOW, NULL,(LPDWORD) &dwType,(LPBYTE) &m_iWordsThat, (LPDWORD) &dwSize);
#if 0
dwSize = sizeof(m_bPhraseFeedback);
lResult = RegQueryValueEx(hkPerUser,SZ_PHRASEFEEDBACK, NULL,(LPDWORD) &dwType,(LPBYTE) &m_bPhraseFeedback, (LPDWORD) &dwSize);
#else
m_bPhraseFeedback= m_ptkc->PhraseFeedback();
#endif
RegCloseKey(hkPerUser);
}
if (m_iLookFor == PHRASE && !m_ptkc->PhraseSearch())
m_iLookFor = ALL_WORDS;
// Note: The initial fragment info object must be created after the RegQueryValueA calls above.
// Prior to those calls, we don't have the correct value for m_iLookFor.
m_apfi[0] = CFragInfo::NewFragInfo(m_ptkc, m_ptlc, (RefType)m_iLookFor, m_bPhraseFeedback, m_iWordsThat); // mfcc
m_cfiActive = 1;
m_cfiAllocated = 1;
// Ctl3dRegister(m_hInst);
// Ctl3dAutoSubclass(m_hInst);
ASSERT(hOwner && IsWindow(hOwner));
m_hDlg = ::CreateDialogParam(m_hInst, MAKEINTRESOURCE(IDD_FIND), hOwner, (DLGPROC) DlgWndProc, (LPARAM) this);
::GetWindowRect(m_hDlg,&rct);
::MoveWindow(m_hDlg,0, 0, rct.right - rct.left , rct.bottom- rct.top,TRUE); // Move the Dialog for now
HWND hWndEdit = ::GetWindow(GetDlgItem(m_hDlg,IDC_NARROW),GW_CHILD); // find the edit box
::SetProp(hWndEdit,"FindClass",(HANDLE) this); // give it a pointer to this object
m_dpOldProc = (WNDPROC) SetWindowLong(hWndEdit,GWL_WNDPROC,(LPARAM) &CFind::DlgEdtProc); // Subclass it
m_pRankDialog = NULL;
}
CFind::~CFind()
{
// Ctl3dUnregister(m_hInst);
if (m_hDlg)
{
::SendMessage(m_hDlg, UM_CLOSE, 0, 0);
::hwndMain= NULL;
}
if (m_ptkc) DetachRef(m_ptkc);
if (m_ptlc) DetachRef(m_ptlc);
UINT i;
for (i= m_cfiAllocated; i--; ) delete m_apfi[i];
for (i= m_cts; i--; )
if (m_ppisPhraseFilter[i]) DetachRef(m_ppisPhraseFilter[i]);
VFree(m_ppisPhraseFilter); m_ppisPhraseFilter= NULL;
if (m_pisWordSet ) DetachRef(m_pisWordSet );
if (m_pisArticleSet ) DetachRef(m_pisArticleSet );
if (m_pisArticleSubset) DetachRef(m_pisArticleSubset);
if (m_pflArticles ) DetachRef(m_pflArticles );
if (m_ptlTermPatterns ) DetachRef(m_ptlTermPatterns );
LONG lResult;
HKEY hkPerUser;
BOOL bWriteData = FALSE;
LPTSTR pbString = (LPTSTR) _alloca(MAX_QUERY_STRING);
lResult = RegOpenKeyEx(HKEY_CURRENT_USER,SZ_REGISTRY_KEY,0,KEY_WRITE,&hkPerUser);
if (lResult == ERROR_SUCCESS) // have we already registered the data?
{
bWriteData = TRUE;
}
else
{
DWORD dwDis; // Did someone delete the registry while we were running?
lResult = RegCreateKeyEx(HKEY_CURRENT_USER,SZ_REGISTRY_KEY,0,
"Application Per-User Data", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
NULL,&hkPerUser,&dwDis);
if (lResult == ERROR_SUCCESS)
{
bWriteData = TRUE;
}
}
if (bWriteData == TRUE)
{
lResult = RegSetValueEx(hkPerUser,SZ_OPTION_X, NULL, REG_DWORD, (LPBYTE) &m_OptionDlgPos.x, sizeof(m_OptionDlgPos.x));
lResult = RegSetValueEx(hkPerUser,SZ_OPTION_Y, NULL, REG_DWORD, (LPBYTE) &m_OptionDlgPos.y, sizeof(m_OptionDlgPos.y));
lResult = RegSetValueEx(hkPerUser,SZ_HOW_TO_SEARCH, NULL, REG_DWORD, (LPBYTE) &m_iLookFor, sizeof(m_iLookFor));
lResult = RegSetValueEx(hkPerUser,SZ_WHEN_TO_SEARCH, NULL, REG_DWORD, (LPBYTE) &m_bAutoSearch, sizeof(m_bAutoSearch));
lResult = RegSetValueEx(hkPerUser,SZ_WHEN_DELAY,NULL, REG_DWORD, (LPBYTE) &m_uiTimeOut, sizeof(m_uiTimeOut));
lResult = RegSetValueEx(hkPerUser,SZ_WORDS_TO_SHOW, NULL, REG_DWORD, (LPBYTE) &m_iWordsThat, sizeof(m_iWordsThat));
#if 0
lResult = RegSetValueEx(hkPerUser,SZ_PHRASEFEEDBACK, NULL, REG_DWORD, (LPBYTE) &m_bPhraseFeedback,sizeof(m_bPhraseFeedback));
#endif
RegCloseKey(hkPerUser);
}
if (m_pRankDialog)
delete m_pRankDialog;
m_pRankDialog = NULL;
}
HWND CFind::GetHWnd()
{
return m_hDlg;
}
#ifdef _DEBUG
static UINT cEditCalls= 0;
#endif // _DEBUG
int CFind::OnInitDialog(HWND hDlg, HWND hFocusControl, LPARAM lParam)
{
char acString1[MAX_QUERY_STRING+1];
char acString2[MAX_QUERY_STRING+1];
CInterface::PostponeEvents();
m_hDlg = hDlg;
// Save the lParam (pointer to the class object) un DWL_USER
SetWindowLong(hDlg,DWL_USER,lParam);
// Load the strings for the options display static
::LoadString(m_hInst,IDS_OPT_HEAD,acString1,MAX_QUERY_STRING);
strcpy(acString2,acString1);
::LoadString(m_hInst,IDS_TOPICS_ANY + m_iLookFor,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
::LoadString(m_hInst,IDS_WORD_BEGIN + m_iWordsThat,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
::LoadString(m_hInst,IDS_FIND_NOW + (m_bAutoSearch ? 1:0),acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
if (m_bAutoSearch && GetTimeout() != 0)
{
::LoadString(m_hInst,IDS_PAUSE,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
}
// Set the text into the static
::SetWindowText(GetDlgItem(hDlg,IDC_OPTIONS_STRING),acString2);
CheckDlgButton(hDlg,IDC_ADV_TOPICS_THAT + m_rbgTopics,1);
EnableWindow(GetDlgItem(hDlg,IDC_SEARCH_NOW),!m_bAutoSearch);
m_hFont= GetDefaultFont();
if (!m_pWordBase)
{
m_pWordBase= CWordBase::NewWordBase(m_ptkc, m_hInst, hDlg);
if (m_hFont)
m_pWordBase->SetFont(m_hFont);
m_pWordBase->PMaskedTokenList()->SetSelection(CIndicatorSet::NewIndicatorSet(m_ptkc->RowCount(), m_iLookFor != ANY_WORD));
OnWordListSelCancel(); // Update the words matching string
}
if (!m_pfs) // create and size the topics list box...
{
m_pfs= CFileBase::NewFileBase(m_pflArticles, hDlg);
if (m_hFont)
m_pfs->SetFont(m_hFont);
if (m_ptkc->SimilaritySearch()) m_pfs->EnableCheckboxes(TRUE);
}
m_hTopicsFound = GetDlgItem(hDlg,IDC_TOPICSFOUND_STATIC);
m_hwndEditBox= ::GetWindow(GetDlgItem(m_hDlg,IDC_NARROW),GW_CHILD);
::LoadString(m_hInst,IDS_NUM_TOPICS_FOUND,acString1,MAX_QUERY_STRING);
wsprintf(acString2,acString1,m_pflArticles->RowCount());
::SetWindowText(m_hTopicsFound,acString2);
m_rbgTopics = 0;
UpdateWindow(hDlg);
CInterface::ReleaseEvents();
SetFocusToEdit();
return FALSE; // return TRUE unless you set the focus to a control
}
void CFind::OnNCDestroy()
{
// REVIEW: why assign m_hDlg to hdlg when it isn't used?
HWND hdlg= m_hDlg; m_hDlg= NULL;
ASSERT(m_pWordBase); delete m_pWordBase; m_pWordBase = NULL;
ASSERT(m_pfs ); delete m_pfs; m_pfs = NULL;
}
void CFind::OnWordListSelCancel()
{
char acString1[MAX_QUERY_STRING+1];
char acString2[MAX_QUERY_STRING+1];
m_hWordsFound = GetDlgItem(m_hDlg,IDC_NUM_MATCHING_WORDS);
::LoadString(m_hInst,IDS_NUM_MATCHING_WORDS,acString1,MAX_QUERY_STRING);
wsprintf(acString2,acString1,m_pWordBase->PMaskedTokenList()->RowCount());
::SetWindowText(m_hWordsFound,acString2);
m_serial++; // hilites invalidated
}
UINT CFind::FindCurrentToken(PWCHAR pwcQuery, UINT cwcQuery, UINT iStart, PWCHAR *paStart, PWCHAR *paEnd, PUINT pcPatterns, PUINT pcbPatterns)
{
BOOL fFoundStart = FALSE;
UINT iTokenStart = 0;
UINT cPatterns = 0;
UINT cbPatterns = 0;
PWCHAR pwcStart = pwcQuery + iStart;
CAbortSearch::CheckContinueState();
if (!cwcQuery)
{
*paStart= *paEnd= pwcQuery;
cPatterns= 1; fFoundStart=TRUE;
}
else
{
UINT i;
int nChars = cwcQuery;
PWCHAR lpStr = pwcQuery;
cPatterns = WordBreakW(&lpStr, &nChars, paStart, paEnd, NULL, NULL, CB_QUERY_MAX, REMOVE_SPACE_CHARS | STARTING_IMBEDS);
for (i = 0; i < cPatterns; i++)
{
CAbortSearch::CheckContinueState();
// BugBug! The code below for locating the "current" token doesn't always work correctly.
// It ignores the case where the text cursor lies between two text fragments.
if (!fFoundStart && (paEnd[i] >= pwcStart))
{
fFoundStart = TRUE;
iTokenStart = i;
if (paStart[i] > pwcStart && cPatterns < CB_QUERY_MAX)
{
MoveMemory(paStart + i + 1, paStart + i, (cPatterns - i) * sizeof(PWCHAR));
MoveMemory(paEnd + i + 1, paEnd + i, (cPatterns - i) * sizeof(PWCHAR));
paEnd[i]= paStart[i];
++cPatterns;
continue;
}
}
cbPatterns += paEnd[i] - paStart[i];
}
if (!fFoundStart)
{
iTokenStart = cPatterns++;
ASSERT(iTokenStart < CB_QUERY_MAX);
paStart[iTokenStart]= paEnd[iTokenStart]= iTokenStart? paEnd[iTokenStart-1] : pwcQuery;
}
}
if ( pcPatterns) * pcPatterns= cPatterns;
if (pcbPatterns) *pcbPatterns= cbPatterns;
return iTokenStart;
}
#ifdef _DEBUG
BOOL fDumpHeap= FALSE;
#endif // _DEBUG
BOOL CFind::QueueAbortDialog()
{
BOOL fAlreadySearching= !CAbortSearch::StartAbortTimer(m_hInst, m_hDlg);
if (!fAlreadySearching)
{
EnableWindow(GetDlgItem(m_hDlg, IDC_CLEAR_EDIT ), FALSE);
EnableWindow(GetDlgItem(m_hDlg, IDC_OPTIONS ), FALSE);
EnableWindow(GetDlgItem(m_hDlg, IDC_INDEX ), FALSE);
EnableWindow(GetDlgItem(m_hDlg, IDC_SEARCH_NOW ), FALSE);
EnableWindow(GetDlgItem(m_hDlg, IDC_APPLYFEEDBACK), FALSE);
}
return fAlreadySearching;
}
void CFind::DequeueAbortDialog()
{
CAbortSearch::StopAbortTimer();
EnableWindow(GetDlgItem(m_hDlg, IDC_CLEAR_EDIT ), TRUE);
EnableWindow(GetDlgItem(m_hDlg, IDC_OPTIONS ), TRUE);
EnableWindow(GetDlgItem(m_hDlg, IDC_INDEX ), TRUE);
EnableWindow(GetDlgItem(m_hDlg, IDC_SEARCH_NOW ), !m_bAutoSearch);
EnableWindow(GetDlgItem(m_hDlg, IDC_APPLYFEEDBACK),
m_ptkc->SimilaritySearch() && m_pflArticles->AnyRelevant()
);
}
void CFind::OnEditchangeNarrow()
{
if (m_iDirtyFactor) // this is the implimentation for the paused input
{ // model. Each time a key is pressed the dirtyfactor
KillTimer(m_hDlg,ID_CHECKDIRTY); // is increased and a single shot timer is set up (or reset)
m_iDirtyFactor = 0; // If the timer is not available the delay mechanism will
} // act as if pause was not selected
ASSERT(m_iLookFor != PHRASE || m_ptkc->PhraseSearch());
#ifdef _DEBUG
if (fDumpHeap) DumpResidualAllocations();
#endif // _DEBUG
BOOL fAlreadySearching = QueueAbortDialog();
if (fAlreadySearching)
{
m_fDeferredSearch= TRUE;
return;
}
if (m_fIgnoreSelectionChanges) return;
m_fDoneSearching = FALSE; // mfcc
HCURSOR hSaveCursor = SetCursor(hcurBusy);
ASSERT(m_pWordBase!= NULL);
BOOL fAlreadyPostponed= m_pWordBase->PostponingEvents();
if (!fAlreadyPostponed) m_pWordBase->PostponeEvents();
PWCHAR pwcCurrentQuery, pwcLastQuery= m_pwcLastQuery;
pwcCurrentQuery = (pwcLastQuery == m_awcQueryPair)? m_awcQueryPair + CB_QUERY_MAX + 1
: m_awcQueryPair;
m_pwcLastQuery= pwcCurrentQuery;
int iStart= 0, iEnd= 0;
PWCHAR pbImages = NULL;
PDESCRIPTOR pdImages = NULL;
PWCHAR pwcDisplay = NULL;
CTokenList *ptlCurrentPatterns = NULL;
CIndicatorSet *pisSel = NULL;
CFragInfo *pfiNew = NULL;
UINT uExceptionType= 0;
__try
{
__try
{
GetSel(iStart, iEnd);
UINT cbQuery= ::WGetWindowText(m_hwndEditBox, pwcCurrentQuery, CB_QUERY_MAX + 1); //rmk
UINT iTokenActiveFirst= UINT(-1),
iTokenActiveLast = UINT(-1);
PWCHAR pb= pwcCurrentQuery, //rmk
pbLimit= pb + cbQuery;
UINT cPatterns= 0;
UINT cbPatterns= 0;
PWCHAR paStart[CB_QUERY_MAX]; //rmk
PWCHAR paEnd [CB_QUERY_MAX]; //rmk
UINT iTokenStart = FindCurrentToken(pwcCurrentQuery, cbQuery, iEnd, paStart,
paEnd, &cPatterns, &cbPatterns);
UINT iTokenStartLast= m_iTokenStart;
BOOL fSelectionChanged= iTokenStartLast != iTokenStart;
m_iTokenStart= iTokenStart;
pbImages = (PWCHAR ) VAlloc(FALSE, MaxSortKeyBytes(cbPatterns)); //rmk
pdImages = (PDESCRIPTOR) VAlloc(FALSE, sizeof(DESCRIPTOR) * (cPatterns+1));
PWCHAR pbDest = pbImages; //rmk
PDESCRIPTOR pdDest = pdImages;
PWCHAR pwc;
UINT cwcDisplay = 0;
UINT cFragments= 0;
UINT i, cLexW, cbToken, oldcbToken;
int nChars = cbQuery;
PWCHAR lpStr = pwcCurrentQuery;
if (!cbPatterns) cbPatterns= 1;
pwc= pwcDisplay= PWCHAR(VAlloc(FALSE, cbPatterns * sizeof(WCHAR)));
ValidateHeap();
cLexW= cFragments= cPatterns;
for (i = 0; i < cLexW; i++, pdDest++)
{
CAbortSearch::CheckContinueState();
oldcbToken = cbToken = paEnd[i] - paStart[i];
CopyMemory(pwc, paStart[i], cbToken * sizeof(WCHAR));
pdDest->pwDisplay= pwc;
ValidateHeap();
cbToken = LCSortKeyW(GetUserDefaultLCID(), 0, paStart[i], cbToken, pbDest, MaxSortKeyBytes(cbToken));
ValidateHeap();
pdDest->pbImage= pbDest;
if (i >= m_cfiActive)
{
ASSERT(i == m_cfiActive);
if (i >= m_cfiAllocated)
{
ASSERT(i == m_cfiAllocated);
m_apfi[m_cfiAllocated++]= CFragInfo::NewFragInfo(m_ptkc, m_ptlc,
(RefType)m_iLookFor, m_bPhraseFeedback, m_iWordsThat, pbDest, cbToken, pwc, oldcbToken);
}
else m_apfi[i]->SetImageAndType(pbDest, cbToken, pwc, oldcbToken, (RefType)m_iLookFor, m_bPhraseFeedback);
++m_cfiActive;
}
else
{
if (!cbToken && m_apfi[i]->HasImage() && m_cfiActive == cLexW - 1)
{
UINT iLast= cLexW - 1;
if (iLast < m_cfiAllocated)
{
pfiNew= m_apfi[iLast];
pfiNew->SetImageAndType(pbDest, cbToken, pwc, oldcbToken, (RefType)m_iLookFor, m_bPhraseFeedback);
}
else
pfiNew= CFragInfo::NewFragInfo(m_ptkc, m_ptlc, (RefType)m_iLookFor, m_bPhraseFeedback, m_iWordsThat, pbDest, cbToken, pwc, oldcbToken);
MoveMemory(m_apfi + i + 1, m_apfi + i, (iLast - i) * sizeof(CFragInfo *));
m_apfi[i]= pfiNew;
pfiNew= NULL;
m_cfiActive= cLexW;
if (m_cfiActive > m_cfiAllocated) ++m_cfiAllocated;
}
else
{
if (cbToken && !(m_apfi[i]->HasImage())
&& m_cfiActive == cLexW + 1
)
{
pfiNew= m_apfi[i];
MoveMemory(m_apfi + i, m_apfi + i + 1, (cLexW - i) * sizeof(CFragInfo *));
m_apfi[cLexW]= pfiNew; pfiNew= NULL;
}
m_apfi[i]->SetImage(pbDest, cbToken, pwc, oldcbToken);
}
}
pwc += oldcbToken;
pbDest += cbToken;
}
pdDest->pwDisplay = pwc;
pdDest->pbImage = pbDest;
// ASSERT(fFoundStart); //rmk
// ASSERT(fFoundEnd); // BugBug: Need to add code to the loop above to locate iTokenEnd;
ptlCurrentPatterns= CTokenList::NewTokenList(pbImages, cbPatterns, pdImages, cPatterns, GetUserDefaultLCID(), pwcDisplay, cwcDisplay);
pbImages = NULL;
pdImages = NULL;
pwcDisplay = NULL;
CAbortSearch::CheckContinueState();
// Now we clear out any excess indicator sets left over from the last
// input event.
UINT iFragment;
for (iFragment= cFragments; iFragment < m_cfiActive; iFragment++)
{
CAbortSearch::CheckContinueState();
m_apfi[iFragment]->SetImageAndType(NULL, 0, NULL, 0, NoRefs, 0);
m_apfi[iFragment]->SetSelection(NULL);
}
m_cfiActive= cFragments;
UINT cPatternsOld= m_ptlTermPatterns->RowCount();
// The m_pisWordSet variable is a word-set filter for the current
// token. It is constructed by doing a partial evaluation. That is,
// evaluate everything except the current token and combine their
// result appropriately.
//
// When the cursor moves to a different fragment or when more than
// one fragment changes we must recalculate the filter.
if (m_pisWordSet)
switch (m_iLookFor)
{
case ALL_WORDS:
if (fSelectionChanged || cPatternsOld != cFragments) DiscardPartials();
else
if (CntFragmentsWithValues(iTokenStart) < cFragments - 1) DiscardPartials();
break;
case ANY_WORD:
DiscardPartials();
break;
case PHRASE:
ASSERT(m_ptkc->PhraseSearch());
if (fSelectionChanged || cPatternsOld != cFragments)
if ( iTokenStart == cFragments - 1
&& iTokenStartLast == cFragments - 2
&& cPatternsOld == cFragments - 1
)
if (CntFragmentsWithValues(iTokenStart) < cFragments - 1) DiscardPartials();
else
{
DetachRef(m_pisWordSet);
AddPhraseWord(m_apfi[iTokenStartLast]);
}
else DiscardPartials();
break;
}
if (!m_pisWordSet)
{
switch(m_iLookFor)
{
case ALL_WORDS:
{
ASSERT(!m_pisWordSet );
ChangeRef(m_pisArticleSet, CIndicatorSet::NewIndicatorSet(m_ptlc->ActiveTitles()));
CAbortSearch::CheckContinueState();
for (iFragment= cFragments; iFragment--; )
if (iFragment != iTokenStart)
{
CAbortSearch::CheckContinueState();
CIndicatorSet *pis= m_apfi[iFragment]->GetArticleSet();
if (pis)
{
m_pisArticleSet->ANDWith(pis);
delete pis;
}
}
CAbortSearch::CheckContinueState();
if (cFragments == 1 || m_pisArticleSet->SelectionCount() == m_ptlc->ActiveTitles()->SelectionCount())
AttachRef(m_pisWordSet, CIndicatorSet::NewIndicatorSet(m_ptkc->ActiveTokens()));
else AttachRef(m_pisWordSet, VocabularyFor(m_pisArticleSet));
}
break;
case PHRASE:
{
ASSERT(m_ptkc->PhraseSearch());
ConstructPhraseFilter(iTokenStart);
ConstructPhraseVocabulary();
}
break;
case ANY_WORD:
ASSERT(!m_pisWordSet );
CAbortSearch::CheckContinueState();
ChangeRef(m_pisArticleSet, CIndicatorSet::NewIndicatorSet(m_ptlc->RowCount(), FALSE));
for (iFragment= cFragments; iFragment--; )
if (iFragment != iTokenStart)
{
CAbortSearch::CheckContinueState();
CIndicatorSet *pis= m_apfi[iFragment]->GetArticleSet();
CAbortSearch::CheckContinueState();
if (pis)
{
m_pisArticleSet->ORWith(pis);
delete pis;
}
}
CAbortSearch::CheckContinueState();
AttachRef(m_pisWordSet, CIndicatorSet::NewIndicatorSet(m_ptkc->ActiveTokens()));
break;
}
CAbortSearch::CheckContinueState();
m_pWordBase->SetSearchFilter(m_pisWordSet);
}
m_pWordBase->PMaskedTokenList()->SetElipsis(iTokenStart > 0, iTokenStart < cFragments - 1);
CAbortSearch::CheckContinueState();
m_pWordBase->SetSubstringFilter(m_apfi[iTokenStart]->GetWordSet());
if (!(m_apfi[iTokenStart]->HasValue()) || fSelectionChanged)
{
CAbortSearch::CheckContinueState();
pisSel= m_apfi[iTokenStart]->GetSelection();
CAbortSearch::CheckContinueState();
if (!pisSel) pisSel= (m_iLookFor != ANY_WORD)? CIndicatorSet::NewIndicatorSet(m_ptkc->ActiveTokens())
: CIndicatorSet::NewIndicatorSet(m_ptkc->RowCount ());
CAbortSearch::CheckContinueState();
m_pWordBase->PMaskedTokenList()->SetSelection(pisSel); pisSel= NULL;
}
ComputeTopicList();
ChangeRef(m_ptlTermPatterns, ptlCurrentPatterns); ptlCurrentPatterns= NULL;
}
__finally
{
if (pbImages ) { VFree(pbImages ); pbImages = NULL; }
if (pdImages ) { VFree(pdImages ); pdImages = NULL; }
if (pwcDisplay) { VFree(pwcDisplay); pwcDisplay = NULL; }
if (!fAlreadySearching) {
DequeueAbortDialog();
m_fDoneSearching = TRUE; // mfcc
}
if (ptlCurrentPatterns) { delete ptlCurrentPatterns; ptlCurrentPatterns = NULL; }
if (pisSel ) { delete pisSel; pisSel = NULL; }
if (pfiNew ) { delete pfiNew; pfiNew = NULL; }
}
}
__except(FilterFTExceptions(uExceptionType= _exception_code()))
{
OnClearEdit(TRUE);
// BugBug! What special recovery actions should we take for each
// specific exception type?
#if 0
switch (uExceptionType)
{
case STATUS_NO_MEMORY:
case STATUS_NO_DISK_SPACE:
case STATUS_DISK_READ_ERROR:
case STATUS_DISK_WRITE_ERROR:
case STATUS_ABORT_SEARCH:
}
#endif // 0
}
if (!fAlreadyPostponed)
{
m_fIgnoreSelectionChanges= TRUE;
m_pWordBase->ReleaseEvents();
m_fIgnoreSelectionChanges= FALSE;
}
SetCursor(hSaveCursor);
if (m_fDeferredSearch)
{
m_fDeferredSearch= FALSE;
m_iDirtyFactor++;
SetTimer(m_hDlg, ID_CHECKDIRTY, 0, NULL);
}
if (m_fExitPending) OnDisplay(); // mfcc
}
void CFind::DiscardPartials()
{
CAbortSearch::CheckContinueState();
if (m_pisWordSet ) DetachRef(m_pisWordSet );
if (m_pisArticleSet) DetachRef(m_pisArticleSet);
for (UINT i= m_cts; i--; )
if (m_ppisPhraseFilter[i]) DetachRef(m_ppisPhraseFilter[i]);
}
UINT CFind::CntFragmentsWithValues(UINT iExcludedToken)
{
UINT cDefined= 0;
for (UINT iFragment= m_cfiActive; iFragment--; )
if (iFragment != iExcludedToken && m_apfi[iFragment]->HasValue()) ++cDefined;
return cDefined;
}
void CFind::AddPhraseWord(CFragInfo *pfi, BOOL fAtTheEnd)
{
ASSERT(m_ptkc->PhraseSearch());
int cbitsShift= fAtTheEnd? 1 : -1;
pfi->MoveToFirstLocationSet();
CIndicatorSet *pisFrag = NULL;
CIndicatorSet *pis = NULL;
CIndicatorSet *pisTokens = NULL;
CIndicatorSet *pisFilter = NULL;
__try
{
for (UINT iTextSet= 0; iTextSet < m_cts; iTextSet++)
{
CAbortSearch::CheckContinueState();
if (!m_ptkc->IsActive(iTextSet)) continue;
pis= pfi->GetLocationSet(iTextSet);
if (!pis) continue;
AttachRef(pisFrag, pis); pis= NULL;
if (!m_ppisPhraseFilter[iTextSet]) AttachRef(m_ppisPhraseFilter[iTextSet], pisFrag);
else m_ppisPhraseFilter[iTextSet]->ANDWith(pisFrag);
DetachRef(pisFrag);
CTextSet *pts= m_papts[iTextSet];
AttachRef(pisFilter, m_ppisPhraseFilter[iTextSet]);
CAbortSearch::CheckContinueState();
if (!fAtTheEnd) pts->ExcludeStartBoundaries(pisFilter);
CAbortSearch::CheckContinueState();
pisFilter->ShiftIndicators(cbitsShift);
CAbortSearch::CheckContinueState();
if (fAtTheEnd) pts->ExcludeStartBoundaries(pisFilter);
AttachRef(pisTokens, CIndicatorSet::NewIndicatorSet(pisFilter));
CAbortSearch::CheckContinueState();
pisTokens->GTRWith(pts->SymbolLocations());
CAbortSearch::CheckContinueState();
if (!fAtTheEnd) pts->ExcludeStartBoundaries(pisTokens);
CAbortSearch::CheckContinueState();
pisFilter->ORWith(pisTokens->ShiftIndicators(cbitsShift));
CAbortSearch::CheckContinueState();
if (fAtTheEnd) pts->ExcludeStartBoundaries(pisFilter);
DetachRef(pisTokens);
DetachRef(pisFilter);
}
}
__finally
{
if (_abnormal_termination())
{
if (pisFrag ) DetachRef(pisFrag );
if (pisTokens) DetachRef(pisTokens);
if (pisFilter) DetachRef(pisFilter);
if (pis) delete pis;
}
}
}
void CFind::ConstructPhraseFilter(UINT iTargetSlot)
{
ASSERT(m_ptkc->PhraseSearch());
if (m_cfiActive == 1) return;
UINT iFragment;
CAbortSearch::CheckContinueState();
for (iFragment= m_cfiActive; iFragment--; ) m_apfi[iFragment]->MoveToFirstLocationSet();
CIndicatorSet *pisSymbols = NULL;
CIndicatorSet *pisTokens = NULL;
CIndicatorSet *pisFilter = NULL;
CIndicatorSet *pisLocations = NULL;
__try
{
for (UINT iTextSet= 0; iTextSet < m_cts; iTextSet++)
{
CAbortSearch::CheckContinueState();
if (m_ppisPhraseFilter[iTextSet]) DetachRef(m_ppisPhraseFilter[iTextSet]);
if (!m_ptkc->IsActive(iTextSet)) continue;
CTextSet *pts= m_papts[iTextSet];
AttachRef(pisSymbols, pts->SymbolLocations() );
CAbortSearch::CheckContinueState();
AttachRef(pisTokens, CIndicatorSet::NewIndicatorSet(pts->TokenCount(), FALSE));
CAbortSearch::CheckContinueState();
AttachRef(pisFilter, CIndicatorSet::NewIndicatorSet(pts->TokenCount(), TRUE ));
if (iTargetSlot > 0)
{
for (iFragment= 0; iFragment < iTargetSlot; iFragment++)
{
CAbortSearch::CheckContinueState();
pisLocations= m_apfi[iFragment]->GetLocationSet(iTextSet);
CAbortSearch::CheckContinueState();
if (pisLocations)
{
pisFilter->ANDWith(pisLocations);
delete pisLocations; pisLocations= NULL;
}
else
{
pisFilter->ClearAll();
break;
}
CAbortSearch::CheckContinueState();
pisFilter->ShiftIndicators(1);
CAbortSearch::CheckContinueState();
pts->ExcludeStartBoundaries(pisFilter);
CAbortSearch::CheckContinueState();
pisTokens->CopyFrom(pisFilter);
CAbortSearch::CheckContinueState();
pisTokens->GTRWith(pisSymbols);
CAbortSearch::CheckContinueState();
pisTokens->ShiftIndicators(1);
CAbortSearch::CheckContinueState();
pisFilter->ORWith(pisTokens);
CAbortSearch::CheckContinueState();
pts->ExcludeStartBoundaries(pisFilter);
}
AttachRef(m_ppisPhraseFilter[iTextSet], pisFilter);
CAbortSearch::CheckContinueState();
if (iTargetSlot < m_cfiActive - 1) ChangeRef(pisFilter, CIndicatorSet::NewIndicatorSet(pts->TokenCount(), TRUE));
}
if (iTargetSlot < m_cfiActive - 1)
{
for (iFragment= m_cfiActive; --iFragment > iTargetSlot; )
{
CAbortSearch::CheckContinueState();
pisLocations= m_apfi[iFragment]->GetLocationSet(iTextSet);
CAbortSearch::CheckContinueState();
if (pisLocations)
{
pisFilter->ANDWith(pisLocations);
delete pisLocations; pisLocations= NULL;
}
else
{
pisFilter->ClearAll();
break;
}
CAbortSearch::CheckContinueState();
pts->ExcludeStartBoundaries(pisFilter);
CAbortSearch::CheckContinueState();
pisFilter->ShiftIndicators(-1);
CAbortSearch::CheckContinueState();
pisTokens->CopyFrom(pisFilter);
CAbortSearch::CheckContinueState();
pisTokens->GTRWith(pisSymbols);
CAbortSearch::CheckContinueState();
pts->ExcludeStartBoundaries(pisTokens);
CAbortSearch::CheckContinueState();
pisTokens->ShiftIndicators(-1);
CAbortSearch::CheckContinueState();
pisFilter->ORWith(pisTokens);
}
CAbortSearch::CheckContinueState();
if (m_ppisPhraseFilter[iTextSet]) m_ppisPhraseFilter[iTextSet]->ANDWith(pisFilter);
else AttachRef(m_ppisPhraseFilter[iTextSet], pisFilter);
}
DetachRef(pisFilter );
DetachRef(pisTokens );
DetachRef(pisSymbols);
}
}
__finally
{
if (_abnormal_termination())
{
if (pisLocations) { delete pisLocations; pisLocations= NULL; }
if (pisFilter ) DetachRef(pisFilter );
if (pisTokens ) DetachRef(pisTokens );
if (pisSymbols ) DetachRef(pisSymbols );
}
}
}
void CFind::ConstructPhraseVocabulary()
{
UINT iTextSet;
ASSERT(m_ptkc->PhraseSearch());
CIndicatorSet *pisTokens = NULL;
CIndicatorSet *pisPartitions = NULL;
PUINT paiPartitions = NULL;
__try
{
for (iTextSet= m_cts; iTextSet--; )
{
CAbortSearch::CheckContinueState();
if (!m_ptkc->IsActive (iTextSet)) continue;
if (!m_ppisPhraseFilter[iTextSet]) continue;
AttachRef(pisTokens, m_ppisPhraseFilter[iTextSet]);
CAbortSearch::CheckContinueState();
if (!m_pisWordSet) AttachRef(m_pisWordSet, CIndicatorSet::NewIndicatorSet(m_ptkc->RowCount()));
CTextSet *pts = m_papts[iTextSet];
PUINT piMap = m_ptkc->UniversalTokenMap(iTextSet);
if (m_ptkc->PhraseFeedback() && m_bPhraseFeedback)
{
CAbortSearch::CheckContinueState();
pts->IndicateVocabularyRefs(m_pisWordSet, pisTokens, piMap);
}
else
{
CAbortSearch::CheckContinueState();
AttachRef(pisPartitions, pts->PartitionsContaining(pisTokens));
UINT cPartitions= pisPartitions->SelectionCount();
CAbortSearch::CheckContinueState();
paiPartitions= PUINT(VAlloc(FALSE, cPartitions * sizeof(UINT)));
CAbortSearch::CheckContinueState();
pisPartitions->MarkedItems(0, PINT(paiPartitions), cPartitions);
for (PUINT pi= paiPartitions; cPartitions--; )
{
CAbortSearch::CheckContinueState();
pts->IndicateVocabularyRefs(m_pisWordSet, *pi++, piMap);
}
VFree(paiPartitions); paiPartitions= NULL;
DetachRef(pisPartitions);
}
m_pisWordSet->InvalidateCache();
DetachRef(pisTokens);
}
}
__finally
{
if (pisTokens ) DetachRef(pisTokens );
if (pisPartitions) DetachRef(pisPartitions);
if (paiPartitions) VFree(paiPartitions);
}
CAbortSearch::CheckContinueState();
if (!m_pisWordSet) AttachRef(m_pisWordSet, CIndicatorSet::NewIndicatorSet(m_ptkc->ActiveTokens()));
}
void CFind::OnWordListSelChange()
{
if (m_fIgnoreSelectionChanges) return;
m_fDoneSearching = FALSE; // mfcc
BOOL fAlreadyPostponed= m_pWordBase->PostponingEvents();
BOOL fAlreadySearching= QueueAbortDialog();
if (!fAlreadyPostponed) m_pWordBase->PostponeEvents();
DWORD uExceptionType = 0;
__try
{
__try
{
m_apfi[m_iTokenStart]->SetSelection(m_pWordBase->PMaskedTokenList()->GetIndicators());
ComputeTopicList();
}
__finally
{
if (!fAlreadySearching) {
DequeueAbortDialog();
m_fDoneSearching = TRUE; // mfcc
}
if (!fAlreadyPostponed) m_pWordBase->ReleaseEvents();
}
}
__except(FilterFTExceptions(uExceptionType= _exception_code()))
{
OnClearEdit(TRUE);
// BugBug! What special recovery actions should we take for each
// specific exception type?
#if 0
switch (uExceptionType)
{
case STATUS_NO_MEMORY:
case STATUS_NO_DISK_SPACE:
case STATUS_DISK_READ_ERROR:
case STATUS_DISK_WRITE_ERROR:
case STATUS_ABORT_SEARCH:
}
#endif // 0
}
m_serial++;
if (m_fExitPending) OnDisplay(); // mfcc
}
void CFind::ComputeTopicList()
{
// Now we'll do the complete evaluation. We exploit the fact that we
// already have most of the evaluation done.
if (m_iLookFor == PHRASE)
{
if (m_pisArticleSet ) DetachRef(m_pisArticleSet );
if (m_pisArticleSubset) DetachRef(m_pisArticleSubset);
CAbortSearch::CheckContinueState();
AttachRef(m_pisArticleSubset, CIndicatorSet::NewIndicatorSet(m_ptlc->RowCount()));
}
else
{
CAbortSearch::CheckContinueState();
if (!m_pisArticleSet)
if (m_iLookFor == ANY_WORD)
AttachRef(m_pisArticleSet, CIndicatorSet::NewIndicatorSet(m_ptlc->RowCount ()));
else AttachRef(m_pisArticleSet, CIndicatorSet::NewIndicatorSet(m_ptlc->ActiveTitles()));
CAbortSearch::CheckContinueState();
ChangeRef(m_pisArticleSubset, CIndicatorSet::NewIndicatorSet(m_pisArticleSet));
}
CIndicatorSet *pis = NULL;
CIndicatorSet *pisTokens = NULL;
CIndicatorSet *pisPartitions = NULL;
PUINT paiPartitions = NULL;
ValidateHeap();
__try
{
switch (m_iLookFor)
{
case ALL_WORDS:
{
CAbortSearch::CheckContinueState();
pis= m_apfi[m_iTokenStart]->GetArticleSet();
CAbortSearch::CheckContinueState();
if (pis)
{
m_pisArticleSubset->ANDWith(pis);
delete pis; pis= NULL;
}
}
break;
case PHRASE:
{
ASSERT(m_ptkc->PhraseSearch());
CFragInfo *pfi= m_apfi[m_iTokenStart];
BOOL fEmptyImage= !(pfi->HasImage());
CAbortSearch::CheckContinueState();
if (m_cfiActive == 1 && fEmptyImage && !pfi->GetCSSelection())
{
CAbortSearch::CheckContinueState();
m_pisArticleSubset->ORWith(m_ptlc->ActiveTitles());
break;
}
ValidateHeap();
pfi->MoveToFirstLocationSet();
ValidateHeap();
for (UINT iTextSet= 0; iTextSet < m_cts; iTextSet++)
{
CAbortSearch::CheckContinueState();
if (!m_ptkc->IsActive(iTextSet)) continue;
ValidateHeap();
CAbortSearch::CheckContinueState();
if (fEmptyImage && !pfi->GetCSSelection())
if (m_ppisPhraseFilter[iTextSet]) AttachRef(pisTokens, m_ppisPhraseFilter[iTextSet]);
else continue;
else
{
ValidateHeap();
pis= pfi->GetLocationSet(iTextSet);
ValidateHeap();
if (pis)
{
AttachRef(pisTokens, pis); pis= NULL;
ValidateHeap();
CAbortSearch::CheckContinueState();
if (m_ppisPhraseFilter[iTextSet]) pisTokens->ANDWith(m_ppisPhraseFilter[iTextSet]);
ValidateHeap();
}
else continue;
}
CTextSet *pts= m_papts[iTextSet];
ValidateHeap();
CAbortSearch::CheckContinueState();
AttachRef(pisPartitions, pts->PartitionsContaining(pisTokens));
ValidateHeap();
DetachRef(pisTokens);
ValidateHeap();
UINT cPartitions= pisPartitions->SelectionCount();
if (!cPartitions) { DetachRef(pisPartitions); continue; }
ValidateHeap();
const UINT *piMap= m_ptlc->UniversalTitleMap(iTextSet);
CAbortSearch::CheckContinueState();
paiPartitions= PUINT(VAlloc(FALSE, cPartitions * sizeof(UINT)));
CAbortSearch::CheckContinueState();
pisPartitions->MarkedItems(0, PINT(paiPartitions), cPartitions);
ValidateHeap();
DetachRef(pisPartitions);
CAbortSearch::CheckContinueState();
for (PUINT pi= paiPartitions; cPartitions--; ) m_pisArticleSubset->RawSetBit(piMap[*pi++]);
m_pisArticleSubset->InvalidateCache();
VFree(paiPartitions); paiPartitions= NULL;
}
}
break;
case ANY_WORD:
{
CAbortSearch::CheckContinueState();
pis= m_apfi[m_iTokenStart]->GetArticleSet();
if (pis)
{
CAbortSearch::CheckContinueState();
m_pisArticleSubset->ORWith(pis);
delete pis; pis= NULL;
}
// else m_pisArticleSubset->ORWith(m_ptlc->ActiveTitles());
}
break;
}
}
__finally
{
if (pis) { delete pis; pis= NULL; }
if (pisTokens ) DetachRef(pisTokens );
if (pisPartitions) DetachRef(pisPartitions);
if (paiPartitions) VFree(paiPartitions);
}
ValidateHeap();
m_pfs->SetSearchFilter(m_pisArticleSubset);
if (m_pisArticleSubset && m_pisArticleSubset->AnyOnes()) m_pfs->SetSelectedRow(0);
char acFormat[MAX_CB_FORMAT_STRING+1];
char acImage [MAX_CB_FORMAT_STRING+1];
::LoadString(m_hInst,IDS_NUM_TOPICS_FOUND, acFormat, MAX_CB_FORMAT_STRING);
::wsprintf(acImage, acFormat, m_pisArticleSubset->SelectionCount());
::SetWindowText(m_hTopicsFound, acImage);
}
void CFind::OnDisplay() // The display button has been pressed...
{
// We don't need __try/__finally brackets in this routine
// because it doesn't contain any allocation or AttachRef
// instances in the retail code.
if (!m_fDoneSearching) {
m_fExitPending = TRUE; // mfcc
return; // come back and try again later
}
UINT iFile= m_pfs->InxSelectedFile();
if (iFile == UINT(-1)) return;
m_fExitPending = FALSE; // mfcc
CTextSet *pts = NULL;
UINT iTextSet = UINT(-1);
UINT iPartition= m_ptlc->PartitionFor(iFile, &iTextSet);
pts= m_papts[iTextSet];
#ifdef _DEBUG
#ifdef SHOWMSG
UINT uJumpHelp = IDOK;
PWCHAR wTitle = NULL;
LPSTR szTitle = NULL;
PWCHAR wImage = NULL;
LPSTR szImage = NULL;
CDisplayHelp *pcdh= NULL;
if (m_ptkc->PhraseFeedback())
__try
{
int cwText = m_pflArticles->TokenList()->GetWTokenI(iFile, NULL, 0); //rmk
wTitle = (PWCHAR) VAlloc(FALSE, (cwText+1) * sizeof(WCHAR)); //rmk
szTitle = (LPSTR) VAlloc(FALSE, cwText+1); //rmk
cwText = m_pflArticles->TokenList()->GetWTokenI(iFile, wTitle, cwText); //rmk
CP cp = GetCPFromCharset(pts->GetDefaultCharSet());
int cbText = WideCharToMultiByte(cp, 0, wTitle, cwText, szTitle, cwText, NULL, NULL); //rmk
szTitle[cbText] = 0; //rmk
UINT cbImage= m_ptkc->TopicDisplayImageSize(iTextSet, iPartition);
// Do not move this line. I need to pass iPartition to this construnctor. -- Krishna
pcdh= New CDisplayHelp(m_hInst,IDD_DISPLAY_HELP,m_hDlg, iPartition, m_pflArticles);
pcdh->SetTitle(szTitle); //rmk
wImage= (PWCHAR) VAlloc(FALSE, (cbImage+1) * sizeof(WCHAR)); //rmk
szImage= (LPSTR) VAlloc(FALSE, cbImage+1); //rmk
ASSERT(szImage); //rmk
cwText = m_ptkc->CopyTopicDisplayImage(UINT iTextSet, iPartition, wImage, cbImage); //rmk
cbText = WideCharToMultiByte(cp, 0, wImage, cwText, szImage, cbImage, NULL, NULL); //rmk
szImage[cbText] = 0; //rmk
pcdh->SetText(szImage); //rmk
uJumpHelp= pcdh->DoModal();
EnableWindow(GetDlgItem(m_hDlg, IDC_APPLYFEEDBACK), m_ptkc->SimilaritySearch() && m_pflArticles->AnyRelevant());
}
__finally
{
if (szTitle) { VFree(szTitle); szTitle = NULL; }
if (wTitle ) { VFree(wTitle ); wTitle = NULL; }
if (szImage) { VFree(szImage); szImage = NULL; }
if (wImage ) { VFree(wImage ); wImage = NULL; }
if (pcdh) { delete pcdh; pcdh= NULL; }
}
if (uJumpHelp == IDOK)
{
#endif // SHOWMSG
#endif // _DEBUG
HANDLE hTopic = pts->TopicHandle(iPartition);
HWND hwndParent = GetParent(m_hDlg);
if (hwndParent)
{
m_fFromSimilarTopics= FALSE;
UINT uOpt= pts->IndexOptions();
if (uOpt & USE_QWORD_JUMP)
{
QWordAddress qwa;
qwa.iSerial = pts->TopicSerial(iPartition);
qwa.hTopic = hTopic;
SendMessage(hwndParent, MSG_FTS_JUMP_QWORD , WPARAM(iTextSet), LPARAM(&qwa));
}
else
{
UINT uiMsg= (pts->IndexOptions() & USE_VA_ADDR)? MSG_FTS_JUMP_VA
: MSG_FTS_JUMP_HASH;
if (hwndParent)
SendMessage(hwndParent, uiMsg, WPARAM(iTextSet), LPARAM(hTopic));
}
OnUpdateComboList(); // seems reason enough to store search string
}
#ifdef _DEBUG
#ifdef SHOWMSG
}
#endif // SHOWMSG
#endif // _DEBUG
}
void CFind::SetFocusToEdit()
{
HWND hEdit = GetDlgItem(m_hDlg,IDC_NARROW);
SetFocus(hEdit);
}
void CFind::OnUpdateComboList()
{
BYTE abbQuery[CB_QUERY_MAX + 1];
HWND hEdit = GetDlgItem(m_hDlg,IDC_NARROW);
// Add the text to the combo box
int cwText = ::GetWindowText(m_hwndEditBox, (LPSTR)abbQuery, CB_QUERY_MAX + 1);
if (strlen((LPSTR) abbQuery)) // don't insert blank lines!
{
LRESULT lrFind;
if ((lrFind = ::SendMessage(hEdit,CB_FINDSTRING,(WPARAM) -1,(LPARAM) abbQuery)) != CB_ERR)
{
::SendMessage(hEdit,CB_DELETESTRING,lrFind,(LPARAM) 0);
BOOL bAutoSearchOld = m_bAutoSearch;
m_bAutoSearch = FALSE; // just for now to quell effects of changing the edit box
::SendMessage(m_hwndEditBox, WM_SETTEXT, 0, (LPARAM) abbQuery);
m_bAutoSearch = bAutoSearchOld; // restore proper value (mfcc)
}
::SendMessage(hEdit,CB_INSERTSTRING,0,(LPARAM) abbQuery);
}
}
void CFind::OnClearEdit(BOOL fRecovery)
{
BYTE abbQuery[CB_QUERY_MAX + 1];
HWND hEdit = GetDlgItem(m_hDlg,IDC_NARROW);
// Add the text to the combo box
int cwText = ::GetWindowText(m_hwndEditBox, (LPSTR)abbQuery, CB_QUERY_MAX + 1);
if (KEYCLEAR && !fRecovery)
{
PSZ psz = (PSZ) &abbQuery;
while (*psz) *psz++ = *psz + 1;
switch (m_uiClearStatus)
{
case 0 : // You have only Just Begun
m_uiClearStatus = ((m_iWordsThat == BEGIN_WITH) && (m_iLookFor == ALL_WORDS) && (strcmp((PSZ) &abbQuery,"Xip!lopxt!xip!cvjmu!uijt!uppm@") == 0)) ? 1 : 0;
break;
case 1 : // Okay are you serious about this?
m_uiClearStatus = 0;
if ((m_iWordsThat == CONTAIN) && (m_iLookFor == ANY_WORD) && (strcmp((PSZ) &abbQuery,"Uif!Tibepx!lopxt\"") == 0))
{
CGiveCredit cgc(m_hInst,IDD_BUILTBY,m_hDlg);
cgc.DoModal();
}
break;
}
}
OnUpdateComboList();
DiscardPartials();
m_apfi[0]->SetSelection(NULL);
SetWindowText(hEdit,""); // Clear the edit box for the user to be nice...
}
void CFind::OnOptions()
{
// Bug Bug this code will allow both options boxes new one by default
// or the old one if the shift key is depressed. This is for UI experimentation
// only and should be remove before final ship...
// BUG BUG BUGBUG BugBug
UINT fdwSearchOptions= m_ptkc->SearchOptions();
CFindOptions *pfo= NULL;
__try
{
pfo= CFindOptions::NewFindOptions(m_hInst,IDD_FIND_OPTIONS2,m_hDlg, m_cts, m_ptkc, m_ptlc);
BOOL bEditChange = FALSE;
pfo->m_rbgWordsThat = m_iWordsThat; // Set up the radio button groups
pfo->m_rbgCriteria = m_iLookFor; // before starting the dialog
pfo->m_bDelay = (GetTimeout() != 0) ? TRUE : FALSE; // Initialize the delay check box
pfo->m_bAutoSearch = m_bAutoSearch; // Initialize the auto search check box
pfo->m_cbPhraseFeedback = m_bPhraseFeedback;
pfo->m_ptWindowPosition.x = m_OptionDlgPos.x; // Read from registry
pfo->m_ptWindowPosition.y = m_OptionDlgPos.y; // Read from registry
if (pfo->DoModal() == IDOK) // Display the dialog and check for OK button
{
UINT fdwNewOptions= m_ptkc->SearchOptions();
if (fdwNewOptions != fdwSearchOptions)
{
UINT fdwDiff= fdwNewOptions ^ fdwSearchOptions;
if (fdwDiff & VECTOR_SEARCH)
{
m_pfs->EnableCheckboxes(fdwNewOptions & VECTOR_SEARCH);
if (!(fdwNewOptions & VECTOR_SEARCH))
{
m_pflArticles->ClearRelevancy();
EnableWindow(GetDlgItem(m_hDlg, IDC_APPLYFEEDBACK), FALSE);
}
}
}
if (m_iWordsThat != pfo->m_rbgWordsThat) // If the radio button has changed
{
m_iWordsThat = pfo->m_rbgWordsThat; // Get the index and notify the
for (UINT i=0; i < m_cfiAllocated; i++) m_apfi[i]->SetMatchCriteria(m_iWordsThat);
DiscardPartials();
bEditChange = TRUE; // edit box to update the words windows
}
if ((m_iLookFor != pfo->m_rbgCriteria) || // Check for change in radio button group state
(m_bPhraseFeedback != pfo->m_cbPhraseFeedback)) { // .. and the phrase feedback button
m_bPhraseFeedback = pfo->m_cbPhraseFeedback;
UINT iLookFor = pfo->m_rbgCriteria;
for (UINT i=0; i < m_cfiActive; i++)
m_apfi[i]->SetReferenceType((RefType)iLookFor, m_bPhraseFeedback); // mfcc
m_iLookFor = iLookFor;
DiscardPartials();
bEditChange = TRUE;
}
if (pfo->m_TSSChanged)
{
for (UINT i=0; i < m_cfiActive; i++) m_apfi[i]->InvalidateMatches();
DiscardPartials();
bEditChange= TRUE;
}
if (m_bAutoSearch != pfo->m_bAutoSearch) // Check for changed state in group
{
m_bAutoSearch = pfo->m_bAutoSearch;
EnableWindow(GetDlgItem(m_hDlg,IDC_SEARCH_NOW),!m_bAutoSearch); // Enable or disable the button
}
char acString1[MAX_QUERY_STRING+1];
char acString2[MAX_QUERY_STRING+1];
::LoadString(m_hInst,IDS_OPT_HEAD,acString1,MAX_QUERY_STRING);
strcpy(acString2,acString1);
::LoadString(m_hInst,IDS_TOPICS_ANY + m_iLookFor,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
::LoadString(m_hInst,IDS_WORD_BEGIN + m_iWordsThat,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
::LoadString(m_hInst,IDS_FIND_NOW + (m_bAutoSearch ? 1:0),acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
if (m_bAutoSearch && pfo->m_bDelay)
{
::LoadString(m_hInst,IDS_PAUSE,acString1,MAX_QUERY_STRING);
strcat(acString2,acString1);
}
::SetWindowText(GetDlgItem(m_hDlg,IDC_OPTIONS_STRING),acString2);
if (bEditChange && m_bAutoSearch) OnEditchangeNarrow(); // Update the interface if necessary
SetTimeout(pfo->m_bDelay ? 400 : 0); // set up timeout
}
m_OptionDlgPos.x = pfo->m_ptWindowPosition.x; // Save the window Position
m_OptionDlgPos.y = pfo->m_ptWindowPosition.y; // Save the window Position
m_iWordsThatLast= m_iWordsThat;
}
__finally
{
delete pfo;
}
}
BOOL CFind::GetSel(int& iStart, int& iEnd, BOOL bNoCheck)
{
BOOL fResult= FALSE;
if ((GetFocus() == m_hwndEditBox) || bNoCheck)
{
iStart= m_iStart;
iEnd = m_iEnd;
SendMessage(m_hwndEditBox,EM_GETSEL,(WPARAM) &m_iStart,(LPARAM)&m_iEnd);
fResult= (iStart != m_iStart || iEnd != m_iEnd);
}
iStart = m_iStart; // save selection from the last time it lost
iEnd = m_iEnd; // the focus.
return fResult;
}
void CFind::OnLButtonUp()
{
int is, ie;
if (!GetSel(is, ie)) return;
UINT uiSave = GetTimeout();
SetTimeout(250); // For wm_button ups go faster
DirtyEditBox();
SetTimeout(uiSave);
}
void CFind::OnKeyUp(WPARAM nVirtKey,LPARAM lKeyData)
{
switch (nVirtKey)
{
case VK_UP :
case VK_DOWN :
case VK_LEFT :
case VK_RIGHT :
case VK_HOME :
case VK_END :
DirtyEditBox(); // Make sure that cursor movement is noted
break;
case VK_RETURN :
if (m_bAutoSearch) OnEditchangeNarrow(); // If they hit return do it without delay!
break;
}
}
void CFind::DirtyEditBox()
{
if (m_iDirtyFactor) // Kill the old time if it exists to restart count down
KillTimer(m_hDlg,ID_CHECKDIRTY);
if (m_bAutoSearch)
{
if (!GetTimeout())
OnEditchangeNarrow();
else if (!SetTimer(m_hDlg,ID_CHECKDIRTY,GetTimeout(),NULL))
OnEditchangeNarrow(); // Could not get timer so update now!
else
m_iDirtyFactor++;
}
}
void CFind::OnApplyfeedback()
{
ASSERT(m_ptkc->SimilaritySearch());
HCURSOR hOldCur = NULL;
PWCHAR pwText = NULL;
SimStruct *pRank = NULL;
CQuery *pQuery = NULL;
BOOL fNewDialog = FALSE;
BOOL fAlreadySearching= QueueAbortDialog();
if (fAlreadySearching) return;
m_fDoneSearching = FALSE; // mfc
__try
{
__try
{
UINT cRankedHits = 0;
UINT cwRelArtSize = 0; // size of the combined set of articles marked relevant
UINT cRelevantArticles= 0;
UINT iTextSet, iPartition; // used for file to partition conversion
UINT i, j, cwCopied; // trivial vbles used to acquire combined relevance text
hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Obtain the size of the combined query (combination of all the relevant
// articles). RetrieveWithFeedback is capable of handling both relevant and
// non-relevant feedback (positive and negative), but WinHelp FTS is only
// using the positive feedback.
for (i = 0, j = m_ptlc->RowCount(); i < j; i++)
{
// Find the iFile (= m_pflArticles->MapToActualRow(i)) from the row position
// and see if the article iFile has been marked relevant
if (m_pflArticles->IsRelevant(i))
{
iPartition = m_ptlc->PartitionFor(i, &iTextSet);
cwRelArtSize += 1 + m_ptkc->TopicDisplayImageSize(iTextSet, iPartition);
cRelevantArticles++;
}
}
if (cwRelArtSize == cRelevantArticles)
__leave; // The similarity code will die badly if we have no text!
CAbortSearch::CheckContinueState();
// Allocate memory for the combined article set
pwText = (PWCHAR) VAlloc(FALSE, sizeof(WCHAR)*cwRelArtSize);
// Now copy the text into the buffers
for (i = 0, j = m_ptlc->RowCount(), cwCopied = 0; i < j; i++)
{
// Find the iFile (= m_pflArticles->MapToActualRow(i)) from the row position
// and see if the article iFile has been marked relevant
if (m_pflArticles->IsRelevant(i))
{
iPartition = m_ptlc->PartitionFor(i, &iTextSet);
// Third param to CopyFileImage is the # of chars to copy...
CAbortSearch::CheckContinueState();
cwCopied += m_ptkc->CopyTopicDisplayImage(iTextSet, iPartition, (PWCHAR)&pwText[cwCopied],
m_ptkc->TopicDisplayImageSize(iTextSet, iPartition)
);
pwText[cwCopied++] = UNICODE_SPACE_CHAR;
ASSERT(cwCopied <= cwRelArtSize);
}
}
int cActive = 0;
for (i = 0; i < m_cts; i++)
if (m_ptkc->IsActive(i)) cActive++;
// We want all the collections to retrieve a maximum of m_cMaxToFind documents.
// However, we want each collection to retrieve at least (m_)cMinPerColl (currently 50) documents.
int cMinPerColl = min(50, m_cMaxToFind/cActive);
CAbortSearch::CheckContinueState();
pRank = (SimStruct *) VAlloc(FALSE, cActive * cMinPerColl * sizeof(SimStruct));
for (i = 0; i < m_cts; i++)
{
// Ignore collections that are currently not active
if (!m_ptkc->IsActive(i)) continue;
CAbortSearch::CheckContinueState();
pQuery = CQuery::NewQuery(m_papts[i]);
// Initialize the pRank structure so that the collection id portion is correct.
// pRank[cRankedHits] is the first element where textset i's search results begin.
for (int j = 0; j < cMinPerColl; j++)
pRank[cRankedHits + j].CollId = i;
// Pass a pointer to the subarray of pRank that will get the
// results of search against index i
CAbortSearch::CheckContinueState();
cRankedHits += pQuery->RetrieveWithFeedback(&pRank[cRankedHits], cMinPerColl, pwText, cwCopied, NULL, 0);
delete pQuery; pQuery= NULL;
}
VFree(pwText); pwText= NULL;
CAbortSearch::CheckContinueState();
// sort the scored documents.
qsort(pRank, cRankedHits, sizeof(SimStruct), CompareSimStruct);
if(fNewDialog= (m_pRankDialog == NULL))
{
CAbortSearch::CheckContinueState();
m_pRankDialog = New CRankDialog (m_hInst, IDD_RANK, m_hDlg, m_pflArticles, m_papts, m_cts, m_ptkc, m_ptlc);
m_pRankDialog->Create();
m_pRankDialog->SetFont(m_hFont);
}
// We pass the rank information to DataUpdate via pRankTmp rather than pRank
// because DataUpdate passes ownership of the array to m_pRankDialog. Subsequent
// to that rebinding it may raise an out-of-memory exception. Thus we must
// do this dance to avoid mistakenly deallocating pRank in our __finally epilog
// when we now longer own it.
SimStruct *pRankTmp= pRank; pRank= NULL;
CAbortSearch::CheckContinueState();
m_pRankDialog->DataUpdate( pRankTmp, cRankedHits);
}
__finally
{
ASSERT(!fAlreadySearching);
DequeueAbortDialog();
m_fDoneSearching = TRUE; // mfcc
}
}
__except(FilterFTExceptions(_exception_code()))
{
if (m_pRankDialog && fNewDialog)
{
delete m_pRankDialog; m_pRankDialog= NULL;
}
if (pwText) { VFree(pwText); pwText = NULL; }
if (pRank ) { VFree(pRank ); pRank = NULL; }
if (pQuery ) { delete pQuery; pQuery = NULL; }
if (hOldCur) { SetCursor(hOldCur); hOldCur = NULL; }
}
}
BOOL CALLBACK CFind::DlgWndProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
const static DWORD aFindHelpIDs[] = { // Context Help IDs
IDC_NARROW, IDH_FIND_TEXTBOX,
IDC_NUM_MATCHING_WORDS, NO_HELP,
IDC_GROUPBOX1, IDH_FIND_TOPICS_FOUND,
IDC_TOPICSFOUND_STATIC, IDH_FIND_TOPICS_FOUND,
IDC_GROUPBOX2, IDH_FIND_CRITERIA,
IDC_OPTIONS_STRING, IDH_FIND_CRITERIA,
IDC_TEST_DATA_BOX, NO_HELP,
IDC_CLEAR_EDIT, IDH_FIND_CLEAR,
IDC_OPTIONS, IDH_FIND_OPTIONS,
IDC_APPLYFEEDBACK, IDH_FIND_FIND_SIMILAR,
IDC_SEARCH_NOW, IDH_FIND_FIND_NOW,
IDC_INDEX, IDH_FIND_REBUILD,
IDC_WORDLIST_SB, IDH_FIND_WORDLIST,
IDC_WORDBASE_LIST, IDH_FIND_WORDLIST,
IDC_FILELIST_SB, IDH_FIND_TOPICLIST,
IDC_FILEBASE_LIST, IDH_FIND_TOPICLIST,
0, 0
};
BOOL bStatus = FALSE; // Assume we won't process the message
CFind *pFind = (CFind *) GetWindowLong(hDlg,DWL_USER);
switch (uMsg)
{
case WM_TIMER :
{
if (wParam == ID_CHECKDIRTY)
pFind->OnEditchangeNarrow();
}
break;
case UM_CLOSERANKS:
if (pFind->m_pRankDialog != NULL)
{
delete pFind->m_pRankDialog;
pFind->m_pRankDialog = NULL;
pFind->m_fFromSimilarTopics = FALSE;
}
break;
case UM_SIMILAR_SHOW:
pFind->m_fFromSimilarTopics = TRUE;
break;
case WM_CLOSE :
if (pFind->m_pRankDialog)
pFind->m_pRankDialog->Show(FALSE);
ShowWindow(hDlg,SW_HIDE);
SetParent(hDlg,GetDesktopWindow());
bStatus = TRUE;
break;
case UM_CONNECT:
{
SetParent(hDlg,(HWND) wParam);
if (lParam) ShowWindow(hDlg,SW_SHOW);
bStatus = TRUE;
}
break;
case WM_WINDOWPOSCHANGED:
{
BOOL flags = ((LPWINDOWPOS) lParam)->flags;
BOOL fShow = pFind->m_fFromSimilarTopics;
if (flags & SWP_SHOWWINDOW)
{
if (pFind->m_pRankDialog)
pFind->m_pRankDialog->Show(TRUE);
if (!fShow)
pFind->SetFocusToEdit();
}
bStatus= FALSE;
}
break;
case UM_CLOSE:
{
// HWND hWndEdit = ::GetWindow(GetDlgItem(pFind->m_hDlg,IDC_NARROW),GW_CHILD);
// ASSERT(hWndEdit && IsWindow(hWndEdit));
// REVIEW: why set the focus to hWndEdit when we're deleting the whole dialog?
// ::SetFocus(hWndEdit);
if (pFind->m_hFont)
{
pFind->m_pfs ->ReleaseFont();
pFind->m_pWordBase->ReleaseFont();
DeleteObject(pFind->m_hFont);
pFind->m_hFont= NULL;
}
::DestroyWindow(hDlg);
// BUGBUG: this code is called after the dialog has been destroyed
// (FARPROC) SetWindowLong(hWndEdit,GWL_WNDPROC,(LPARAM) m_dpOldProc); // UnSubclass it
// RemoveProp(hWndEdit,"FindClass");
bStatus= TRUE;
}
break;
case WM_INITDIALOG :
{
CFind *pFind = (CFind *) lParam;
bStatus = pFind->OnInitDialog(hDlg,(HWND) wParam,lParam);
}
break;
case WM_NCDESTROY:
{
pFind->OnNCDestroy();
}
break;
case WM_HELP:
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, HELP_FILE,
HELP_WM_HELP, (DWORD)(LPSTR) aFindHelpIDs);
bStatus = TRUE;
break;
case WM_CONTEXTMENU:
WinHelp((HWND) wParam, HELP_FILE, HELP_CONTEXTMENU,
(DWORD)(LPVOID) aFindHelpIDs);
bStatus = TRUE;
break;
case WM_COMMAND :
{
switch(LOWORD(wParam))
{
case IDC_INDEX:
if (HIWORD(wParam) == BN_CLICKED)
{
SendMessage(GetParent(pFind->m_hDlg), MSG_REINDEX_REQUEST, WPARAM(0), LPARAM(0));
}
break;
case IDC_CLEAR_EDIT :
if (HIWORD(wParam) == BN_CLICKED)
{
pFind->OnClearEdit();
pFind->SetFocusToEdit();
}
break;
case IDC_SEARCH_NOW :
if (HIWORD(wParam) == BN_CLICKED)
{
pFind->OnUpdateComboList();
pFind->SetFocusToEdit();
pFind->OnEditchangeNarrow();
}
break;
case IDC_OPTIONS :
if (HIWORD(wParam) == BN_CLICKED)
{
pFind->OnOptions();
pFind->SetFocusToEdit();
}
break;
case IDC_NARROW :
{
if(HIWORD(wParam) == CBN_EDITCHANGE)
pFind->DirtyEditBox(); // Mark as dirty for delayed update
}
break;
case IDC_WORDLIST_OD_LIST :
{
if ((HIWORD(wParam) == LBN_SELCHANGE) || (HIWORD(wParam) == LBN_DBLCLK))
pFind->OnWordListSelChange();
if (HIWORD(wParam) == LBN_SELCANCEL)
pFind->OnWordListSelCancel();
}
break;
case IDOK:
{
if (HIWORD(wParam) == BN_CLICKED)
{
pFind->OnDisplay();
}
}
break;
case IDC_TOPICSLIST_OD_LIST :
{
if (HIWORD(wParam) == LBN_DBLCLK)
{
pFind->OnDisplay();
}
else if (HIWORD(wParam) == LBN_SELCHANGE && HIWORD(lParam) == 1
&& pFind->m_ptkc->SimilaritySearch()
)
{
UINT iFile= pFind->m_pfs->InxSelectedFile();
ASSERT(iFile != UINT(-1));
pFind->m_pflArticles->MarkRelevant(iFile,!pFind->m_pflArticles->IsRelevant(iFile));
EnableWindow(GetDlgItem(pFind->m_hDlg, IDC_APPLYFEEDBACK), pFind->m_pflArticles->AnyRelevant());
}
}
break;
case IDC_APPLYFEEDBACK:
ASSERT(pFind->m_ptkc->SimilaritySearch());
pFind->OnApplyfeedback();
break;
}
}
break;
#if 0
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
pFind->m_hwndFocus= ::GetFocus();
else ::SetFocus(pFind->m_hwndFocus);
break;
case WM_KILLFOCUS:
pFind->m_hwndFocus= ::GetFocus();
break;
case WM_SETFOCUS:
::SetFocus(pFind->m_hwndFocus);
break;
#endif // 0
}
// Note do not call DefWindowProc to process unwanted window messages!
return bStatus;
}
LRESULT CALLBACK CFind::DlgEdtProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CFind *pFind = (CFind *) GetProp(hDlg,"FindClass");
BOOL bCallOn = TRUE;
LRESULT lRes;
ASSERT (pFind); // If this is not in the PROPS table we are really in bad straights!
switch (uMsg)
{
case WM_KILLFOCUS :
{
int iStart,iEnd;
pFind->GetSel(iStart,iEnd,TRUE); // Force the get!
}
break;
case WM_SETFOCUS :
{
lRes = CallWindowProc(m_dpOldProc,hDlg, uMsg, wParam, lParam);
SendMessage(pFind->m_hwndEditBox, EM_SETSEL, pFind->m_iStart, pFind->m_iEnd);
if (pFind->m_fFromSimilarTopics)
{
ASSERT(pFind->m_pRankDialog);
pFind->m_pRankDialog->SetFocus();
pFind->m_fFromSimilarTopics= FALSE;
}
bCallOn = FALSE;
}
break;
case WM_LBUTTONUP :
pFind->OnLButtonUp();
break;
case WM_KEYUP :
pFind->OnKeyUp(wParam,lParam);
break;
case WM_SETTEXT:
lRes = CallWindowProc(m_dpOldProc,hDlg, uMsg, wParam, lParam);
bCallOn = FALSE;
if (pFind->m_bAutoSearch) pFind->OnEditchangeNarrow();
break;
}
if (bCallOn) return CallWindowProc(m_dpOldProc,hDlg, uMsg, wParam, lParam);
else return lRes;
}
CIndicatorSet *CFind::VocabularyFor(CIndicatorSet *pisArticles)
{
UINT cts= m_ptkc->TextSetCount();
PTitleInfo *ppti= (PTitleInfo *) _alloca(cts * sizeof(PTitleInfo));
ASSERT(ppti);
m_ptlc->MapToTitleLists(pisArticles, ppti, cts);
CIndicatorSet *pisTokens= NULL;
// Since this is the only heap allocation in this routine and we don't call
// any routines that allocate from the heap, we don't need __try/__finally
// blocks in this routine.
pisTokens= CIndicatorSet::NewIndicatorSet(m_ptkc->RowCount());
UINT iTextSet;
for (iTextSet= cts; iTextSet--; )
{
PTitleInfo pti= ppti[iTextSet];
if (!pti) continue;
CTextSet *pts = m_papts[iTextSet];
const UINT *piMap = m_ptkc->UniversalTokenMap(iTextSet);
for (; pti; pti= pti->ptiNext)
pts->IndicateVocabularyRefs(pisTokens, pti->iPartition, piMap);
}
return pisTokens;
}
/////////////////////////////////////////////////////////////////////////////
// CRankDialog message handlers
CRankDialog::CRankDialog(HINSTANCE hInst, UINT uID, HWND hWnd, CFileList *pflArticles, CTextSet **papts, UINT cTextSets,
CTokenCollection *ptkc, CTitleCollection *ptlc
)
{
m_hInst = hInst;
m_ID = uID;
m_hParent = hWnd;
m_hDlg = NULL;
m_papts = papts;
m_ptkc = NULL; AttachRef(m_ptkc, ptkc);
m_ptlc = NULL; AttachRef(m_ptlc, ptlc);
m_pflArticles = pflArticles;
m_pflRankedList = NULL;
m_pfs = NULL;
m_aRank = NULL;
m_cHits = 0;
m_cTextSets = cTextSets;
}
CRankDialog::~CRankDialog()
{
if (m_aRank) VFree(m_aRank);
DetachRef(m_ptkc);
DetachRef(m_ptlc);
DisconnectDialog();
DestroyWindow(m_hDlg);
}
void CRankDialog::SetFont(HFONT hf)
{
if (hf) m_pfs->SetFont(hf);
}
BOOL CRankDialog::Create()
{
return ((m_hDlg = ::CreateDialogParam(m_hInst,MAKEINTRESOURCE(m_ID),
GetDesktopWindow(),(DLGPROC) &CRankDialog::DlgProc,
(LPARAM) this)) != NULL);
}
CRankDialog::DoModal()
{
return ::DialogBoxParam(m_hInst,MAKEINTRESOURCE(m_ID),m_hParent,(DLGPROC) &CRankDialog::DlgProc,(LPARAM) this);
}
void CRankDialog::SetFocus()
{
m_pfs->SetFocus();
}
void CRankDialog::OnOK()
{
// Clear the relevancy info.
m_pflArticles->ClearRelevancy();
ASSERT(m_hParent);
EnableWindow(GetDlgItem(m_hParent, IDC_APPLYFEEDBACK), FALSE);
SendMessage(m_hParent, UM_CLOSERANKS, 0, 0);
// EndDialog(m_hDlg, IDOK);
}
void CRankDialog::Show(BOOL bState)
{
ShowWindow(m_hDlg, bState ? SW_SHOW : SW_HIDE);
if (bState) SetFocus();
}
void CRankDialog::DataUpdate( SimStruct * aRank, UINT cHits)
{
DWORD c;
if (m_aRank) VFree(m_aRank);
m_aRank = aRank;
m_cHits = cHits;
PUINT paiSubset= NULL,
pai ;
paiSubset= PUINT(VAlloc(FALSE, cHits * sizeof(UINT)));
for (c= cHits, pai= paiSubset + cHits; c--; )
*--pai = m_ptlc->UniversalTitleMap(m_aRank[c].CollId)[m_aRank[c].DocId];
m_pflRankedList->UpdateList(m_ptlc->TokenSubset(paiSubset, cHits));
SetFocus();
}
void CRankDialog::DisconnectDialog()
{
if (!m_pfs) return; // To avoid disconnecting twice.
UINT cChildren= C_CHILD_WINDOWS;
for (; cChildren--; )
SetWindowLong(m_ahwndChildren[cChildren], GWL_WNDPROC, (LONG) m_apwndprocChildren[cChildren]);
ASSERT(m_pfs ); delete m_pfs; m_pfs = NULL;
ASSERT(m_pflRankedList); DetachRef(m_pflRankedList);
}
BOOL CRankDialog::OnInitDialog()
{
UINT iChild = 0;
HWND hwndChild = NULL;
ASSERT(!m_pflRankedList);
AttachRef(m_pflRankedList, CFileList::NewFileList(New CTokenList));
ASSERT(!m_pfs);
m_pfs= CFileBase::NewFileBase(m_pflRankedList, m_hDlg);
hwndChild= m_pfs->ViewerWnd();
ASSERT(iChild < C_CHILD_WINDOWS);
m_ahwndChildren [iChild] = hwndChild;
m_apwndprocChildren[iChild] = (WNDPROC) GetWindowLong(hwndChild, GWL_WNDPROC);
SetWindowLong(hwndChild, GWL_WNDPROC, (LONG) &GrandchildMessageFilter);
iChild++;
hwndChild= m_pfs->ScrollWnd();
ASSERT(iChild < C_CHILD_WINDOWS);
m_ahwndChildren [iChild] = hwndChild;
m_apwndprocChildren[iChild] = (WNDPROC) GetWindowLong(hwndChild, GWL_WNDPROC);
SetWindowLong(hwndChild, GWL_WNDPROC, (LONG) &GrandchildMessageFilter);
iChild++;
hwndChild= m_pfs->ListWnd();
ASSERT(iChild < C_CHILD_WINDOWS);
m_ahwndChildren [iChild] = hwndChild;
m_apwndprocChildren[iChild] = (WNDPROC) GetWindowLong(hwndChild, GWL_WNDPROC);
SetWindowLong(hwndChild, GWL_WNDPROC, (LONG) &ChildMessageFilter);
iChild++;
hwndChild= GetDlgItem(m_hDlg, IDOK);
ASSERT(iChild < C_CHILD_WINDOWS);
m_ahwndChildren [iChild] = hwndChild;
m_apwndprocChildren[iChild] = (WNDPROC) GetWindowLong(hwndChild, GWL_WNDPROC);
SetWindowLong(hwndChild, GWL_WNDPROC, (LONG) &ChildMessageFilter);
iChild++;
hwndChild= GetDlgItem(m_hDlg, IDCANCEL);
ASSERT(iChild < C_CHILD_WINDOWS);
m_ahwndChildren [iChild] = hwndChild;
m_apwndprocChildren[iChild] = (WNDPROC) GetWindowLong(hwndChild, GWL_WNDPROC);
SetWindowLong(hwndChild, GWL_WNDPROC, (LONG) &ChildMessageFilter);
return TRUE;
}
void CRankDialog::OnDisplay()
{
UINT c= m_pflRankedList->GetSelectedRow();
if (c == LB_ERR) return;
UINT iTextSet = m_aRank[c].CollId;
CTextSet *pts = NULL; AttachRef(pts, m_papts[iTextSet]);
UINT iFile = m_aRank[c].DocId; // pts->PartitionToFile(m_aRank[c].DocId);
UINT iPartition = iFile; // pts->TitleList()->GetSlotIndex(iFile);
HANDLE hTopic = pts->TopicHandle(iFile);
#ifdef _DEBUG
#ifdef SHOWMSG
if (pts->FPhraseFeedback())
{
PWCHAR wTitle = NULL;
LPSTR szTitle = NULL;
PWCHAR wImage = NULL;
LPSTR szImage = NULL;
__try
{
UINT cbTitle = pts->TitleList()->ColCount();
wTitle = (PWCHAR) VAlloc(FALSE, (cbTitle+1) * sizeof(WCHAR)); //rmk
szTitle = (LPSTR) VAlloc(FALSE, cbTitle+1); //rmk
int cwText = pts->TitleList()->GetWTokenI(iFile, wTitle, cbTitle); //rmk
CP cp = GetCPFromCharset(pts->GetDefaultCharSet());
int cbText = WideCharToMultiByte(cp, 0, wTitle, cwText, szTitle, cbTitle, NULL, NULL); //rmk
szTitle[cbText] = 0; //rmk
UINT cbImage= m_ptkc->TopicDisplayImageSize(iTextSet, iPartition);
// FALSE at the end indicates that we do not want the relevance dialog displayed.
CDisplayHelp cdh(m_hInst, IDD_DISPLAY_HELP, m_hDlg, iPartition, m_pflArticles);
cdh.SetTitle(szTitle); //rmk
wImage = (PWCHAR) VAlloc(FALSE, (cbImage+1) * sizeof(WCHAR)); //rmk
szImage = (LPSTR) VAlloc(FALSE, cbImage+1); //rmk
ASSERT(szImage); //rmk
cwText = m_ptkc->CopyTopicDisplayImage(UINT iTextSet, iPartition, wImage, cbImage); //rmk
cbText = WideCharToMultiByte(cp, 0, wImage, cwText, szImage, cbImage, NULL, NULL); //rmk
szImage[cbText] = 0; //rmk
cdh.SetText(szImage); //rmk
cdh.DoModal();
}
__finally
{
if (szTitle) { VFree(szTitle); szTitle = NULL; }
if (wTitle ) { VFree(wTitle ); wTitle = NULL; }
if (szImage) { VFree(szImage); szImage = NULL; }
if (wImage ) { VFree(wImage ); wImage = NULL; }
}
}
#endif // SHOWMSG
#endif // _DEBUG
HWND hwndParent= GetParent(m_hParent);
UINT uOpt= pts->IndexOptions();
if (hwndParent)
{
SendMessage(m_hParent, UM_SIMILAR_SHOW, 0, 0);
if (uOpt & USE_QWORD_JUMP)
{
QWordAddress qwa;
qwa.iSerial = pts->TopicSerial(iPartition);
qwa.hTopic = hTopic;
SendMessage(hwndParent, MSG_FTS_JUMP_QWORD , WPARAM(iTextSet), LPARAM(&qwa));
}
else
{
UINT uiMsg= (pts->IndexOptions() & USE_VA_ADDR)? MSG_FTS_JUMP_VA
: MSG_FTS_JUMP_HASH;
SendMessage(hwndParent, uiMsg, WPARAM(iTextSet), LPARAM(hTopic));
}
}
DetachRef(pts);
}
BOOL CALLBACK CRankDialog::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BOOL bStatus = FALSE; // Assume we won't process the message
CRankDialog *pToMe = (CRankDialog *) GetWindowLong(hDlg,DWL_USER);
switch (uMsg)
{
case WM_INITDIALOG :
{
// if focus is set to a control return FALSE
// Otherwise return TRUE;
SetWindowLong(hDlg,DWL_USER,lParam);
pToMe = (CRankDialog *) lParam;
pToMe->m_hDlg = hDlg;
// This code repositions the display window so that it does not
// overlap the parent (actually the owner) window.
RECT rcWindow, rcParent, rcDesktop;
GetWindowRect(pToMe->m_hParent, &rcParent);
GetWindowRect(hDlg, &rcWindow);
GetWindowRect(GetDesktopWindow(), &rcDesktop);
if ((rcDesktop.right - rcParent.right) > (rcWindow.right - rcWindow.left))
MoveWindow( hDlg, rcParent.right, rcParent.top,
rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
else
MoveWindow( hDlg, rcDesktop.right - (rcWindow.right - rcWindow.left), rcParent.top,
rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);
pToMe->OnInitDialog();
bStatus = TRUE; // did not set the focus == TRUE
}
break;
case WM_COMMAND :
{
bStatus = TRUE; // WM_COMMAND uses 0 = processes
switch(LOWORD(wParam))
{
case IDCANCEL :
if (HIWORD(wParam) == BN_CLICKED)
{pToMe->OnOK(); bStatus = FALSE;}
break;
case IDOK:
if (HIWORD(wParam) == BN_CLICKED)
{pToMe->OnDisplay(); bStatus = FALSE;}
break;
case IDC_TOPICSLIST_OD_LIST :
{
if (HIWORD(wParam) == LBN_DBLCLK)
{
pToMe->OnDisplay(); bStatus = FALSE;
}
}
break;
}
}
break;
case WM_CLOSE:
pToMe->DisconnectDialog();
bStatus= FALSE;
break;
}
// Note do not call DefWindowProc to process unwanted window messages!
return bStatus;
}
LRESULT CRankDialog::IsDlgMessageFilter(HWND hwnd, UINT msgType, WPARAM wparam, LPARAM lparam)
{
INT cWndChild = C_CHILD_WINDOWS;
HWND hwndChild = NULL;
switch(msgType)
{
case WM_LBUTTONDOWN:
case WM_SYSCHAR:
case WM_CHAR:
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
if (!(m_InIsDialogMessage))
{
MSG msg;
DWORD pos= GetMessagePos();
msg.hwnd= hwnd;
msg.message = msgType;
msg.wParam = wparam;
msg.lParam = lparam;
msg.time = GetMessageTime();
msg.pt.x = LOWORD(pos);
msg.pt.y = HIWORD(pos);
m_InIsDialogMessage = TRUE;
BOOL fProcessed= IsDialogMessage(m_hDlg, &msg);
m_InIsDialogMessage = FALSE;
if (fProcessed) return TRUE;
}
default:
for (; cWndChild--; ) {
if (hwnd == m_ahwndChildren[cWndChild]) {
return CallWindowProc(m_apwndprocChildren[cWndChild],
hwnd, msgType, wparam, lparam
);
// NOTE: If you try to call this function directly, you will get an
// Access Violation under NT. The problem goes away if you use
// CallWindowProc(). (mfcc)
}
}
}
ASSERT(FALSE); // Shouldn't happen! This means we were called for
// a window not listed in m_ahwndChildren.
return TRUE;
}
LRESULT CALLBACK CRankDialog::GrandchildMessageFilter(HWND hwnd, UINT msgType, WPARAM wparam, LPARAM lparam)
{
HWND hwndDlg = GetParent(GetParent(hwnd));
CRankDialog *pCRDlg = (CRankDialog *) GetWindowLong(hwndDlg, DWL_USER);
return pCRDlg->IsDlgMessageFilter(hwnd, msgType, wparam, lparam);
}
LRESULT CALLBACK CRankDialog::ChildMessageFilter(HWND hwnd, UINT msgType, WPARAM wparam, LPARAM lparam)
{
HWND hwndDlg = GetParent(hwnd);
CRankDialog *pCRDlg = (CRankDialog *) GetWindowLong(hwndDlg,DWL_USER);
return pCRDlg->IsDlgMessageFilter(hwnd, msgType, wparam, lparam);
}