|
|
/*****************************************************************************
* Subset.cpp * * Copyright (C) Microsoft, 1989-1998 * Feb 22, 1998 * * Modification History: * * Ported to hhctrl.ocx from the old B2 code base. * *****************************************************************************/ #include "header.h"
#include "subset.h"
#include "resource.h"
#include "toc.h"
#include "cdefinss.h"
#include "verdef.h"
#include "secwin.h"
#define CmdID LOWORD(wParam)
#define CmdCode HIWORD(wParam)
#define CmdHwnd (HWND)lParam
/*
* Defines, the EXPANDED define aids in intrepreting the proper bit in the * FGT data structure depending on which LB we're operating on. */ #define EXPANDED(lb_id, ds) ((lb_id) ? ds->f_A_Open : ds->f_F_Open)
#define PRESENT(lb_id, ds) ((lb_id) ? ds->f_Available : ds->f_Filter)
// declare a static this pointer for our window procedures.
//
CDefineSS* CDefineSS::m_pThis;
//********************************************************************************
//
// CStructuralSubset Implementation - This is object representation of a subset.
//
//********************************************************************************
CSSList::CSSList() { m_iSubSetCount = 0; m_pHeadSubSets = m_pFTS_SS = m_pF1_SS = m_pTOC_SS = m_pNew_SS = m_pEC_SS = NULL; }
CSSList::~CSSList() { CStructuralSubset *pSS, *pSSNext;
pSS = m_pHeadSubSets; while ( pSS ) { pSSNext = pSS->m_pNext; delete pSS; pSS = pSSNext; } }
CStructuralSubset* CSSList::GetSubset(PSTR pszSSName) { CStructuralSubset *pSS = m_pHeadSubSets;
while ( pSS ) { if (! lstrcmpi(pSS->GetName(), pszSSName) ) return pSS; pSS = pSS->m_pNext; } return NULL; }
void CSSList::DeleteSubset(CStructuralSubset* pSS, CStructuralSubset* pSSNew, /* == NULL */ HWND hWndUI /* == NULL */) { CStructuralSubset *pSSCurrCB, *pSSl = m_pHeadSubSets; TCHAR szSel[MAX_SS_NAME_LEN]; HWND hWndCB; INT_PTR i; CHHWinType* phh;
if (! pSSNew ) pSSNew = m_pEC_SS;
if ( pSS->m_dwFlags & SS_READ_ONLY ) return;
if ( pSS == m_pFTS_SS ) m_pFTS_SS = pSSNew; if ( pSS == m_pF1_SS ) m_pF1_SS = pSSNew; if ( pSS == m_pTOC_SS ) m_pTOC_SS = pSSNew; //
// If we're given an hwnd, update the combo-box UI.
//
if ( hWndUI && (hWndCB = GetDlgItem(hWndUI, IDC_SS_PICKER)) ) { //
// Get the current CB selection and see if it's the one we're deleting ?
//
if ( ((i = SendMessage(hWndCB, CB_GETCURSEL, 0, 0L)) != -1) ) { GetDlgItemText(hWndUI, IDC_SS_PICKER, szSel, sizeof(szSel));
pSSCurrCB = GetSubset(szSel); if ( pSSCurrCB == pSS ) // Yep, we're deleting the current one, select the new one.
{ SendMessage(hWndCB, CB_SELECTSTRING, -1, (LPARAM)pSSNew->GetName()); if ( (phh = FindWindowIndex(hWndUI)) ) { pSSNew->SelectAsTOCSubset(phh->m_phmData->m_pTitleCollection); phh->UpdateInformationTypes(); // This call re-draws the TOC.
} } } if ( lstrcmpi(pSS->GetName(), pSSNew->GetName()) ) { if ( (i = SendMessage(hWndCB, CB_FINDSTRING, -1, (LPARAM)pSS->GetName())) != -1 ) SendMessage(hWndCB, CB_DELETESTRING, i, 0L); } } //
// Take the delete victum out of the linked list.
//
while ( pSSl ) { if ( pSSl->m_pNext == pSS ) { pSSl->m_pNext = pSS->m_pNext; delete pSS; break; } pSSl = pSSl->m_pNext; } m_iSubSetCount--; }
HRESULT CSSList::PersistSubsets(CExCollection* pCollection) { LPCSTR lpszFQSSStore; HANDLE hFile; SSHEADER ssHeader; CStructuralSubset* pSS; CStructuralSubset* pSSCurr = NULL; PSS pSSFile = NULL; unsigned long ulCnt; int iSSSize; int i = 0;
if (! (pSS = m_pHeadSubSets) ) return S_OK; //
// Count'em
//
do { if ( pSS->IsTOC() ) pSSCurr = pSS; if ( !pSS->IsEntire() && !pSS->IsEmpty() && !pSS->IsReadOnly() ) i++; } while ( (pSS = GetNextSubset(pSS)) ); //
// Prepare a file.
//
if (! (lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathnameByLanguage()) ) return E_FAIL; hFile = CreateFile(lpszFQSSStore, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0); if ( hFile == INVALID_HANDLE_VALUE ) return E_FAIL; //
// Fill in the header, write out the header.
//
// Need to store the persisted subset in the header since it may be a predefine.
//
ssHeader.dwSig = SS_FILE_SIGNATURE; ssHeader.dwVer = (VER_PRODUCTVERSION_DW & 0x0000); ssHeader.iSSCount = i; ssHeader.dwFlags = 0; if ( pSSCurr ) lstrcpy(ssHeader.lpszCurrentSSName, pSSCurr->GetName()); if (! WriteFile(hFile, &ssHeader, sizeof(SSHEADER), &ulCnt, NULL) ) { MsgBox(IDS_PERSIST_SUBSET_ERR, MB_OK | MB_ICONHAND); return E_FAIL; } //
// Write out the subsets.
//
pSS = m_pHeadSubSets; do { if ( pSS->IsEntire() || pSS->IsEmpty() || pSS->IsReadOnly() ) continue; int iHashCnt = pSS->GetHashCount(); iSSSize = (sizeof(SS) + ((iHashCnt - 1) * sizeof(DWORD))); if ( (pSSFile = (PSS)lcReAlloc(pSSFile, iSSSize)) ) { pSSFile->iHashCount = iHashCnt; lstrcpy(pSSFile->lpszSSName, pSS->GetName()); lstrcpy(pSSFile->lpszSSID, pSS->GetID()); pSSFile->dwFlags = pSS->m_dwFlags; while ( --iHashCnt >= 0) pSSFile->dwHashes[iHashCnt] = pSS->EnumHashes(iHashCnt); if (! WriteFile(hFile, pSSFile, iSSSize, &ulCnt, NULL) ) { MsgBox(IDS_PERSIST_SUBSET_ERR, MB_OK | MB_ICONHAND); lcFree(pSSFile); CloseHandle(hFile); return E_FAIL; } } } while ( (pSS = GetNextSubset(pSS)) );
lcFree(pSSFile); CloseHandle(hFile); return S_OK; }
HRESULT CSSList::RestoreSubsets(CExCollection* pCollection, PSTR pszRestoreSS) { LPCSTR lpszFQSSStore; HANDLE hFile; SSHEADER ssHeader; PSS pSSFile; CStructuralSubset* pSS; unsigned long ulHashCnt, ulRead; HRESULT hr = E_FAIL;
if (! (pSSFile = (PSS)lcMalloc(sizeof(SS) + sizeof(DWORD) * 50)) ) return hr; lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathnameByLanguage(); hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if ( hFile == INVALID_HANDLE_VALUE) { lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathname(); hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if ( hFile == INVALID_HANDLE_VALUE) { lpszFQSSStore = pCollection->GetLocalStoragePathname(".chs"); hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if ( hFile == INVALID_HANDLE_VALUE ) { lcFree(pSSFile); return hr; } } } //
// Read the header.
//
if (! ReadFile(hFile, &ssHeader, sizeof(SSHEADER), &ulRead, NULL) ) goto crap_out; if ( ssHeader.dwSig != SS_FILE_SIGNATURE ) goto crap_out; //
// Get the subsets.
//
while ( ssHeader.iSSCount-- ) { if (! ReadFile(hFile, &ulHashCnt, sizeof(int), &ulRead, NULL) ) goto crap_out; if ( ulHashCnt > 51 ) { if (! (pSSFile = (PSS)lcReAlloc(pSSFile, sizeof(SS) + (sizeof(DWORD) * ulHashCnt))) ) goto crap_out; } pSSFile->iHashCount = ulHashCnt; unsigned long ulAmt = ((sizeof(SS) - sizeof(int)) + (sizeof(DWORD) * (ulHashCnt - 1))); if (! ReadFile(hFile, (((BYTE*)pSSFile) + sizeof(int)), ulAmt, &ulRead, NULL) ) goto crap_out; //
// Now create a CStructuralSubset from the data.
//
pSS = new CStructuralSubset(pSSFile->lpszSSName); pSS->m_dwFlags = pSSFile->dwFlags; pSS->m_dwFlags &= ~(SS_FTS | SS_TOC | SS_F1); // Insure selection bits are reset.
lstrcpy(pSS->m_szSSID, pSSFile->lpszSSID); while ( ulHashCnt ) pSS->AddHash(pSSFile->dwHashes[--ulHashCnt]); //
// Add the subset to the list appropiatly.
//
AddSubset(pSS); if (! lstrcmpi(ssHeader.lpszCurrentSSName, pSS->GetName() ) ) { SetFTS(pSS); SetTOC(pSS); SetF1(pSS); } } if ( pszRestoreSS ) lstrcpy(pszRestoreSS, ssHeader.lpszCurrentSSName); hr = S_OK; crap_out: lcFree(pSSFile); CloseHandle(hFile); return hr; }
HRESULT CSSList::ReadPreDefinedSubsets(CExCollection* pCollection, PSTR pszRestoreSS) { SSHEADER ssHeader; PSS pSSFile; CStructuralSubset* pSS; CSubFileSystem* pSubFS; unsigned long ulHashCnt, ulRead; HRESULT hr = E_FAIL;
if (! (pSSFile = (PSS)lcMalloc(sizeof(SS) + sizeof(DWORD) * 50)) ) return hr;
if (! pCollection || !pCollection->GetMasterTitle() ) return hr;
pSubFS = new CSubFileSystem(pCollection->GetMasterTitle()->GetTitleIdxFileSystem()); if ( !SUCCEEDED(pSubFS->OpenSub("predef.chs")) ) goto crap_out; //
// Read the header.
//
if ( !SUCCEEDED(pSubFS->ReadSub(&ssHeader, sizeof(SSHEADER), &ulRead)) ) goto crap_out; if ( ssHeader.dwSig != SS_FILE_SIGNATURE ) goto crap_out; //
// Get the subsets.
//
while ( ssHeader.iSSCount-- ) { if ( !SUCCEEDED(pSubFS->ReadSub(&ulHashCnt, sizeof(int), &ulRead)) ) goto crap_out; if ( ulHashCnt > 51 ) { if (! (pSSFile = (PSS)lcReAlloc(pSSFile, sizeof(SS) + (sizeof(DWORD) * ulHashCnt))) ) goto crap_out; } pSSFile->iHashCount = ulHashCnt; unsigned long ulAmt = ((sizeof(SS) - sizeof(int)) + (sizeof(DWORD) * (ulHashCnt - 1))); if ( !SUCCEEDED(pSubFS->ReadSub((((BYTE*)pSSFile) + sizeof(int)), ulAmt, &ulRead)) ) goto crap_out; //
// Now create a CStructuralSubset from the data.
//
pSS = new CStructuralSubset(pSSFile->lpszSSName); pSS->m_dwFlags = pSSFile->dwFlags; pSS->m_dwFlags &= ~(SS_FTS | SS_TOC | SS_F1); // Insure selection bits are reset.
pSS->m_dwFlags |= SS_READ_ONLY; lstrcpy(pSS->m_szSSID, pSSFile->lpszSSID); while ( ulHashCnt ) pSS->AddHash(pSSFile->dwHashes[--ulHashCnt]); //
// Add the subset to the list appropiatly.
//
AddSubset(pSS); if (! lstrcmpi(pszRestoreSS, pSS->GetName() ) ) { SetFTS(pSS); SetTOC(pSS); SetF1(pSS); } } hr = S_OK; crap_out: lcFree(pSSFile); delete pSubFS; return hr; }
HRESULT CSSList::AddSubset(CStructuralSubset* pSS, HWND hWndUI /* == NULL */) { CStructuralSubset *pSSl; HWND hWndCB;
if (! m_pHeadSubSets ) m_pHeadSubSets = pSS; else { pSSl = m_pHeadSubSets; while ( pSSl->m_pNext ) pSSl = pSSl->m_pNext;
pSSl->m_pNext = pSS; pSS->m_pNext = NULL; } m_iSubSetCount++; if ( hWndUI && (hWndCB = GetDlgItem(hWndUI, IDC_SS_PICKER)) ) { if ( SendMessage(hWndCB, CB_FINDSTRING, -1, (LPARAM)pSS->GetName()) == -1 ) SendMessage(hWndCB, CB_ADDSTRING, 0, (LPARAM)pSS->GetName()); } return S_OK; }
void CSSList::Set(CStructuralSubset* pSSNew, CStructuralSubset** pSSOld, DWORD dwFlags) { if (! pSSNew ) return;
pSSNew->m_dwFlags |= dwFlags; if ( *pSSOld && (pSSNew != *pSSOld) ) (*pSSOld)->m_dwFlags &= ~dwFlags; *pSSOld = pSSNew; }
//********************************************************************************
//
// CStructuralSubset Implementation - This is object representation of a subset.
//
//********************************************************************************
CStructuralSubset::CStructuralSubset(PCSTR pszSubSetName) { TCHAR* psz; int i = 0;
m_szSSID[0] = '\0';
if ( pszSubSetName ) { if ( (psz = StrChr(pszSubSetName, '|')) ) // If the subset name contains an identifier, process it.
{ psz = AnsiNext(psz); lstrcpyn(m_szSubSetName, psz, MAX_SS_NAME_LEN); while ( pszSubSetName[i] != '|' && (i < MAX_SS_NAME_LEN) ) { m_szSSID[i] = pszSubSetName[i]; i++; } m_szSSID[i] = '\0'; // terminate.
} else lstrcpyn(m_szSubSetName, pszSubSetName, MAX_SS_NAME_LEN); } else { m_szSubSetName[0] = '\0'; m_szSSID[0] = '\0'; } m_pdwHashes = NULL; m_iAllocatedCount = m_iHashCount = 0; m_dwFlags = 0; m_pNext = NULL; }
CStructuralSubset::~CStructuralSubset() { if ( m_pdwHashes ) lcFree(m_pdwHashes); }
HASH CStructuralSubset::EnumHashes(int pos) { if ( !m_iHashCount || (pos >= m_iHashCount) || (pos < 0) ) return 0; return m_pdwHashes[pos]; }
void CStructuralSubset::AddHash(DWORD dwHash) { if ( (m_iHashCount && (!(m_iHashCount % 12))) || (m_iAllocatedCount == 0) ) { m_iAllocatedCount += 12; m_pdwHashes = (HASH*)lcReAlloc(m_pdwHashes, sizeof(HASH) * m_iAllocatedCount); } m_pdwHashes[m_iHashCount] = dwHash; m_iHashCount++; }
BOOL CStructuralSubset::IsTitleInSubset(CExTitle* pTitle) { int i;
for (i = 0; i < m_iHashCount; i++) { if ( m_pdwHashes[i] == pTitle->m_dwHash ) return TRUE; } return FALSE; }
//
// Function selects the subset as the current TOC filter by setting the f_IsVisable bit accordingly.
// NOTE: we don't bother selecting the bits for entire contents, this is special cased for performance reasons.
//
void CStructuralSubset::SelectAsTOCSubset(CExCollection* pCollection) { CFolder* pFgt; // pointer to filtered group tree.
UINT i = 0; HASH Hash;
if ( IsEntire() || IsEmpty() ) return;
pFgt = pCollection->m_Collection.GetVisableRootFolder(); //
// De-select all node's filter bits and select the proper
// tree nodes based on the hash list!
//
while ( pFgt ) { MarkNode(pFgt, 0); // Remove nodes by marking as not visable. // RemoveNodeFromFilter(pFgt);
pFgt = pFgt->pNext; } while ( Hash = EnumHashes(i++) ) { if ( (pFgt = pCollection->m_pCSlt->HashToCFolder(Hash)) ) MarkNode(pFgt, 1); // Add nodes by marking as "visable". // AddNode2Filter(pFgt);
} }
void CStructuralSubset::MarkNode(CFolder* pFgti, BOOL bVisable) { CFolder* pFgt; CFolder* pFgtLast;
// First, mark the node and any children of the node.
//
pFgt = pFgti; if ( pFgt->pKid ) { while ( pFgt ) { do { pFgt->f_IsVisable = bVisable; pFgtLast = pFgt; pFgt = pFgt->pKid;
} while ( pFgt ); pFgt = pFgtLast; while ( pFgt && (! (pFgt->pNext)) ) { if ( pFgt->pParent != pFgti ) pFgt = pFgt->pParent; else break; } if ( pFgt ) pFgt = pFgt->pNext; } } // Next, assure any parents of the node are properly marked.
//
pFgt = pFgti; pFgt->f_IsVisable = bVisable;
while ( (pFgt = pFgt->pParent) ) pFgt->f_IsVisable = bVisable; }
//****************************************************************************
//
// CDefineSS Implementation - This is the guy that does all the UI.
//
//*****************************************************************************
CDefineSS::CDefineSS(CExCollection* pCollection) { m_bShouldSave = FALSE; m_pSS = NULL; m_pCollection = pCollection; m_hIL = 0; m_hWndParent = 0; }
CDefineSS::~CDefineSS() { }
/****************************************************************************
* IDefineFilter() * * Internal entry point for filter manipulation dialog. * * ENTRY: * none. * * EXIT: * none. * ****************************************************************************/ CStructuralSubset* CDefineSS::DefineSubset(HWND hWnd, CStructuralSubset* pSS) { m_pSS = pSS;
if (! m_hIL ) { m_hIL = ImageList_LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_CNT_IMAGE_LIST), CWIDTH_IMAGE_LIST, 0, 0x00FF00FF, IMAGE_BITMAP, 0); if (! m_hIL ) return NULL; } //
// Create the model dialog.
//
m_pThis = this; m_hWndParent = hWnd; if(g_bWinNT5) return (CStructuralSubset*)DialogBoxW(_Module.GetResourceInstance(), MAKEINTRESOURCEW(DLG_FILTERS), hWnd, FilterDlgProc); else return (CStructuralSubset*)DialogBox(_Module.GetResourceInstance(), MAKEINTRESOURCE(DLG_FILTERS), hWnd, FilterDlgProc); }
/*****************************************************************************
* MyFilterLBFunc() * * ListBox subclasser. Used for our filter construction LB's. Needed so * we can do proper mouse move processing for diddiling the cursor and * implementing the silly collpase feature. * * ENTRY: * The usual window procedure parameters. * * EXIT: * a long LRESULT. * *****************************************************************************/ LRESULT CDefineSS::MyFilterLBFunc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { int iTop, iHeight, iItem; POINT pt; CFolder* pFgt;
switch (uiMsg) { case WM_SETCURSOR: m_pThis->m_giXpos = -1; iTop = (int)SendMessage(hWnd, LB_GETTOPINDEX, 0, 0L); iHeight = (int)SendMessage(hWnd, LB_GETITEMHEIGHT, 0, 0L); GetCursorPos(&pt); ScreenToClient(hWnd, &pt); //
// Compute index of the item the cursor is currently hovering over
// and then get the item data for that item so we can determine it's
// level and diddle the cursor appropiatly.
//
iItem = ((pt.y / iHeight) + iTop); if ( (pFgt = (CFolder*)SendMessage(hWnd, LB_GETITEMDATA, iItem, (LPARAM)0)) != (CFolder*)LB_ERR ) { if ( pFgt->iLevel >= 1 ) { if ( pt.x < (pFgt->iLevel * m_pThis->m_giIndentSpacing) ) { SetCursor(LoadCursor(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDC_COLLAPSE))); m_pThis->m_giXpos = pt.x; return(TRUE); } } } break;
case WM_KEYDOWN: PostMessage(hWnd, WM_SETCURSOR, 0, 0L); break;
// HACKHACK - we have a hidden button called IDOK that
// we use to trap VK_RETURNs so we can send these to
// the list boxes or other controls
case WM_SETFOCUS: m_pThis->SetDefaultButton( GetParent(hWnd), IDOK, FALSE ); break;
} return(CallWindowProc(m_pThis->m_lpfnOrigLBProc, hWnd, uiMsg, wParam, lParam)); }
/*****************************************************************************
* FilterDlgProc() * * Filter dialog handler * * ENTRY: * Standard windows callback params. * * EXIT: * BOOL - TRUE if we handled it. FALSE if we didn't. * ****************************************************************************/ INT_PTR CDefineSS::FilterDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { int i; CFolder* pfgt;
switch(msg) { case WM_INITDIALOG: { //
// Set the this pointers for our LB message hook procedures. Also, set the procedure hooks
// for our LB's so we can do cursor changes, tree collapse and proper keyboard interface.
//
SendMessage(GetDlgItem(hDlg,IDF_AVAIL), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0); SendMessage(GetDlgItem(hDlg,IDF_RANGE), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0); SendMessage(GetDlgItem(hDlg,IDF_RANGES), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0); // SendMessage(GetDlgItem(hDlg,IDF_RANGES), WM_SETFONT, (WPARAM)_Resource.GetUIFont(), 0);
m_pThis->m_lpfnOrigLBProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg,IDF_RANGE), GWLP_WNDPROC, (LONG_PTR)MyFilterLBFunc); SetWindowLongPtr(GetDlgItem(hDlg,IDF_AVAIL), GWLP_WNDPROC, (LONG_PTR)MyFilterLBFunc); SendDlgItemMessage(hDlg, IDF_SAVE_EC, EM_LIMITTEXT, MAX_SS_NAME_LEN - 1, 0L); SendMessage(GetDlgItem(hDlg,IDF_SAVE_EC), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0); m_pThis->InitDialog(hDlg, NULL); m_pThis->m_bShouldSave = FALSE; // set the Close button as the default button
m_pThis->SetDefaultButton( hDlg, IDCANCEL, FALSE ); m_pThis->m_giXpos = -1; break; }
case WM_CHARTOITEM: // swallow these
return( -2 );
case WM_VKEYTOITEM: switch (CmdID) { case 0xBD: // '-'
case VK_SUBTRACT: pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0); m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL)); return(-2);
case VK_HOME: if (CmdID == VK_HOME && !(GetKeyState(VK_CONTROL) & 0x8000 )) return( -1 );
// otherwise fall through
case VK_LEFT: if ( ((CmdID == VK_HOME)||(CmdID == VK_LEFT)) && (GetKeyState(VK_CONTROL) & 0x8000 )) { // Close everyone
pfgt= (CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, 0, (LPARAM)0); while (pfgt->pNext) {
m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL)); pfgt = pfgt->pNext; } } else { pfgt= (CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0); m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL)); } return(-2);
case VK_BACK: { // go to parent
CFolder* pFgtCaret; int caret;
if ( (caret = (int)SendMessage(CmdHwnd,LB_GETCARETINDEX,0,0L)) == -1 ) return -2; if (! (pFgtCaret=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, caret, (LPARAM)0)) ) return -2; pFgtCaret = pFgtCaret->pParent; if( pFgtCaret ) { SendMessage(CmdHwnd, LB_SETSEL, FALSE, MAKELPARAM(caret,0)); if ( (caret = (int)SendMessage(CmdHwnd,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtCaret)) == -1 ) caret = 0; SendMessage(CmdHwnd, LB_SETCARETINDEX, caret, 0L); SendMessage(CmdHwnd, LB_SETSEL, TRUE, MAKELPARAM(caret,0)); } return(-2); }
case 0xBB: // '+'
case VK_ADD: pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0); m_pThis->ExpandContract(CmdHwnd, pfgt, TRUE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL) ); return(-2);
case VK_RIGHT: { INT ci;
pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0); m_pThis->ExpandContract(CmdHwnd, pfgt, TRUE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL));
// select the first child if it has one
if ( CmdID == VK_RIGHT && pfgt->pKid && (ci = (INT)SendMessage(CmdHwnd, LB_GETCARETINDEX, 0, 0L)) != LB_ERR ) { SendMessage(CmdHwnd, LB_SETSEL, FALSE, MAKELPARAM(ci,0)); SendMessage(CmdHwnd, LB_SETCARETINDEX, ci++, MAKELPARAM(0,0)); SendMessage(CmdHwnd, LB_SETSEL, TRUE, MAKELPARAM(ci,0)); }
return(-2); }
case VK_RETURN: SendMessage( CmdHwnd, WM_COMMAND, ((HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL))?IDF_AVAIL:IDF_RANGE, MAKELPARAM(CmdHwnd,LBN_DBLCLK)); return(-2);
} return(-1); // Tell dlgmgr we didn't handle this key stroke.
case WM_NCLBUTTONDOWN: SendDlgItemMessage(hDlg,IDF_RANGES,CB_SHOWDROPDOWN,FALSE,0L); return(FALSE);
case WM_DRAWITEM: // draw one of our listbox items
m_pThis->DrawFBItem(hDlg, (LPDRAWITEMSTRUCT)lParam, (UINT)wParam); break;
case WM_MEASUREITEM: // report how big our items are
m_pThis->MeasureFBItem((LPMEASUREITEMSTRUCT)lParam); break;
case WM_COMMAND: if ( m_pThis->FilterDlgCommand(hDlg, wParam, lParam) ) { i = m_pThis->FillFilterTree(GetDlgItem(hDlg,IDF_RANGE), FALSE, FALSE); EnableWindow(GetDlgItem(hDlg,IDF_REMOVE), (i != 0)); EnableWindow(GetDlgItem(hDlg,IDF_REMOVEALL), (i != 0)); i = m_pThis->FillFilterTree(GetDlgItem(hDlg,IDF_AVAIL), TRUE, FALSE); EnableWindow(GetDlgItem(hDlg,IDF_ADD), (i != 0)); EnableWindow(GetDlgItem(hDlg,IDF_ADDALL), (i != 0)); m_pThis->SetSaveStatus(hDlg); } else return FALSE; break;
case WM_CLOSE: // Closing the Dialog behaves the same as Cancel
PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L); break;
case WM_DESTROY: break;
default: return FALSE; // say we didn't handle it
break; } return TRUE; // say we did handle it
}
/*****************************************************************************
* MeasureFBItem() * * Set appropiate size entries in the measure item struc according to the * items we'll be rendering in the filter listboxes. * * ENTRY: * hDlg - Handle to the filter dialog. * lpMIS - Pointer to the LPMEASUREITEMSTRUCT * * EXIT: * None. * *****************************************************************************/ void CDefineSS::MeasureFBItem(LPMEASUREITEMSTRUCT lpMIS) { POINT pt; HDC hDC; HFONT hOldFont; TEXTMETRIC tm;
ImageList_GetIconSize(m_hIL, (int*)&pt.x, (int*)&pt.y); hDC = GetDC(NULL); hOldFont = (HFONT)SelectObject(hDC, m_pCollection->m_phmData->GetContentFont()); GetTextMetrics(hDC, &tm); SelectObject(hDC, hOldFont); ReleaseDC(NULL, hDC);
if ( pt.y > tm.tmHeight ) lpMIS->itemHeight = pt.y; else lpMIS->itemHeight = tm.tmHeight;
m_giIndentSpacing = pt.x; m_iFontHeight = tm.tmHeight; m_iGlyphX = pt.x; m_iGlyphY = pt.y; }
/*****************************************************************************
* InitDialog() * * Do all initialization of the range definition dialog for a particular * situation, Add, Delete or Change. * * ENTRY: * hDlg - The handle to the dialog. * szRange - Pointer to new range or NULL if initing the range combo-box. * * EXIT: * BOOL - TRUE on success, FALSE on failure. * ****************************************************************************/ BOOL CDefineSS::InitDialog(HWND hDlg, LPSTR szRange) { int iSel = 0; int i = 0; int iFilterCnt = 0; BOOL bDef = FALSE; CStructuralSubset* pSS = NULL;
SendDlgItemMessage(hDlg,IDF_RANGES,CB_SETEXTENDEDUI,TRUE,0L);
if (! m_pCollection->m_pSSList ) return(FALSE);
if (! szRange ) { SendDlgItemMessage(hDlg, IDF_RANGES, CB_RESETCONTENT, 0, 0L); while ( (pSS = m_pCollection->m_pSSList->GetNextSubset(pSS)) ) { i = (int) SendDlgItemMessage(hDlg, IDF_RANGES, CB_INSERTSTRING, (WPARAM) -1, (LPARAM)(LPSTR)pSS->GetName()); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETITEMDATA, i, (LPARAM)((DWORD_PTR)pSS)); } } else { if ( (iSel = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT,0, (LPARAM)szRange)) != LB_ERR ) pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, iSel,0L); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, iSel, 0L); bDef = TRUE; } //
// Select the current filter. If it's "entire CD" select "New".
//
if (! bDef || ! pSS) { pSS = m_pCollection->m_pSSList->GetNew(); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)pSS->GetName()); } //
// Init the listboxes!
//
SetRangeToTree(pSS); //
// Init filter LB and remove options.
//
i = FillFilterTree(GetDlgItem(hDlg,IDF_RANGE), FALSE, FALSE); EnableWindow(GetDlgItem(hDlg,IDF_REMOVE), (i != 0)); EnableWindow(GetDlgItem(hDlg,IDF_REMOVEALL), (i != 0)); //
// Init available LB and add options.
//
i = FillFilterTree(GetDlgItem(hDlg,IDF_AVAIL), TRUE, FALSE); EnableWindow(GetDlgItem(hDlg,IDF_ADD), (i != 0)); EnableWindow(GetDlgItem(hDlg,IDF_ADDALL), (i != 0)); //
// deal with buttons
//
if ( pSS->IsReadOnly() ) { EnableWindow(GetDlgItem(hDlg, IDF_DELETE), FALSE); SetWindowText(GetDlgItem(hDlg,IDF_SAVE_EC),GetStringResource(IDS_UNTITLED_SUBSET)); } else { EnableWindow(GetDlgItem(hDlg, IDF_DELETE), TRUE); SetWindowText(GetDlgItem(hDlg,IDF_SAVE_EC), pSS->GetName()); } EnableWindow(GetDlgItem(hDlg,IDF_SAVE), FALSE); return(TRUE); }
/*****************************************************************************
* DoesNodeHaveANext() * * aids DrawFBItem() in painting the vertical connecting codes in the filter * list boxes. * * ENTRY: * LbId - ListBox ID. * n - What level are we painting. * pFgt - Pointer to the node we're painting. * * EXIT: * BOOL - TRUE if a next will appear on the given level. FALSE otherwise. * ****************************************************************************/ BOOL CDefineSS::DoesNodeHaveANext(UINT LbId, int n, CFolder* pFgt) { while ( pFgt->iLevel > (n + 1) ) pFgt = pFgt->pParent;
while ( pFgt->pNext ) { pFgt = pFgt->pNext; if ( (PRESENT((LbId == IDF_AVAIL), pFgt)) ) return(TRUE); } return(FALSE); }
/*****************************************************************************
* DrawFBItem() * * Function is responsible for painting the items in the owner-draw list boxes * that are used in the filter contents dialog. * * ENTRY: * hDlg - Handle to the dialog. * lpDI - Pointer to the draw item struct. Contains a pFgt to the item * we're painting. * Lbid - ListBox identifier. * * EXIT: * None. * ****************************************************************************/ void CDefineSS::DrawFBItem(HWND hDlg, LPDRAWITEMSTRUCT lpDI, UINT LbId) { RECT rc; int n; WORD wTopText; HDC hDC; CFolder* pFgt; INT xBitmap = 0; int iHeight; BOOL bHasNext; char* lpszText; char szScratch[MAX_PATH]; static int bNoReEnter = 0;
if (lpDI->itemID == 0xFFFF) return; pFgt = (CFolder*)lpDI->itemData; if (!pFgt || lpDI->itemData == -1 ) return;
bNoReEnter++; if ( bNoReEnter > 1 ) { bNoReEnter--; return; }
hDC = lpDI->hDC; rc = lpDI->rcItem; iHeight = rc.bottom - rc.top; wTopText = (WORD)((rc.top + ((iHeight) / 2)) - ((m_iFontHeight - 2) / 2)); /*
* Paint the proper lines based on the level and position of the item. */ if ( pFgt->iLevel ) { for ( n = 0; n < pFgt->iLevel; n++ ) { // Draw the verticle line indicating level. Remember to not leave a
// "tail".
//
bHasNext = DoesNodeHaveANext(LbId, n, pFgt); if ( bHasNext ) QRect(hDC, rc.left + m_iGlyphX / 2, rc.top, // Full verticle line.
1, iHeight, COLOR_WINDOWTEXT); else if ( n == (pFgt->iLevel - 1) ) QRect(hDC, rc.left + m_iGlyphX / 2, rc.top, // Half vertical line.
1, (iHeight / 2), COLOR_WINDOWTEXT);
rc.left += m_iGlyphX; } // Draw the horizontal connector line.
//
QRect(hDC, (rc.left - m_iGlyphX / 2), (rc.top + (m_iGlyphY / 2)), ((m_iGlyphX / 2)), 1, COLOR_WINDOWTEXT); } //
// draw the little book.
//
if ( EXPANDED((LbId == IDF_AVAIL), pFgt) ) // Is the book open or closed ?
xBitmap++; // It's an open book.
ImageList_Draw(m_hIL, xBitmap, hDC, rc.left+1, rc.top, ILD_NORMAL); rc.left += m_iGlyphX + 2; if ( lpDI->itemState & ODS_SELECTED ) { SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); } //
// Now paint the text.
//
if ( pFgt->f_HasHash && pFgt->pExTitle ) { pFgt->pExTitle->GetTopicLocation(0, szScratch, sizeof(szScratch)); lpszText = szScratch; } else lpszText = pFgt->Title; //
// Set LB Horizontal extent based upon the width of the string.
//
int iWidth, len = lstrlen(lpszText); SIZE size;
if ( lpDI->itemAction == ODA_DRAWENTIRE ) { GetTextExtentPoint32(hDC, lpszText, len, &size); size.cx += rc.left + 4; iWidth = (int)SendDlgItemMessage(hDlg, LbId, LB_GETHORIZONTALEXTENT, 0, 0L); if ( size.cx > iWidth ) SendDlgItemMessage(hDlg, LbId, LB_SETHORIZONTALEXTENT, (WPARAM)size.cx, 0L); } //
// Paint the string.
//
ExtTextOut(hDC, (rc.left + 2), wTopText, ETO_OPAQUE | ETO_CLIPPED, &rc, lpszText, len, NULL); if (lpDI->itemState & ODS_FOCUS) DrawFocusRect(hDC,&rc);
bNoReEnter--; }
/****************************************************************************
* SetRangeToTree() * * Function will set the filter tree up according the the subset specified * by the given CStructuraSubset pointer. * * ENTRY: * CStructuralSubset* A NULL object is the equivelent to RF_NONE. * Use of this feature will cause all nodes to be * removed from the filter. * * EXIT: * BOOL - TRUE for success. FALSE for failure! * ****************************************************************************/ BOOL CDefineSS::SetRangeToTree(CStructuralSubset* pSS) { CFolder* pFgt; // pointer to filtered group tree.
UINT i = 0; HASH Hash;
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); if ( pSS ) { if ( pSS->m_dwFlags & SS_ENTIRE_CONTENTS ) { while ( pFgt ) { AddNode2Filter(pFgt); pFgt = pFgt->pNext; } } else { //
// De-select all nodes filter bits and select the proper
// tree nodes based on the hash list!
//
while ( pFgt ) { RemoveNodeFromFilter(pFgt); pFgt = pFgt->pNext; } while ( Hash = pSS->EnumHashes(i++) ) { if ( (pFgt = m_pCollection->m_pCSlt->HashToCFolder(Hash)) ) AddNode2Filter(pFgt); } } return(TRUE); } else { while ( pFgt ) { RemoveNodeFromFilter(pFgt); pFgt = pFgt->pNext; } } return(FALSE); }
/****************************************************************************
* GetRangeFromTree() * * Function will extract a range from the filter LB and return a handle to * the range. * * ENTRY: * sz - Range name. * * EXIT: * ****************************************************************************/ CStructuralSubset* CDefineSS::GetRangeFromTree(LPSTR sz) { CFolder* pFgt; CFolder* pFgtLast; int i = 0; CStructuralSubset* pSS; CExTitle* pExTitle;
if (! (pSS = new CStructuralSubset(sz)) ) return NULL; // Young girls are chaining themselves to the axels of big mac trucks.
// Walk root level nodes and gather up the prefix hashes from each node
// and all it's kids if the filter bit is set.
//
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); while ( pFgt ) { do { pFgtLast = pFgt; if ( pFgt->f_Filter && !pFgt->f_Available && pFgt->f_HasHash ) { pSS->AddHash(pFgt->pExTitle->m_dwHash); //
// Any merged .CHM's ?
//
pExTitle = pFgt->pExTitle->m_pKid; while ( pExTitle ) { pSS->AddHash(pExTitle->m_dwHash); pExTitle = pExTitle->m_pNextKid; } i++; break; } pFgt = pFgt->pKid;
} while ( pFgt );
pFgt = pFgtLast; while ( pFgt && (! (pFgt->pNext)) ) pFgt = pFgt->pParent; if ( pFgt ) pFgt = pFgt->pNext; } // Lastly, setup the range entry and add it to the range list.
//
if (! i ) { delete pSS; return(NULL); } return pSS; }
/*****************************************************************************
* SetSaveStatus() * * If you don't want'em saving then disable the save button! * * ENTRY: * hDlg - Handle to the define contents dialog. * * EXIT: * None. * ****************************************************************************/ void CDefineSS::SetSaveStatus(HWND hDlg) { char sz[MAX_SS_NAME_LEN]; int i; CStructuralSubset* pSS; HWND hWnd = GetDlgItem(hDlg, IDF_SAVE);
GetWindowText(GetDlgItem(hDlg, IDF_SAVE_EC), sz, sizeof(sz)); i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L); pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETITEMDATA,i,0L);
if ( ((pSS->m_dwFlags & SS_READ_ONLY) && (! lstrcmpi(pSS->GetName(), sz))) || (! SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETCOUNT, 0, 0L)) || (! lstrlen(sz)) || !m_bShouldSave ) EnableWindow(hWnd, FALSE); else EnableWindow(hWnd, TRUE); }
/*****************************************************************************
* ShouldSave() * * Alert the user that they may want to save the changes they've made to * the filter. * * ENTRY: * hDlg - Handle to the filter definition dialog. * * EXIT: * INT - IDYES, IDNO or IDCANCEL. 0 if saving is not necessary. * ****************************************************************************/ INT CDefineSS::ShouldSave(HWND hDlg) { char sz[MAX_SS_NAME_LEN];
if ( IsWindowEnabled(GetDlgItem(hDlg, IDF_SAVE)) ) { GetWindowText(GetDlgItem(hDlg, IDF_SAVE_EC), sz, sizeof(sz)); return MsgBox(IDS_SAVE_FILTER, sz, MB_YESNOCANCEL | MB_ICONQUESTION); } return(0); }
/****************************************************************************
* FilterDlgCommand() * * Function handles all WM_COMMAND messages from the filter dialog. * * ENTRY: * hDlg - Handle to the dialog. * wParam - Message dependent. * lParam - Message dependent. * * EXIT: * Returns TRUE is range list boxes need updating. False otherwise. * ***************************************************************************/ BOOL CDefineSS::FilterDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam) { int i, n; CFolder* pFgt; char sz[MAX_SS_NAME_LEN]; static il; static HWND hWndCombo = NULL;
switch (CmdID) { // HACKHACK - this is an invisible button that we use to route double-clicks
// to other controls
case IDOK: { HWND hWndCurrent, hWndFocus; int id = 0; // find out which control we are on
if( (hWndFocus = GetFocus()) ) { hWndCurrent = GetDlgItem(hDlg,IDF_AVAIL); if( hWndFocus == hWndCurrent ) id = IDF_AVAIL; hWndCurrent = GetDlgItem(hDlg,IDF_RANGE); if( hWndFocus == hWndCurrent ) id = IDF_RANGE; hWndCurrent = GetDlgItem(hDlg,IDF_RANGES); if( hWndFocus == hWndCurrent ) id = IDF_RANGES;
SendMessage( hDlg, WM_COMMAND, MAKEWPARAM(id,LBN_DBLCLK), 0L); } return( TRUE ); }
case IDF_SAVE: if ( SaveFilter(hDlg) ) { SetDefaultButton( hDlg, IDCANCEL, TRUE ); i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L); m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L); EnableWindow(GetDlgItem(hDlg, IDF_DELETE), TRUE); m_bShouldSave = FALSE; } else SetFocus(GetDlgItem(hDlg, IDF_RANGES)); break;
case IDCANCEL: // if a combo box is open then close it and don't close the dialog
if( hWndCombo ) { SendMessage( hWndCombo, CB_SHOWDROPDOWN, FALSE, 0L ); return FALSE; } //
// Has the range been modified ? Might it need to be saved.
//
if ( m_bShouldSave ) { i = ShouldSave(hDlg); if ( i == IDYES ) { if (! SaveFilter(hDlg) ) { SetFocus(GetDlgItem(hDlg, IDF_RANGES)); break; } i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L); m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L); m_bShouldSave = FALSE; } else if ( i == IDCANCEL ) break; } EndDialog(hDlg, (INT_PTR)m_pSS); break;
case IDF_DELETE: if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L)) != CB_ERR ) { int n; m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L); if ( MsgBox(IDS_CONFIRM_SSDELETE, m_pSS->GetName(), MB_YESNO | MB_ICONQUESTION) == IDYES ) { if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT, 0, (LPARAM)m_pSS->GetName())) != LB_ERR) SendDlgItemMessage(hDlg, IDF_RANGES, CB_DELETESTRING, i, 0L); m_pCollection->m_pSSList->DeleteSubset(m_pSS, NULL, m_hWndParent); n = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCOUNT, 0, 0L); n--; i = min(n,i); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, i, 0L); i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L); m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L); InitDialog(hDlg, m_pSS->GetName()); m_bShouldSave = FALSE; return(FALSE); } } break;
case IDF_SAVE_EC: switch (CmdCode) { case EN_UPDATE: m_bShouldSave = TRUE; SetSaveStatus(hDlg); SetDefaultButton( hDlg, IDF_SAVE, FALSE ); break;
case EN_CHANGE: m_bShouldSave = TRUE; break; } break;
case IDF_RANGES: switch (CmdCode) { case CBN_DROPDOWN: il = (int)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETCURSEL,0,0L); break;
case CBN_SELCHANGE: i = (int)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETCURSEL,0,0L); SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETLBTEXT,i,(LPARAM)sz); if ( m_bShouldSave ) { n = ShouldSave(hDlg); if ( n == IDCANCEL ) goto cancel_it; else if ( n == IDYES ) { if (! SaveFilter(hDlg) ) goto cancel_it; } //SetDefaultButton( hDlg, IDCANCEL, TRUE );
} i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L); m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L); m_bShouldSave = FALSE; InitDialog(hDlg, sz); return(FALSE); cancel_it: SendDlgItemMessage(hDlg,IDF_RANGES,CB_SETCURSEL,(WPARAM)il,0L); } break;
case IDHELP: break;
case IDF_NEW: m_bShouldSave = TRUE; SetSaveStatus(hDlg); break;
case IDF_REMOVE: n = (int)SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETCOUNT, 0, 0L); for (i = 0; i < n; i++) { if (SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETSEL, i, 0L)) { pFgt=(CFolder*)SendDlgItemMessage(hDlg,IDF_RANGE,LB_GETITEMDATA,i, (LPARAM)0); RemoveNodeFromFilter(pFgt); SendDlgItemMessage(hDlg, IDF_RANGE, LB_SETSEL, 0, (LPARAM)i); m_bShouldSave = TRUE; } } SetFocus(GetDlgItem(hDlg, IDF_RANGE)); return(TRUE); break;
case IDF_ADDALL: //
// Enumerate root level nodes Adding each!
//
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); while ( pFgt ) { AddNode2Filter(pFgt); pFgt = pFgt->pNext; } m_bShouldSave = TRUE; SetFocus(GetDlgItem(hDlg, IDF_RANGE)); return(TRUE); break;
case IDF_ADD: n = (int)SendDlgItemMessage(hDlg, IDF_AVAIL, LB_GETCOUNT, 0, 0L); for (i = 0; i < n; i++) { if (SendDlgItemMessage(hDlg, IDF_AVAIL, LB_GETSEL, i, 0L)) { pFgt=(CFolder*)SendDlgItemMessage(hDlg,IDF_AVAIL,LB_GETITEMDATA,i, (LPARAM)0); AddNode2Filter(pFgt); SendDlgItemMessage(hDlg, IDF_AVAIL, LB_SETSEL, 0, (LPARAM)i); m_bShouldSave = TRUE; } } SetFocus(GetDlgItem(hDlg, IDF_AVAIL)); return(TRUE); break;
case IDF_REMOVEALL: //
// Enumerate root level nodes removing each!
//
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); while ( pFgt ) { RemoveNodeFromFilter(pFgt); pFgt = pFgt->pNext; } m_bShouldSave = TRUE; SetFocus(GetDlgItem(hDlg, IDF_AVAIL)); return(TRUE); break;
case IDF_RANGE: switch (CmdCode) { case LBN_DBLCLK: n = 0; goto expcont; } break;
case IDF_AVAIL: switch (CmdCode) { case LBN_DBLCLK: n = 1; expcont: i = (int)SendDlgItemMessage(hDlg,CmdID,LB_GETCARETINDEX,0,0L); if (i == (int)LB_ERR) break;
pFgt=(CFolder*)SendDlgItemMessage(hDlg,CmdID,LB_GETITEMDATA,i, (LPARAM)0); if ( !pFgt || pFgt == (CFolder*)-1 ) break; //
// giXpos is set in my LB hook proc. If it's != -1 then this
// double click is intended as a collapsing dbl click and giXpos
// will indicate the x position within the LB where the double
// click occured. Sound reasonable ?
//
if ( m_giXpos > 0 ) { int iLevel;
iLevel = m_giXpos / m_giIndentSpacing; while ( (iLevel != pFgt->iLevel) && pFgt->pParent ) pFgt = pFgt->pParent; } ExpandContract(GetDlgItem(hDlg,CmdID), pFgt, -1, n); break;
default: break;
} break; }
switch( CmdCode ) { case CBN_DROPDOWN: hWndCombo = (HWND) lParam; SetDefaultButton( hDlg, IDCANCEL, FALSE ); break;
case CBN_CLOSEUP: hWndCombo = NULL; SetDefaultButton( hDlg, IDCANCEL, FALSE ); break;
}
return(FALSE); }
/*****************************************************************************
* SaveFilter() * * Function saves a filter to the filter list, insuring a read-only filter * is not over-written. * * ENTRY: * hDlg - Handle to the filter definition dialog. * * EXIT: * BOOL - TRUE Indicates the filter was saved. FALSE indicates filter * was not saved. * *****************************************************************************/ BOOL CDefineSS::SaveFilter(HWND hDlg) { char szGivenRN[MAX_SS_NAME_LEN]; int i = 0; CStructuralSubset* pSS = NULL; CStructuralSubset* pSSNew;
GetDlgItemText(hDlg, IDF_SAVE_EC, szGivenRN, sizeof(szGivenRN)); //
// Extract range from the filter LB.
//
if (! (pSSNew = GetRangeFromTree(szGivenRN)) ) return(FALSE); //
// Insure we're not trashing a read only ramge.
//
while ( (pSS = m_pCollection->m_pSSList->GetNextSubset(pSS)) ) { if (! lstrcmpi(pSS->GetName(), pSSNew->GetName()) ) { if ( pSS->m_dwFlags & SS_READ_ONLY ) { MsgBox(IDS_BAD_RANGE_NAME, MB_OK | MB_ICONEXCLAMATION); return(FALSE); } // Sure you want to over-write the existing rnage ?
//
if ( MsgBox(IDS_OVERWRITE, MB_YESNO | MB_ICONQUESTION) == IDNO ) return(FALSE); if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT, 0, (LPARAM)pSS->GetName())) != LB_ERR) SendDlgItemMessage(hDlg, IDF_RANGES, CB_DELETESTRING, i, 0L); m_pCollection->m_pSSList->DeleteSubset(pSS, pSSNew, m_hWndParent); break; } } // Add new subset to the list and update UI...
//
m_pCollection->m_pSSList->AddSubset(pSSNew, m_hWndParent); SendDlgItemMessage(hDlg, IDF_RANGES, CB_INSERTSTRING, 0, (LPARAM)pSSNew->GetName()); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETITEMDATA, 0, (LPARAM)pSSNew); SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, 0, 0L); EnableWindow(GetDlgItem(hDlg,IDF_SAVE), FALSE); return(TRUE); }
/*****************************************************************************
* RemoveNodeFromFilter() * * Function removes the node and all it's kids from the filter. * * ENTRY: * pFgt - Poiner to the node to be removed. * * EXIT: * None. * *****************************************************************************/ void CDefineSS::RemoveNodeFromFilter(CFolder* pFgti) { CFolder* pFgt; CFolder* pFgtLast;
// First, de-select the node and any children of the node taking care
// to set the f_Available bit from each!
//
pFgt = pFgti; if ( pFgt->pKid ) { while ( pFgt ) { do { pFgt->f_Available = 1; pFgt->f_Filter = 0; pFgtLast = pFgt; pFgt = pFgt->pKid;
} while ( pFgt ); pFgt = pFgtLast; while ( pFgt && (! (pFgt->pNext)) ) { if ( pFgt->pParent != pFgti ) pFgt = pFgt->pParent; else break; } if ( pFgt ) pFgt = pFgt->pNext; } } // Next, assure any parents of the node are marked as available. We also
// have to take care to see that a parent who has no children who are
// part of the filter are removed from the filter!
//
pFgt = pFgti; pFgt->f_Filter = 0; pFgt->f_Available = 1;
while ( pFgt = pFgt->pParent ) { pFgt->f_Available = 1; SetFilterStatus(pFgt); } }
/*****************************************************************************
* SetFilterStatus() * * If ALL children of the given node are marked as available, that nodes * filter bit will be set to zero. * * ENTRY: * pFgt - Pointer to the node to start from. * * EXIT: * ****************************************************************************/ void CDefineSS::SetFilterStatus(CFolder* pFgt) { CFolder* pFgtl = pFgt->pKid; CFolder* pFgtLast;
while ( pFgtl ) { do { if (! pFgtl->f_Available ) return; pFgtLast = pFgtl; pFgtl = pFgtl->pKid; } while ( pFgtl ); pFgtl = pFgtLast; while ( pFgtl && (! (pFgtl->pNext)) && (pFgtl->pParent != pFgt) ) pFgtl = pFgtl->pParent; if ( pFgtl ) pFgtl = pFgtl->pNext; } pFgt->f_Filter = 0; }
/*****************************************************************************
* AddNode2Filter() * * Function adds a node to the filter assuring that necessary parents are * added, and necessary nodes are removed from the available listbox. * * ENTRY: * pFgti = Node to be added. * * EXIT: * None. * *****************************************************************************/ void CDefineSS::AddNode2Filter(CFolder* pFgti) { CFolder* pFgt; CFolder* pFgtLast;
// First, select the node and any children of the node taking care
// to remove the f_Available bit from each!
//
pFgt = pFgti; while ( pFgt ) { do { pFgt->f_Available = 0; pFgt->f_Filter = 1;
pFgtLast = pFgt; pFgt = pFgt->pKid;
} while ( pFgt ); pFgt = pFgtLast; if ( pFgt == pFgti ) break; while ( pFgt && (! (pFgt->pNext)) ) { if ( pFgt->pParent != pFgti ) pFgt = pFgt->pParent; else break; } if ( pFgt ) pFgt = pFgt->pNext; } // Next, assure parents are selected.
//
pFgt = pFgti; if ( pFgt->pParent ) { while ( pFgt = pFgt->pParent ) { pFgt->f_Filter = 1; pFgt->f_F_Open = 1; SetAvailableStatus(pFgt); // Should it still be available ?
} } }
/*****************************************************************************
* SetAvailabilityStatus() * * If ALL children of the given node are selected as part of a filter, that * nodes availability bit will be set to zero. * * ENTRY: * pFgt - Pointer to the node to start from. * * EXIT: * ****************************************************************************/ void CDefineSS::SetAvailableStatus(CFolder* pFgt) { CFolder* pFgtl = pFgt->pKid; CFolder* pFgtLast;
while ( pFgtl ) { do { if (! pFgtl->f_Filter ) return; pFgtLast = pFgtl; pFgtl = pFgtl->pKid; } while ( pFgtl ); pFgtl = pFgtLast; while ( pFgtl && (! (pFgtl->pNext)) && (pFgtl->pParent != pFgt) ) pFgtl = pFgtl->pParent; if ( pFgtl ) pFgtl = pFgtl->pNext; } pFgt->f_Available = 0; }
/******************************************************************************
* ExpandContract() * * Function set's appropiate bits in the appropiate nodes to cause * a parent node to expand or contract when FillRangeTree() is called. * * ENTRY: * hwndLB - Handle to the listbox that contains the node were operating on. * * pFgt - Pointer to the node were expanding or contracting. * * sel - Identifies action: TRUE for Expansion * FALSE for Contraction * -1 for double-click which really means that * we toggle the current state for the appropiate * LB identified by the "which" arg. * * which - Which ListBox are we working with: TRUE == Available LB. * FALSE == Range LB. * * EXIT: * WORD - Returns the AX from FillRangeTree which happens to be the number * of items placed in the LB. * *****************************************************************************/ WORD CDefineSS::ExpandContract(HWND hwndLB, CFolder* pFgt, int sel, BOOL which) { if (sel != 0 && sel != 1) { if (! pFgt->pKid ) return(0); //
// This is the double click case.
//
if ( which ) { if( pFgt->f_A_Open ) pFgt->f_A_Open = FALSE; else pFgt->f_A_Open = TRUE; } else pFgt->f_F_Open = !pFgt->f_F_Open; } else { // This is the +/- case
//
// Contraction works a little differently than expansion.
// For contraction, if the selected node is not expanded, we close
// it's parent. If it is expanded, we close it.
//
if ( !sel ) // if we're doing contraction...
{ if ( ! (which ? pFgt->f_A_Open : pFgt->f_F_Open) ) // if node closed...
{ if ( pFgt->pParent ) pFgt = pFgt->pParent; } }
if (! pFgt->pKid && pFgt->pParent) pFgt = pFgt->pParent;
if ( which ) pFgt->f_A_Open = sel; else pFgt->f_F_Open = sel; } return (WORD)FillFilterTree(hwndLB, which, sel); }
/*****************************************************************************
* FillFilterTree() * * Function actually makes the send message calls to cause a repaint of * the listbox identified by hwndLB. * * ENTRY: * hwndLB - Identifies the listbox were working with (it's handle) * fAvailable - Which ListBox are we working with: TRUE == Available LB. * FALSE == Range LB. * fScrollup - If TRUE and a parents children will appear off the bottom * of the LB we'll scroll the parent to the top of the LB. * * EXIT: * UINT - Returns the number of items placed in the LB. * *****************************************************************************/ UINT CDefineSS::FillFilterTree(HWND hwndLB, BOOL fAvailable, BOOL fScrollup) { UINT uiRet = 0; int n, nVis, top, caret; CFolder* pFgtTop, *pFgtCaret, *pFgt, *plFgt; RECT rc;
/*
* Compute the number of visible lines, get the top and caret indicies. */ GetClientRect(hwndLB,&rc); n = (int)SendMessage(hwndLB,LB_GETITEMHEIGHT,0,0L); nVis = rc.bottom / n; SendMessage(hwndLB,WM_SETREDRAW,FALSE,0L); // Don't re-paint!
caret = (int)SendMessage(hwndLB,LB_GETCARETINDEX,0,0L); top = (int)SendMessage(hwndLB,LB_GETTOPINDEX,0,0L); /*
* Get the items living at the top and the caret position of the listbox. */ if (top == (int)LB_ERR) pFgtTop = NULL; else { if ( (pFgtTop=(CFolder*)SendMessage(hwndLB, LB_GETITEMDATA, top, (LPARAM)0)) == (CFolder*)LB_ERR ) pFgtTop = NULL; }
if (caret == (int)LB_ERR) pFgtCaret = NULL; else { if ( (pFgtCaret=(CFolder*)SendMessage(hwndLB, LB_GETITEMDATA, caret, (LPARAM)0)) == (CFolder*)LB_ERR ) pFgtCaret = NULL; } /*
* If the top entry is a child and it's not expanded, set it's parent * as the top. ie it's been collapsed. */ if ( pFgtTop && pFgtTop->pParent && !EXPANDED(fAvailable, pFgtTop->pParent) ) pFgtTop = pFgtTop->pParent; /*
* If the caret position is on a child and it's not expanded, set it's * parent as the caret position. ie it's been collapsed. */ if ( pFgtCaret && pFgtCaret->pParent && !EXPANDED(fAvailable, pFgtCaret->pParent) ) pFgtCaret = pFgtCaret->pParent; /*
* Insure we have not set the top or caret position to a non selected * node. */ if ( pFgtTop && !PRESENT(fAvailable,pFgtTop) ) { plFgt = pFgtTop; do { do { pFgtTop = pFgtTop->pNext; } while ( pFgtTop && !PRESENT(fAvailable,pFgtTop) );
if (! pFgtTop ) { pFgtTop = plFgt->pParent; plFgt = pFgtTop; } else break; } while ( pFgtTop ); } if ( pFgtCaret && !PRESENT(fAvailable,pFgtCaret) ) { plFgt = pFgtCaret; do { do { pFgtCaret = pFgtCaret->pNext; } while ( pFgtCaret && !PRESENT(fAvailable,pFgtCaret) );
if (! pFgtCaret ) { pFgtCaret = plFgt->pParent; plFgt = pFgtCaret; } else break; } while ( pFgtCaret ); } SendMessage(hwndLB,LB_RESETCONTENT,FALSE,0L); /*
* Reset horizontal extent. */ SendMessage(hwndLB, LB_SETHORIZONTALEXTENT, 0, 0L); /*
* Now, add the appropiate items to the list box. */ if ( fAvailable ) uiRet = AvailableWalk(hwndLB); else uiRet = FilteredWalk(hwndLB); /*
* Lastly, insure a parent is scrolled to the top of the LB if it's kids * have run off of the bottom of the LB. */ if (pFgtTop) top = (int)SendMessage(hwndLB,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtTop);
if (pFgtCaret) caret = (int)SendMessage(hwndLB,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtCaret);
if (!pFgtTop || top == (int)LB_ERR) top = 0;
if (!pFgtCaret || caret == (int)LB_ERR) caret = 0;
if ( fScrollup && pFgtCaret && pFgtCaret->pKid ) { if (caret < top) top = caret;
for (pFgt = pFgtCaret->pKid, n = 1; pFgt; pFgt = pFgt->pNext) ++n;
if (n >= nVis) top = caret; else if (caret + n > top + nVis) top = caret - nVis + n; } SendMessage(hwndLB, LB_SETTOPINDEX, top, 0L); SendMessage(hwndLB, LB_SETCARETINDEX, caret, 0L); SendMessage(hwndLB, LB_SETSEL, TRUE, MAKELPARAM(caret,0));
SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hwndLB, NULL, TRUE); return(uiRet); }
/*****************************************************************************
* FilteredWalk() * * Helper function called only from FillFilterTree(). This bit of code walks * the filter group tree and adds the selected nodes to the listbox given. * * ENTRY: * hwndLB - Handle to the list box to which items are to be added. * * EXIT: * uint - Returns the number of items added to the listbox. * ****************************************************************************/ UINT CDefineSS::FilteredWalk(HWND hwndLB) { CFolder* pFgt; CFolder* pFgtLast; UINT i = 0;
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); /*
* Ok, now we actually do all the walking of the filter linked list to * re-generate the filter listbox contnets. This must be done in the * order in which the items appear in the LB. ie. Depthwise. */ while ( pFgt ) { do { if ( pFgt->f_Filter && !pFgt->f_IsOrphan ) { SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)pFgt); i++; } pFgtLast = pFgt; if ( pFgt->f_F_Open ) pFgt = pFgt->pKid; else break; } while ( pFgt ); pFgt = pFgtLast; while ( pFgt && (! (pFgt->pNext)) ) pFgt = pFgt->pParent; if ( pFgt ) pFgt = pFgt->pNext; } return(i); }
/*****************************************************************************
* AvailableWalk() * * Helper function called only from FillFilterTree(). This bit of code walks * the filter group tree and adds the selected nodes to the listbox given. * * ENTRY: * hwndLB - Handle to the list box to which items are to be added. * * EXIT: * uint - Returns the number of items added to the listbox. * ****************************************************************************/ UINT CDefineSS::AvailableWalk(HWND hwndLB) { CFolder* pFgt; CFolder* pFgtLast; UINT i = 0;
pFgt = m_pCollection->m_Collection.GetVisableRootFolder(); /*
* Ok, now we actually do all the walking of the filter linked list to * re-generate the filter listbox contnets. This must be done in the * order in which the items appear in the LB. ie. Depthwise. */ while ( pFgt ) { do { if ( pFgt->f_Available && !pFgt->f_IsOrphan ) { SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)pFgt); i++; } pFgtLast = pFgt; if ( pFgt->f_A_Open ) pFgt = pFgt->pKid; else break; } while ( pFgt ); pFgt = pFgtLast; while ( pFgt && (! (pFgt->pNext)) ) pFgt = pFgt->pParent; if ( pFgt ) pFgt = pFgt->pNext; } return(i); }
//
// Change a dialog's default push button
//
BOOL CDefineSS::SetDefaultButton( HWND hDlg, int iID, BOOL fFocus ) { BOOL bReturn = FALSE;
if( hDlg ) {
// Get the current default push button and reset it.
ResetDefaultButton( hDlg );
// Update the default push button's control ID.
SendMessage( hDlg, DM_SETDEFID, (WPARAM) iID, 0L );
// Set the new style.
bReturn = (BOOL) SendDlgItemMessage( hDlg, iID, BM_SETSTYLE, (WPARAM) BS_DEFPUSHBUTTON, (LPARAM) TRUE );
// Set the focus to the new default push button.
if( fFocus ) bReturn &= (SetFocus( GetDlgItem( hDlg, iID ) ) != NULL);
} return( bReturn ); }
//
// Clear the current default button status from the default push button
//
void CDefineSS::ResetDefaultButton( HWND hDlg ) { DWORD dwResult;
if( hDlg ) {
// Get the current default push button.
dwResult = (DWORD) SendMessage( hDlg, DM_GETDEFID, 0, 0L );
// Reset the current default push button to a regular button.
if( HIWORD(dwResult) == DC_HASDEFID ) SendDlgItemMessage( hDlg, LOWORD(dwResult), BM_SETSTYLE, (WPARAM) BS_PUSHBUTTON, (LPARAM) TRUE );
}
return; }
|