2946 lines
88 KiB
C++
2946 lines
88 KiB
C++
// 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);
|
|
}
|