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

2211 lines
64 KiB

  1. /*****************************************************************************
  2. * Subset.cpp
  3. *
  4. * Copyright (C) Microsoft, 1989-1998
  5. * Feb 22, 1998
  6. *
  7. * Modification History:
  8. *
  9. * Ported to hhctrl.ocx from the old B2 code base.
  10. *
  11. *****************************************************************************/
  12. #include "header.h"
  13. #include "subset.h"
  14. #include "resource.h"
  15. #include "toc.h"
  16. #include "cdefinss.h"
  17. #include "verdef.h"
  18. #include "secwin.h"
  19. #define CmdID LOWORD(wParam)
  20. #define CmdCode HIWORD(wParam)
  21. #define CmdHwnd (HWND)lParam
  22. /*
  23. * Defines, the EXPANDED define aids in intrepreting the proper bit in the
  24. * FGT data structure depending on which LB we're operating on.
  25. */
  26. #define EXPANDED(lb_id, ds) ((lb_id) ? ds->f_A_Open : ds->f_F_Open)
  27. #define PRESENT(lb_id, ds) ((lb_id) ? ds->f_Available : ds->f_Filter)
  28. // declare a static this pointer for our window procedures.
  29. //
  30. CDefineSS* CDefineSS::m_pThis;
  31. //********************************************************************************
  32. //
  33. // CStructuralSubset Implementation - This is object representation of a subset.
  34. //
  35. //********************************************************************************
  36. CSSList::CSSList()
  37. {
  38. m_iSubSetCount = 0;
  39. m_pHeadSubSets = m_pFTS_SS = m_pF1_SS = m_pTOC_SS = m_pNew_SS = m_pEC_SS = NULL;
  40. }
  41. CSSList::~CSSList()
  42. {
  43. CStructuralSubset *pSS, *pSSNext;
  44. pSS = m_pHeadSubSets;
  45. while ( pSS )
  46. {
  47. pSSNext = pSS->m_pNext;
  48. delete pSS;
  49. pSS = pSSNext;
  50. }
  51. }
  52. CStructuralSubset* CSSList::GetSubset(PSTR pszSSName)
  53. {
  54. CStructuralSubset *pSS = m_pHeadSubSets;
  55. while ( pSS )
  56. {
  57. if (! lstrcmpi(pSS->GetName(), pszSSName) )
  58. return pSS;
  59. pSS = pSS->m_pNext;
  60. }
  61. return NULL;
  62. }
  63. void CSSList::DeleteSubset(CStructuralSubset* pSS, CStructuralSubset* pSSNew, /* == NULL */ HWND hWndUI /* == NULL */)
  64. {
  65. CStructuralSubset *pSSCurrCB, *pSSl = m_pHeadSubSets;
  66. TCHAR szSel[MAX_SS_NAME_LEN];
  67. HWND hWndCB;
  68. INT_PTR i;
  69. CHHWinType* phh;
  70. if (! pSSNew )
  71. pSSNew = m_pEC_SS;
  72. if ( pSS->m_dwFlags & SS_READ_ONLY )
  73. return;
  74. if ( pSS == m_pFTS_SS )
  75. m_pFTS_SS = pSSNew;
  76. if ( pSS == m_pF1_SS )
  77. m_pF1_SS = pSSNew;
  78. if ( pSS == m_pTOC_SS )
  79. m_pTOC_SS = pSSNew;
  80. //
  81. // If we're given an hwnd, update the combo-box UI.
  82. //
  83. if ( hWndUI && (hWndCB = GetDlgItem(hWndUI, IDC_SS_PICKER)) )
  84. {
  85. //
  86. // Get the current CB selection and see if it's the one we're deleting ?
  87. //
  88. if ( ((i = SendMessage(hWndCB, CB_GETCURSEL, 0, 0L)) != -1) )
  89. {
  90. GetDlgItemText(hWndUI, IDC_SS_PICKER, szSel, sizeof(szSel));
  91. pSSCurrCB = GetSubset(szSel);
  92. if ( pSSCurrCB == pSS ) // Yep, we're deleting the current one, select the new one.
  93. {
  94. SendMessage(hWndCB, CB_SELECTSTRING, -1, (LPARAM)pSSNew->GetName());
  95. if ( (phh = FindWindowIndex(hWndUI)) )
  96. {
  97. pSSNew->SelectAsTOCSubset(phh->m_phmData->m_pTitleCollection);
  98. phh->UpdateInformationTypes(); // This call re-draws the TOC.
  99. }
  100. }
  101. }
  102. if ( lstrcmpi(pSS->GetName(), pSSNew->GetName()) )
  103. {
  104. if ( (i = SendMessage(hWndCB, CB_FINDSTRING, -1, (LPARAM)pSS->GetName())) != -1 )
  105. SendMessage(hWndCB, CB_DELETESTRING, i, 0L);
  106. }
  107. }
  108. //
  109. // Take the delete victum out of the linked list.
  110. //
  111. while ( pSSl )
  112. {
  113. if ( pSSl->m_pNext == pSS )
  114. {
  115. pSSl->m_pNext = pSS->m_pNext;
  116. delete pSS;
  117. break;
  118. }
  119. pSSl = pSSl->m_pNext;
  120. }
  121. m_iSubSetCount--;
  122. }
  123. HRESULT CSSList::PersistSubsets(CExCollection* pCollection)
  124. {
  125. LPCSTR lpszFQSSStore;
  126. HANDLE hFile;
  127. SSHEADER ssHeader;
  128. CStructuralSubset* pSS;
  129. CStructuralSubset* pSSCurr = NULL;
  130. PSS pSSFile = NULL;
  131. unsigned long ulCnt;
  132. int iSSSize;
  133. int i = 0;
  134. if (! (pSS = m_pHeadSubSets) )
  135. return S_OK;
  136. //
  137. // Count'em
  138. //
  139. do
  140. {
  141. if ( pSS->IsTOC() )
  142. pSSCurr = pSS;
  143. if ( !pSS->IsEntire() && !pSS->IsEmpty() && !pSS->IsReadOnly() )
  144. i++;
  145. } while ( (pSS = GetNextSubset(pSS)) );
  146. //
  147. // Prepare a file.
  148. //
  149. if (! (lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathnameByLanguage()) )
  150. return E_FAIL;
  151. hFile = CreateFile(lpszFQSSStore, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
  152. if ( hFile == INVALID_HANDLE_VALUE )
  153. return E_FAIL;
  154. //
  155. // Fill in the header, write out the header.
  156. //
  157. // Need to store the persisted subset in the header since it may be a predefine.
  158. //
  159. ssHeader.dwSig = SS_FILE_SIGNATURE;
  160. ssHeader.dwVer = (VER_PRODUCTVERSION_DW & 0x0000);
  161. ssHeader.iSSCount = i;
  162. ssHeader.dwFlags = 0;
  163. if ( pSSCurr )
  164. lstrcpy(ssHeader.lpszCurrentSSName, pSSCurr->GetName());
  165. if (! WriteFile(hFile, &ssHeader, sizeof(SSHEADER), &ulCnt, NULL) )
  166. {
  167. MsgBox(IDS_PERSIST_SUBSET_ERR, MB_OK | MB_ICONHAND);
  168. return E_FAIL;
  169. }
  170. //
  171. // Write out the subsets.
  172. //
  173. pSS = m_pHeadSubSets;
  174. do
  175. {
  176. if ( pSS->IsEntire() || pSS->IsEmpty() || pSS->IsReadOnly() )
  177. continue;
  178. int iHashCnt = pSS->GetHashCount();
  179. iSSSize = (sizeof(SS) + ((iHashCnt - 1) * sizeof(DWORD)));
  180. if ( (pSSFile = (PSS)lcReAlloc(pSSFile, iSSSize)) )
  181. {
  182. pSSFile->iHashCount = iHashCnt;
  183. lstrcpy(pSSFile->lpszSSName, pSS->GetName());
  184. lstrcpy(pSSFile->lpszSSID, pSS->GetID());
  185. pSSFile->dwFlags = pSS->m_dwFlags;
  186. while ( --iHashCnt >= 0)
  187. pSSFile->dwHashes[iHashCnt] = pSS->EnumHashes(iHashCnt);
  188. if (! WriteFile(hFile, pSSFile, iSSSize, &ulCnt, NULL) )
  189. {
  190. MsgBox(IDS_PERSIST_SUBSET_ERR, MB_OK | MB_ICONHAND);
  191. lcFree(pSSFile);
  192. CloseHandle(hFile);
  193. return E_FAIL;
  194. }
  195. }
  196. } while ( (pSS = GetNextSubset(pSS)) );
  197. lcFree(pSSFile);
  198. CloseHandle(hFile);
  199. return S_OK;
  200. }
  201. HRESULT CSSList::RestoreSubsets(CExCollection* pCollection, PSTR pszRestoreSS)
  202. {
  203. LPCSTR lpszFQSSStore;
  204. HANDLE hFile;
  205. SSHEADER ssHeader;
  206. PSS pSSFile;
  207. CStructuralSubset* pSS;
  208. unsigned long ulHashCnt, ulRead;
  209. HRESULT hr = E_FAIL;
  210. if (! (pSSFile = (PSS)lcMalloc(sizeof(SS) + sizeof(DWORD) * 50)) )
  211. return hr;
  212. lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathnameByLanguage();
  213. hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  214. if ( hFile == INVALID_HANDLE_VALUE)
  215. {
  216. lpszFQSSStore = pCollection->GetUserCHSLocalStoragePathname();
  217. hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  218. if ( hFile == INVALID_HANDLE_VALUE)
  219. {
  220. lpszFQSSStore = pCollection->GetLocalStoragePathname(".chs");
  221. hFile = CreateFile(lpszFQSSStore, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  222. if ( hFile == INVALID_HANDLE_VALUE )
  223. {
  224. lcFree(pSSFile);
  225. return hr;
  226. }
  227. }
  228. }
  229. //
  230. // Read the header.
  231. //
  232. if (! ReadFile(hFile, &ssHeader, sizeof(SSHEADER), &ulRead, NULL) )
  233. goto crap_out;
  234. if ( ssHeader.dwSig != SS_FILE_SIGNATURE )
  235. goto crap_out;
  236. //
  237. // Get the subsets.
  238. //
  239. while ( ssHeader.iSSCount-- )
  240. {
  241. if (! ReadFile(hFile, &ulHashCnt, sizeof(int), &ulRead, NULL) )
  242. goto crap_out;
  243. if ( ulHashCnt > 51 )
  244. {
  245. if (! (pSSFile = (PSS)lcReAlloc(pSSFile, sizeof(SS) + (sizeof(DWORD) * ulHashCnt))) )
  246. goto crap_out;
  247. }
  248. pSSFile->iHashCount = ulHashCnt;
  249. unsigned long ulAmt = ((sizeof(SS) - sizeof(int)) + (sizeof(DWORD) * (ulHashCnt - 1)));
  250. if (! ReadFile(hFile, (((BYTE*)pSSFile) + sizeof(int)), ulAmt, &ulRead, NULL) )
  251. goto crap_out;
  252. //
  253. // Now create a CStructuralSubset from the data.
  254. //
  255. pSS = new CStructuralSubset(pSSFile->lpszSSName);
  256. pSS->m_dwFlags = pSSFile->dwFlags;
  257. pSS->m_dwFlags &= ~(SS_FTS | SS_TOC | SS_F1); // Insure selection bits are reset.
  258. lstrcpy(pSS->m_szSSID, pSSFile->lpszSSID);
  259. while ( ulHashCnt )
  260. pSS->AddHash(pSSFile->dwHashes[--ulHashCnt]);
  261. //
  262. // Add the subset to the list appropiatly.
  263. //
  264. AddSubset(pSS);
  265. if (! lstrcmpi(ssHeader.lpszCurrentSSName, pSS->GetName() ) )
  266. {
  267. SetFTS(pSS);
  268. SetTOC(pSS);
  269. SetF1(pSS);
  270. }
  271. }
  272. if ( pszRestoreSS )
  273. lstrcpy(pszRestoreSS, ssHeader.lpszCurrentSSName);
  274. hr = S_OK;
  275. crap_out:
  276. lcFree(pSSFile);
  277. CloseHandle(hFile);
  278. return hr;
  279. }
  280. HRESULT CSSList::ReadPreDefinedSubsets(CExCollection* pCollection, PSTR pszRestoreSS)
  281. {
  282. SSHEADER ssHeader;
  283. PSS pSSFile;
  284. CStructuralSubset* pSS;
  285. CSubFileSystem* pSubFS;
  286. unsigned long ulHashCnt, ulRead;
  287. HRESULT hr = E_FAIL;
  288. if (! (pSSFile = (PSS)lcMalloc(sizeof(SS) + sizeof(DWORD) * 50)) )
  289. return hr;
  290. if (! pCollection || !pCollection->GetMasterTitle() )
  291. return hr;
  292. pSubFS = new CSubFileSystem(pCollection->GetMasterTitle()->GetTitleIdxFileSystem());
  293. if ( !SUCCEEDED(pSubFS->OpenSub("predef.chs")) )
  294. goto crap_out;
  295. //
  296. // Read the header.
  297. //
  298. if ( !SUCCEEDED(pSubFS->ReadSub(&ssHeader, sizeof(SSHEADER), &ulRead)) )
  299. goto crap_out;
  300. if ( ssHeader.dwSig != SS_FILE_SIGNATURE )
  301. goto crap_out;
  302. //
  303. // Get the subsets.
  304. //
  305. while ( ssHeader.iSSCount-- )
  306. {
  307. if ( !SUCCEEDED(pSubFS->ReadSub(&ulHashCnt, sizeof(int), &ulRead)) )
  308. goto crap_out;
  309. if ( ulHashCnt > 51 )
  310. {
  311. if (! (pSSFile = (PSS)lcReAlloc(pSSFile, sizeof(SS) + (sizeof(DWORD) * ulHashCnt))) )
  312. goto crap_out;
  313. }
  314. pSSFile->iHashCount = ulHashCnt;
  315. unsigned long ulAmt = ((sizeof(SS) - sizeof(int)) + (sizeof(DWORD) * (ulHashCnt - 1)));
  316. if ( !SUCCEEDED(pSubFS->ReadSub((((BYTE*)pSSFile) + sizeof(int)), ulAmt, &ulRead)) )
  317. goto crap_out;
  318. //
  319. // Now create a CStructuralSubset from the data.
  320. //
  321. pSS = new CStructuralSubset(pSSFile->lpszSSName);
  322. pSS->m_dwFlags = pSSFile->dwFlags;
  323. pSS->m_dwFlags &= ~(SS_FTS | SS_TOC | SS_F1); // Insure selection bits are reset.
  324. pSS->m_dwFlags |= SS_READ_ONLY;
  325. lstrcpy(pSS->m_szSSID, pSSFile->lpszSSID);
  326. while ( ulHashCnt )
  327. pSS->AddHash(pSSFile->dwHashes[--ulHashCnt]);
  328. //
  329. // Add the subset to the list appropiatly.
  330. //
  331. AddSubset(pSS);
  332. if (! lstrcmpi(pszRestoreSS, pSS->GetName() ) )
  333. {
  334. SetFTS(pSS);
  335. SetTOC(pSS);
  336. SetF1(pSS);
  337. }
  338. }
  339. hr = S_OK;
  340. crap_out:
  341. lcFree(pSSFile);
  342. delete pSubFS;
  343. return hr;
  344. }
  345. HRESULT CSSList::AddSubset(CStructuralSubset* pSS, HWND hWndUI /* == NULL */)
  346. {
  347. CStructuralSubset *pSSl;
  348. HWND hWndCB;
  349. if (! m_pHeadSubSets )
  350. m_pHeadSubSets = pSS;
  351. else
  352. {
  353. pSSl = m_pHeadSubSets;
  354. while ( pSSl->m_pNext )
  355. pSSl = pSSl->m_pNext;
  356. pSSl->m_pNext = pSS;
  357. pSS->m_pNext = NULL;
  358. }
  359. m_iSubSetCount++;
  360. if ( hWndUI && (hWndCB = GetDlgItem(hWndUI, IDC_SS_PICKER)) )
  361. {
  362. if ( SendMessage(hWndCB, CB_FINDSTRING, -1, (LPARAM)pSS->GetName()) == -1 )
  363. SendMessage(hWndCB, CB_ADDSTRING, 0, (LPARAM)pSS->GetName());
  364. }
  365. return S_OK;
  366. }
  367. void CSSList::Set(CStructuralSubset* pSSNew, CStructuralSubset** pSSOld, DWORD dwFlags)
  368. {
  369. if (! pSSNew )
  370. return;
  371. pSSNew->m_dwFlags |= dwFlags;
  372. if ( *pSSOld && (pSSNew != *pSSOld) )
  373. (*pSSOld)->m_dwFlags &= ~dwFlags;
  374. *pSSOld = pSSNew;
  375. }
  376. //********************************************************************************
  377. //
  378. // CStructuralSubset Implementation - This is object representation of a subset.
  379. //
  380. //********************************************************************************
  381. CStructuralSubset::CStructuralSubset(PCSTR pszSubSetName)
  382. {
  383. TCHAR* psz;
  384. int i = 0;
  385. m_szSSID[0] = '\0';
  386. if ( pszSubSetName )
  387. {
  388. if ( (psz = StrChr(pszSubSetName, '|')) ) // If the subset name contains an identifier, process it.
  389. {
  390. psz = AnsiNext(psz);
  391. lstrcpyn(m_szSubSetName, psz, MAX_SS_NAME_LEN);
  392. while ( pszSubSetName[i] != '|' && (i < MAX_SS_NAME_LEN) )
  393. {
  394. m_szSSID[i] = pszSubSetName[i];
  395. i++;
  396. }
  397. m_szSSID[i] = '\0'; // terminate.
  398. }
  399. else
  400. lstrcpyn(m_szSubSetName, pszSubSetName, MAX_SS_NAME_LEN);
  401. }
  402. else
  403. {
  404. m_szSubSetName[0] = '\0';
  405. m_szSSID[0] = '\0';
  406. }
  407. m_pdwHashes = NULL;
  408. m_iAllocatedCount = m_iHashCount = 0;
  409. m_dwFlags = 0;
  410. m_pNext = NULL;
  411. }
  412. CStructuralSubset::~CStructuralSubset()
  413. {
  414. if ( m_pdwHashes )
  415. lcFree(m_pdwHashes);
  416. }
  417. HASH CStructuralSubset::EnumHashes(int pos)
  418. {
  419. if ( !m_iHashCount || (pos >= m_iHashCount) || (pos < 0) )
  420. return 0;
  421. return m_pdwHashes[pos];
  422. }
  423. void CStructuralSubset::AddHash(DWORD dwHash)
  424. {
  425. if ( (m_iHashCount && (!(m_iHashCount % 12))) || (m_iAllocatedCount == 0) )
  426. {
  427. m_iAllocatedCount += 12;
  428. m_pdwHashes = (HASH*)lcReAlloc(m_pdwHashes, sizeof(HASH) * m_iAllocatedCount);
  429. }
  430. m_pdwHashes[m_iHashCount] = dwHash;
  431. m_iHashCount++;
  432. }
  433. BOOL CStructuralSubset::IsTitleInSubset(CExTitle* pTitle)
  434. {
  435. int i;
  436. for (i = 0; i < m_iHashCount; i++)
  437. {
  438. if ( m_pdwHashes[i] == pTitle->m_dwHash )
  439. return TRUE;
  440. }
  441. return FALSE;
  442. }
  443. //
  444. // Function selects the subset as the current TOC filter by setting the f_IsVisable bit accordingly.
  445. // NOTE: we don't bother selecting the bits for entire contents, this is special cased for performance reasons.
  446. //
  447. void CStructuralSubset::SelectAsTOCSubset(CExCollection* pCollection)
  448. {
  449. CFolder* pFgt; // pointer to filtered group tree.
  450. UINT i = 0;
  451. HASH Hash;
  452. if ( IsEntire() || IsEmpty() )
  453. return;
  454. pFgt = pCollection->m_Collection.GetVisableRootFolder();
  455. //
  456. // De-select all node's filter bits and select the proper
  457. // tree nodes based on the hash list!
  458. //
  459. while ( pFgt )
  460. {
  461. MarkNode(pFgt, 0); // Remove nodes by marking as not visable. // RemoveNodeFromFilter(pFgt);
  462. pFgt = pFgt->pNext;
  463. }
  464. while ( Hash = EnumHashes(i++) )
  465. {
  466. if ( (pFgt = pCollection->m_pCSlt->HashToCFolder(Hash)) )
  467. MarkNode(pFgt, 1); // Add nodes by marking as "visable". // AddNode2Filter(pFgt);
  468. }
  469. }
  470. void CStructuralSubset::MarkNode(CFolder* pFgti, BOOL bVisable)
  471. {
  472. CFolder* pFgt;
  473. CFolder* pFgtLast;
  474. // First, mark the node and any children of the node.
  475. //
  476. pFgt = pFgti;
  477. if ( pFgt->pKid )
  478. {
  479. while ( pFgt )
  480. {
  481. do
  482. {
  483. pFgt->f_IsVisable = bVisable;
  484. pFgtLast = pFgt;
  485. pFgt = pFgt->pKid;
  486. } while ( pFgt );
  487. pFgt = pFgtLast;
  488. while ( pFgt && (! (pFgt->pNext)) )
  489. {
  490. if ( pFgt->pParent != pFgti )
  491. pFgt = pFgt->pParent;
  492. else
  493. break;
  494. }
  495. if ( pFgt )
  496. pFgt = pFgt->pNext;
  497. }
  498. }
  499. // Next, assure any parents of the node are properly marked.
  500. //
  501. pFgt = pFgti;
  502. pFgt->f_IsVisable = bVisable;
  503. while ( (pFgt = pFgt->pParent) )
  504. pFgt->f_IsVisable = bVisable;
  505. }
  506. //****************************************************************************
  507. //
  508. // CDefineSS Implementation - This is the guy that does all the UI.
  509. //
  510. //*****************************************************************************
  511. CDefineSS::CDefineSS(CExCollection* pCollection)
  512. {
  513. m_bShouldSave = FALSE;
  514. m_pSS = NULL;
  515. m_pCollection = pCollection;
  516. m_hIL = 0;
  517. m_hWndParent = 0;
  518. }
  519. CDefineSS::~CDefineSS()
  520. {
  521. }
  522. /****************************************************************************
  523. * IDefineFilter()
  524. *
  525. * Internal entry point for filter manipulation dialog.
  526. *
  527. * ENTRY:
  528. * none.
  529. *
  530. * EXIT:
  531. * none.
  532. *
  533. ****************************************************************************/
  534. CStructuralSubset* CDefineSS::DefineSubset(HWND hWnd, CStructuralSubset* pSS)
  535. {
  536. m_pSS = pSS;
  537. if (! m_hIL )
  538. {
  539. m_hIL = ImageList_LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_CNT_IMAGE_LIST), CWIDTH_IMAGE_LIST,
  540. 0, 0x00FF00FF, IMAGE_BITMAP, 0);
  541. if (! m_hIL )
  542. return NULL;
  543. }
  544. //
  545. // Create the model dialog.
  546. //
  547. m_pThis = this;
  548. m_hWndParent = hWnd;
  549. if(g_bWinNT5)
  550. return (CStructuralSubset*)DialogBoxW(_Module.GetResourceInstance(), MAKEINTRESOURCEW(DLG_FILTERS), hWnd, FilterDlgProc);
  551. else
  552. return (CStructuralSubset*)DialogBox(_Module.GetResourceInstance(), MAKEINTRESOURCE(DLG_FILTERS), hWnd, FilterDlgProc);
  553. }
  554. /*****************************************************************************
  555. * MyFilterLBFunc()
  556. *
  557. * ListBox subclasser. Used for our filter construction LB's. Needed so
  558. * we can do proper mouse move processing for diddiling the cursor and
  559. * implementing the silly collpase feature.
  560. *
  561. * ENTRY:
  562. * The usual window procedure parameters.
  563. *
  564. * EXIT:
  565. * a long LRESULT.
  566. *
  567. *****************************************************************************/
  568. LRESULT CDefineSS::MyFilterLBFunc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  569. {
  570. int iTop, iHeight, iItem;
  571. POINT pt;
  572. CFolder* pFgt;
  573. switch (uiMsg)
  574. {
  575. case WM_SETCURSOR:
  576. m_pThis->m_giXpos = -1;
  577. iTop = (int)SendMessage(hWnd, LB_GETTOPINDEX, 0, 0L);
  578. iHeight = (int)SendMessage(hWnd, LB_GETITEMHEIGHT, 0, 0L);
  579. GetCursorPos(&pt);
  580. ScreenToClient(hWnd, &pt);
  581. //
  582. // Compute index of the item the cursor is currently hovering over
  583. // and then get the item data for that item so we can determine it's
  584. // level and diddle the cursor appropiatly.
  585. //
  586. iItem = ((pt.y / iHeight) + iTop);
  587. if ( (pFgt = (CFolder*)SendMessage(hWnd, LB_GETITEMDATA, iItem, (LPARAM)0)) != (CFolder*)LB_ERR )
  588. {
  589. if ( pFgt->iLevel >= 1 )
  590. {
  591. if ( pt.x < (pFgt->iLevel * m_pThis->m_giIndentSpacing) )
  592. {
  593. SetCursor(LoadCursor(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDC_COLLAPSE)));
  594. m_pThis->m_giXpos = pt.x;
  595. return(TRUE);
  596. }
  597. }
  598. }
  599. break;
  600. case WM_KEYDOWN:
  601. PostMessage(hWnd, WM_SETCURSOR, 0, 0L);
  602. break;
  603. // HACKHACK - we have a hidden button called IDOK that
  604. // we use to trap VK_RETURNs so we can send these to
  605. // the list boxes or other controls
  606. case WM_SETFOCUS:
  607. m_pThis->SetDefaultButton( GetParent(hWnd), IDOK, FALSE );
  608. break;
  609. }
  610. return(CallWindowProc(m_pThis->m_lpfnOrigLBProc, hWnd, uiMsg, wParam, lParam));
  611. }
  612. /*****************************************************************************
  613. * FilterDlgProc()
  614. *
  615. * Filter dialog handler
  616. *
  617. * ENTRY:
  618. * Standard windows callback params.
  619. *
  620. * EXIT:
  621. * BOOL - TRUE if we handled it. FALSE if we didn't.
  622. *
  623. ****************************************************************************/
  624. INT_PTR CDefineSS::FilterDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  625. {
  626. int i;
  627. CFolder* pfgt;
  628. switch(msg)
  629. {
  630. case WM_INITDIALOG: {
  631. //
  632. // Set the this pointers for our LB message hook procedures. Also, set the procedure hooks
  633. // for our LB's so we can do cursor changes, tree collapse and proper keyboard interface.
  634. //
  635. SendMessage(GetDlgItem(hDlg,IDF_AVAIL), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0);
  636. SendMessage(GetDlgItem(hDlg,IDF_RANGE), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0);
  637. SendMessage(GetDlgItem(hDlg,IDF_RANGES), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0);
  638. // SendMessage(GetDlgItem(hDlg,IDF_RANGES), WM_SETFONT, (WPARAM)_Resource.GetUIFont(), 0);
  639. m_pThis->m_lpfnOrigLBProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg,IDF_RANGE), GWLP_WNDPROC, (LONG_PTR)MyFilterLBFunc);
  640. SetWindowLongPtr(GetDlgItem(hDlg,IDF_AVAIL), GWLP_WNDPROC, (LONG_PTR)MyFilterLBFunc);
  641. SendDlgItemMessage(hDlg, IDF_SAVE_EC, EM_LIMITTEXT, MAX_SS_NAME_LEN - 1, 0L);
  642. SendMessage(GetDlgItem(hDlg,IDF_SAVE_EC), WM_SETFONT, (WPARAM)m_pThis->m_pCollection->m_phmData->GetContentFont(), 0);
  643. m_pThis->InitDialog(hDlg, NULL);
  644. m_pThis->m_bShouldSave = FALSE;
  645. // set the Close button as the default button
  646. m_pThis->SetDefaultButton( hDlg, IDCANCEL, FALSE );
  647. m_pThis->m_giXpos = -1;
  648. break;
  649. }
  650. case WM_CHARTOITEM: // swallow these
  651. return( -2 );
  652. case WM_VKEYTOITEM:
  653. switch (CmdID)
  654. {
  655. case 0xBD: // '-'
  656. case VK_SUBTRACT:
  657. pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0);
  658. m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL));
  659. return(-2);
  660. case VK_HOME:
  661. if (CmdID == VK_HOME && !(GetKeyState(VK_CONTROL) & 0x8000 ))
  662. return( -1 );
  663. // otherwise fall through
  664. case VK_LEFT:
  665. if ( ((CmdID == VK_HOME)||(CmdID == VK_LEFT)) && (GetKeyState(VK_CONTROL) & 0x8000 ))
  666. {
  667. // Close everyone
  668. pfgt= (CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, 0, (LPARAM)0);
  669. while (pfgt->pNext)
  670. {
  671. m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL));
  672. pfgt = pfgt->pNext;
  673. }
  674. }
  675. else
  676. {
  677. pfgt= (CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0);
  678. m_pThis->ExpandContract(CmdHwnd, pfgt, FALSE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL));
  679. }
  680. return(-2);
  681. case VK_BACK: { // go to parent
  682. CFolder* pFgtCaret;
  683. int caret;
  684. if ( (caret = (int)SendMessage(CmdHwnd,LB_GETCARETINDEX,0,0L)) == -1 )
  685. return -2;
  686. if (! (pFgtCaret=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, caret, (LPARAM)0)) )
  687. return -2;
  688. pFgtCaret = pFgtCaret->pParent;
  689. if( pFgtCaret )
  690. {
  691. SendMessage(CmdHwnd, LB_SETSEL, FALSE, MAKELPARAM(caret,0));
  692. if ( (caret = (int)SendMessage(CmdHwnd,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtCaret)) == -1 )
  693. caret = 0;
  694. SendMessage(CmdHwnd, LB_SETCARETINDEX, caret, 0L);
  695. SendMessage(CmdHwnd, LB_SETSEL, TRUE, MAKELPARAM(caret,0));
  696. }
  697. return(-2);
  698. }
  699. case 0xBB: // '+'
  700. case VK_ADD:
  701. pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0);
  702. m_pThis->ExpandContract(CmdHwnd, pfgt, TRUE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL) );
  703. return(-2);
  704. case VK_RIGHT: {
  705. INT ci;
  706. pfgt=(CFolder*)SendMessage(CmdHwnd, LB_GETITEMDATA, CmdCode, (LPARAM)0);
  707. m_pThis->ExpandContract(CmdHwnd, pfgt, TRUE, (HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL));
  708. // select the first child if it has one
  709. if ( CmdID == VK_RIGHT && pfgt->pKid && (ci = (INT)SendMessage(CmdHwnd, LB_GETCARETINDEX, 0, 0L)) != LB_ERR ) {
  710. SendMessage(CmdHwnd, LB_SETSEL, FALSE, MAKELPARAM(ci,0));
  711. SendMessage(CmdHwnd, LB_SETCARETINDEX, ci++, MAKELPARAM(0,0));
  712. SendMessage(CmdHwnd, LB_SETSEL, TRUE, MAKELPARAM(ci,0));
  713. }
  714. return(-2);
  715. }
  716. case VK_RETURN:
  717. SendMessage( CmdHwnd, WM_COMMAND, ((HWND)CmdHwnd == GetDlgItem(hDlg,IDF_AVAIL))?IDF_AVAIL:IDF_RANGE,
  718. MAKELPARAM(CmdHwnd,LBN_DBLCLK));
  719. return(-2);
  720. }
  721. return(-1); // Tell dlgmgr we didn't handle this key stroke.
  722. case WM_NCLBUTTONDOWN:
  723. SendDlgItemMessage(hDlg,IDF_RANGES,CB_SHOWDROPDOWN,FALSE,0L);
  724. return(FALSE);
  725. case WM_DRAWITEM:
  726. // draw one of our listbox items
  727. m_pThis->DrawFBItem(hDlg, (LPDRAWITEMSTRUCT)lParam, (UINT)wParam);
  728. break;
  729. case WM_MEASUREITEM:
  730. // report how big our items are
  731. m_pThis->MeasureFBItem((LPMEASUREITEMSTRUCT)lParam);
  732. break;
  733. case WM_COMMAND:
  734. if ( m_pThis->FilterDlgCommand(hDlg, wParam, lParam) )
  735. {
  736. i = m_pThis->FillFilterTree(GetDlgItem(hDlg,IDF_RANGE), FALSE, FALSE);
  737. EnableWindow(GetDlgItem(hDlg,IDF_REMOVE), (i != 0));
  738. EnableWindow(GetDlgItem(hDlg,IDF_REMOVEALL), (i != 0));
  739. i = m_pThis->FillFilterTree(GetDlgItem(hDlg,IDF_AVAIL), TRUE, FALSE);
  740. EnableWindow(GetDlgItem(hDlg,IDF_ADD), (i != 0));
  741. EnableWindow(GetDlgItem(hDlg,IDF_ADDALL), (i != 0));
  742. m_pThis->SetSaveStatus(hDlg);
  743. }
  744. else
  745. return FALSE;
  746. break;
  747. case WM_CLOSE:
  748. // Closing the Dialog behaves the same as Cancel
  749. PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
  750. break;
  751. case WM_DESTROY:
  752. break;
  753. default:
  754. return FALSE; // say we didn't handle it
  755. break;
  756. }
  757. return TRUE; // say we did handle it
  758. }
  759. /*****************************************************************************
  760. * MeasureFBItem()
  761. *
  762. * Set appropiate size entries in the measure item struc according to the
  763. * items we'll be rendering in the filter listboxes.
  764. *
  765. * ENTRY:
  766. * hDlg - Handle to the filter dialog.
  767. * lpMIS - Pointer to the LPMEASUREITEMSTRUCT
  768. *
  769. * EXIT:
  770. * None.
  771. *
  772. *****************************************************************************/
  773. void CDefineSS::MeasureFBItem(LPMEASUREITEMSTRUCT lpMIS)
  774. {
  775. POINT pt;
  776. HDC hDC;
  777. HFONT hOldFont;
  778. TEXTMETRIC tm;
  779. ImageList_GetIconSize(m_hIL, (int*)&pt.x, (int*)&pt.y);
  780. hDC = GetDC(NULL);
  781. hOldFont = (HFONT)SelectObject(hDC, m_pCollection->m_phmData->GetContentFont());
  782. GetTextMetrics(hDC, &tm);
  783. SelectObject(hDC, hOldFont);
  784. ReleaseDC(NULL, hDC);
  785. if ( pt.y > tm.tmHeight )
  786. lpMIS->itemHeight = pt.y;
  787. else
  788. lpMIS->itemHeight = tm.tmHeight;
  789. m_giIndentSpacing = pt.x;
  790. m_iFontHeight = tm.tmHeight;
  791. m_iGlyphX = pt.x;
  792. m_iGlyphY = pt.y;
  793. }
  794. /*****************************************************************************
  795. * InitDialog()
  796. *
  797. * Do all initialization of the range definition dialog for a particular
  798. * situation, Add, Delete or Change.
  799. *
  800. * ENTRY:
  801. * hDlg - The handle to the dialog.
  802. * szRange - Pointer to new range or NULL if initing the range combo-box.
  803. *
  804. * EXIT:
  805. * BOOL - TRUE on success, FALSE on failure.
  806. *
  807. ****************************************************************************/
  808. BOOL CDefineSS::InitDialog(HWND hDlg, LPSTR szRange)
  809. {
  810. int iSel = 0;
  811. int i = 0;
  812. int iFilterCnt = 0;
  813. BOOL bDef = FALSE;
  814. CStructuralSubset* pSS = NULL;
  815. SendDlgItemMessage(hDlg,IDF_RANGES,CB_SETEXTENDEDUI,TRUE,0L);
  816. if (! m_pCollection->m_pSSList )
  817. return(FALSE);
  818. if (! szRange )
  819. {
  820. SendDlgItemMessage(hDlg, IDF_RANGES, CB_RESETCONTENT, 0, 0L);
  821. while ( (pSS = m_pCollection->m_pSSList->GetNextSubset(pSS)) )
  822. {
  823. i = (int) SendDlgItemMessage(hDlg, IDF_RANGES, CB_INSERTSTRING, (WPARAM) -1, (LPARAM)(LPSTR)pSS->GetName());
  824. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETITEMDATA, i, (LPARAM)((DWORD_PTR)pSS));
  825. }
  826. }
  827. else
  828. {
  829. if ( (iSel = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT,0, (LPARAM)szRange)) != LB_ERR )
  830. pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, iSel,0L);
  831. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, iSel, 0L);
  832. bDef = TRUE;
  833. }
  834. //
  835. // Select the current filter. If it's "entire CD" select "New".
  836. //
  837. if (! bDef || ! pSS)
  838. {
  839. pSS = m_pCollection->m_pSSList->GetNew();
  840. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)pSS->GetName());
  841. }
  842. //
  843. // Init the listboxes!
  844. //
  845. SetRangeToTree(pSS);
  846. //
  847. // Init filter LB and remove options.
  848. //
  849. i = FillFilterTree(GetDlgItem(hDlg,IDF_RANGE), FALSE, FALSE);
  850. EnableWindow(GetDlgItem(hDlg,IDF_REMOVE), (i != 0));
  851. EnableWindow(GetDlgItem(hDlg,IDF_REMOVEALL), (i != 0));
  852. //
  853. // Init available LB and add options.
  854. //
  855. i = FillFilterTree(GetDlgItem(hDlg,IDF_AVAIL), TRUE, FALSE);
  856. EnableWindow(GetDlgItem(hDlg,IDF_ADD), (i != 0));
  857. EnableWindow(GetDlgItem(hDlg,IDF_ADDALL), (i != 0));
  858. //
  859. // deal with buttons
  860. //
  861. if ( pSS->IsReadOnly() )
  862. {
  863. EnableWindow(GetDlgItem(hDlg, IDF_DELETE), FALSE);
  864. SetWindowText(GetDlgItem(hDlg,IDF_SAVE_EC),GetStringResource(IDS_UNTITLED_SUBSET));
  865. }
  866. else
  867. {
  868. EnableWindow(GetDlgItem(hDlg, IDF_DELETE), TRUE);
  869. SetWindowText(GetDlgItem(hDlg,IDF_SAVE_EC), pSS->GetName());
  870. }
  871. EnableWindow(GetDlgItem(hDlg,IDF_SAVE), FALSE);
  872. return(TRUE);
  873. }
  874. /*****************************************************************************
  875. * DoesNodeHaveANext()
  876. *
  877. * aids DrawFBItem() in painting the vertical connecting codes in the filter
  878. * list boxes.
  879. *
  880. * ENTRY:
  881. * LbId - ListBox ID.
  882. * n - What level are we painting.
  883. * pFgt - Pointer to the node we're painting.
  884. *
  885. * EXIT:
  886. * BOOL - TRUE if a next will appear on the given level. FALSE otherwise.
  887. *
  888. ****************************************************************************/
  889. BOOL CDefineSS::DoesNodeHaveANext(UINT LbId, int n, CFolder* pFgt)
  890. {
  891. while ( pFgt->iLevel > (n + 1) )
  892. pFgt = pFgt->pParent;
  893. while ( pFgt->pNext )
  894. {
  895. pFgt = pFgt->pNext;
  896. if ( (PRESENT((LbId == IDF_AVAIL), pFgt)) )
  897. return(TRUE);
  898. }
  899. return(FALSE);
  900. }
  901. /*****************************************************************************
  902. * DrawFBItem()
  903. *
  904. * Function is responsible for painting the items in the owner-draw list boxes
  905. * that are used in the filter contents dialog.
  906. *
  907. * ENTRY:
  908. * hDlg - Handle to the dialog.
  909. * lpDI - Pointer to the draw item struct. Contains a pFgt to the item
  910. * we're painting.
  911. * Lbid - ListBox identifier.
  912. *
  913. * EXIT:
  914. * None.
  915. *
  916. ****************************************************************************/
  917. void CDefineSS::DrawFBItem(HWND hDlg, LPDRAWITEMSTRUCT lpDI, UINT LbId)
  918. {
  919. RECT rc;
  920. int n;
  921. WORD wTopText;
  922. HDC hDC;
  923. CFolder* pFgt;
  924. INT xBitmap = 0;
  925. int iHeight;
  926. BOOL bHasNext;
  927. char* lpszText;
  928. char szScratch[MAX_PATH];
  929. static int bNoReEnter = 0;
  930. if (lpDI->itemID == 0xFFFF)
  931. return;
  932. pFgt = (CFolder*)lpDI->itemData;
  933. if (!pFgt || lpDI->itemData == -1 )
  934. return;
  935. bNoReEnter++;
  936. if ( bNoReEnter > 1 )
  937. {
  938. bNoReEnter--;
  939. return;
  940. }
  941. hDC = lpDI->hDC;
  942. rc = lpDI->rcItem;
  943. iHeight = rc.bottom - rc.top;
  944. wTopText = (WORD)((rc.top + ((iHeight) / 2)) - ((m_iFontHeight - 2) / 2));
  945. /*
  946. * Paint the proper lines based on the level and position of the item.
  947. */
  948. if ( pFgt->iLevel )
  949. {
  950. for ( n = 0; n < pFgt->iLevel; n++ )
  951. {
  952. // Draw the verticle line indicating level. Remember to not leave a
  953. // "tail".
  954. //
  955. bHasNext = DoesNodeHaveANext(LbId, n, pFgt);
  956. if ( bHasNext )
  957. QRect(hDC, rc.left + m_iGlyphX / 2, rc.top, // Full verticle line.
  958. 1, iHeight, COLOR_WINDOWTEXT);
  959. else if ( n == (pFgt->iLevel - 1) )
  960. QRect(hDC, rc.left + m_iGlyphX / 2, rc.top, // Half vertical line.
  961. 1, (iHeight / 2), COLOR_WINDOWTEXT);
  962. rc.left += m_iGlyphX;
  963. }
  964. // Draw the horizontal connector line.
  965. //
  966. QRect(hDC, (rc.left - m_iGlyphX / 2), (rc.top + (m_iGlyphY / 2)), ((m_iGlyphX / 2)), 1, COLOR_WINDOWTEXT);
  967. }
  968. //
  969. // draw the little book.
  970. //
  971. if ( EXPANDED((LbId == IDF_AVAIL), pFgt) ) // Is the book open or closed ?
  972. xBitmap++; // It's an open book.
  973. ImageList_Draw(m_hIL, xBitmap, hDC, rc.left+1, rc.top, ILD_NORMAL);
  974. rc.left += m_iGlyphX + 2;
  975. if ( lpDI->itemState & ODS_SELECTED )
  976. {
  977. SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
  978. SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  979. }
  980. else
  981. {
  982. SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  983. SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  984. }
  985. //
  986. // Now paint the text.
  987. //
  988. if ( pFgt->f_HasHash && pFgt->pExTitle )
  989. {
  990. pFgt->pExTitle->GetTopicLocation(0, szScratch, sizeof(szScratch));
  991. lpszText = szScratch;
  992. }
  993. else
  994. lpszText = pFgt->Title;
  995. //
  996. // Set LB Horizontal extent based upon the width of the string.
  997. //
  998. int iWidth, len = lstrlen(lpszText);
  999. SIZE size;
  1000. if ( lpDI->itemAction == ODA_DRAWENTIRE )
  1001. {
  1002. GetTextExtentPoint32(hDC, lpszText, len, &size);
  1003. size.cx += rc.left + 4;
  1004. iWidth = (int)SendDlgItemMessage(hDlg, LbId, LB_GETHORIZONTALEXTENT, 0, 0L);
  1005. if ( size.cx > iWidth )
  1006. SendDlgItemMessage(hDlg, LbId, LB_SETHORIZONTALEXTENT, (WPARAM)size.cx, 0L);
  1007. }
  1008. //
  1009. // Paint the string.
  1010. //
  1011. ExtTextOut(hDC, (rc.left + 2), wTopText, ETO_OPAQUE | ETO_CLIPPED, &rc, lpszText, len, NULL);
  1012. if (lpDI->itemState & ODS_FOCUS)
  1013. DrawFocusRect(hDC,&rc);
  1014. bNoReEnter--;
  1015. }
  1016. /****************************************************************************
  1017. * SetRangeToTree()
  1018. *
  1019. * Function will set the filter tree up according the the subset specified
  1020. * by the given CStructuraSubset pointer.
  1021. *
  1022. * ENTRY:
  1023. * CStructuralSubset* A NULL object is the equivelent to RF_NONE.
  1024. * Use of this feature will cause all nodes to be
  1025. * removed from the filter.
  1026. *
  1027. * EXIT:
  1028. * BOOL - TRUE for success. FALSE for failure!
  1029. *
  1030. ****************************************************************************/
  1031. BOOL CDefineSS::SetRangeToTree(CStructuralSubset* pSS)
  1032. {
  1033. CFolder* pFgt; // pointer to filtered group tree.
  1034. UINT i = 0;
  1035. HASH Hash;
  1036. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1037. if ( pSS )
  1038. {
  1039. if ( pSS->m_dwFlags & SS_ENTIRE_CONTENTS )
  1040. {
  1041. while ( pFgt )
  1042. {
  1043. AddNode2Filter(pFgt);
  1044. pFgt = pFgt->pNext;
  1045. }
  1046. }
  1047. else
  1048. {
  1049. //
  1050. // De-select all nodes filter bits and select the proper
  1051. // tree nodes based on the hash list!
  1052. //
  1053. while ( pFgt )
  1054. {
  1055. RemoveNodeFromFilter(pFgt);
  1056. pFgt = pFgt->pNext;
  1057. }
  1058. while ( Hash = pSS->EnumHashes(i++) )
  1059. {
  1060. if ( (pFgt = m_pCollection->m_pCSlt->HashToCFolder(Hash)) )
  1061. AddNode2Filter(pFgt);
  1062. }
  1063. }
  1064. return(TRUE);
  1065. }
  1066. else
  1067. {
  1068. while ( pFgt )
  1069. {
  1070. RemoveNodeFromFilter(pFgt);
  1071. pFgt = pFgt->pNext;
  1072. }
  1073. }
  1074. return(FALSE);
  1075. }
  1076. /****************************************************************************
  1077. * GetRangeFromTree()
  1078. *
  1079. * Function will extract a range from the filter LB and return a handle to
  1080. * the range.
  1081. *
  1082. * ENTRY:
  1083. * sz - Range name.
  1084. *
  1085. * EXIT:
  1086. *
  1087. ****************************************************************************/
  1088. CStructuralSubset* CDefineSS::GetRangeFromTree(LPSTR sz)
  1089. {
  1090. CFolder* pFgt;
  1091. CFolder* pFgtLast;
  1092. int i = 0;
  1093. CStructuralSubset* pSS;
  1094. CExTitle* pExTitle;
  1095. if (! (pSS = new CStructuralSubset(sz)) )
  1096. return NULL; // Young girls are chaining themselves to the axels of big mac trucks.
  1097. // Walk root level nodes and gather up the prefix hashes from each node
  1098. // and all it's kids if the filter bit is set.
  1099. //
  1100. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1101. while ( pFgt )
  1102. {
  1103. do
  1104. {
  1105. pFgtLast = pFgt;
  1106. if ( pFgt->f_Filter && !pFgt->f_Available && pFgt->f_HasHash )
  1107. {
  1108. pSS->AddHash(pFgt->pExTitle->m_dwHash);
  1109. //
  1110. // Any merged .CHM's ?
  1111. //
  1112. pExTitle = pFgt->pExTitle->m_pKid;
  1113. while ( pExTitle )
  1114. {
  1115. pSS->AddHash(pExTitle->m_dwHash);
  1116. pExTitle = pExTitle->m_pNextKid;
  1117. }
  1118. i++;
  1119. break;
  1120. }
  1121. pFgt = pFgt->pKid;
  1122. } while ( pFgt );
  1123. pFgt = pFgtLast;
  1124. while ( pFgt && (! (pFgt->pNext)) )
  1125. pFgt = pFgt->pParent;
  1126. if ( pFgt )
  1127. pFgt = pFgt->pNext;
  1128. }
  1129. // Lastly, setup the range entry and add it to the range list.
  1130. //
  1131. if (! i )
  1132. {
  1133. delete pSS;
  1134. return(NULL);
  1135. }
  1136. return pSS;
  1137. }
  1138. /*****************************************************************************
  1139. * SetSaveStatus()
  1140. *
  1141. * If you don't want'em saving then disable the save button!
  1142. *
  1143. * ENTRY:
  1144. * hDlg - Handle to the define contents dialog.
  1145. *
  1146. * EXIT:
  1147. * None.
  1148. *
  1149. ****************************************************************************/
  1150. void CDefineSS::SetSaveStatus(HWND hDlg)
  1151. {
  1152. char sz[MAX_SS_NAME_LEN];
  1153. int i;
  1154. CStructuralSubset* pSS;
  1155. HWND hWnd = GetDlgItem(hDlg, IDF_SAVE);
  1156. GetWindowText(GetDlgItem(hDlg, IDF_SAVE_EC), sz, sizeof(sz));
  1157. i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L);
  1158. pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETITEMDATA,i,0L);
  1159. if ( ((pSS->m_dwFlags & SS_READ_ONLY) && (! lstrcmpi(pSS->GetName(), sz))) ||
  1160. (! SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETCOUNT, 0, 0L)) ||
  1161. (! lstrlen(sz)) || !m_bShouldSave )
  1162. EnableWindow(hWnd, FALSE);
  1163. else
  1164. EnableWindow(hWnd, TRUE);
  1165. }
  1166. /*****************************************************************************
  1167. * ShouldSave()
  1168. *
  1169. * Alert the user that they may want to save the changes they've made to
  1170. * the filter.
  1171. *
  1172. * ENTRY:
  1173. * hDlg - Handle to the filter definition dialog.
  1174. *
  1175. * EXIT:
  1176. * INT - IDYES, IDNO or IDCANCEL. 0 if saving is not necessary.
  1177. *
  1178. ****************************************************************************/
  1179. INT CDefineSS::ShouldSave(HWND hDlg)
  1180. {
  1181. char sz[MAX_SS_NAME_LEN];
  1182. if ( IsWindowEnabled(GetDlgItem(hDlg, IDF_SAVE)) )
  1183. {
  1184. GetWindowText(GetDlgItem(hDlg, IDF_SAVE_EC), sz, sizeof(sz));
  1185. return MsgBox(IDS_SAVE_FILTER, sz, MB_YESNOCANCEL | MB_ICONQUESTION);
  1186. }
  1187. return(0);
  1188. }
  1189. /****************************************************************************
  1190. * FilterDlgCommand()
  1191. *
  1192. * Function handles all WM_COMMAND messages from the filter dialog.
  1193. *
  1194. * ENTRY:
  1195. * hDlg - Handle to the dialog.
  1196. * wParam - Message dependent.
  1197. * lParam - Message dependent.
  1198. *
  1199. * EXIT:
  1200. * Returns TRUE is range list boxes need updating. False otherwise.
  1201. *
  1202. ***************************************************************************/
  1203. BOOL CDefineSS::FilterDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
  1204. {
  1205. int i, n;
  1206. CFolder* pFgt;
  1207. char sz[MAX_SS_NAME_LEN];
  1208. static il;
  1209. static HWND hWndCombo = NULL;
  1210. switch (CmdID)
  1211. {
  1212. // HACKHACK - this is an invisible button that we use to route double-clicks
  1213. // to other controls
  1214. case IDOK:
  1215. {
  1216. HWND hWndCurrent, hWndFocus;
  1217. int id = 0;
  1218. // find out which control we are on
  1219. if( (hWndFocus = GetFocus()) )
  1220. {
  1221. hWndCurrent = GetDlgItem(hDlg,IDF_AVAIL);
  1222. if( hWndFocus == hWndCurrent )
  1223. id = IDF_AVAIL;
  1224. hWndCurrent = GetDlgItem(hDlg,IDF_RANGE);
  1225. if( hWndFocus == hWndCurrent )
  1226. id = IDF_RANGE;
  1227. hWndCurrent = GetDlgItem(hDlg,IDF_RANGES);
  1228. if( hWndFocus == hWndCurrent )
  1229. id = IDF_RANGES;
  1230. SendMessage( hDlg, WM_COMMAND, MAKEWPARAM(id,LBN_DBLCLK), 0L);
  1231. }
  1232. return( TRUE );
  1233. }
  1234. case IDF_SAVE:
  1235. if ( SaveFilter(hDlg) )
  1236. {
  1237. SetDefaultButton( hDlg, IDCANCEL, TRUE );
  1238. i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L);
  1239. m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L);
  1240. EnableWindow(GetDlgItem(hDlg, IDF_DELETE), TRUE);
  1241. m_bShouldSave = FALSE;
  1242. }
  1243. else
  1244. SetFocus(GetDlgItem(hDlg, IDF_RANGES));
  1245. break;
  1246. case IDCANCEL:
  1247. // if a combo box is open then close it and don't close the dialog
  1248. if( hWndCombo )
  1249. {
  1250. SendMessage( hWndCombo, CB_SHOWDROPDOWN, FALSE, 0L );
  1251. return FALSE;
  1252. }
  1253. //
  1254. // Has the range been modified ? Might it need to be saved.
  1255. //
  1256. if ( m_bShouldSave )
  1257. {
  1258. i = ShouldSave(hDlg);
  1259. if ( i == IDYES )
  1260. {
  1261. if (! SaveFilter(hDlg) )
  1262. {
  1263. SetFocus(GetDlgItem(hDlg, IDF_RANGES));
  1264. break;
  1265. }
  1266. i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L);
  1267. m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L);
  1268. m_bShouldSave = FALSE;
  1269. }
  1270. else if ( i == IDCANCEL )
  1271. break;
  1272. }
  1273. EndDialog(hDlg, (INT_PTR)m_pSS);
  1274. break;
  1275. case IDF_DELETE:
  1276. if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L)) != CB_ERR )
  1277. {
  1278. int n;
  1279. m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L);
  1280. if ( MsgBox(IDS_CONFIRM_SSDELETE, m_pSS->GetName(), MB_YESNO | MB_ICONQUESTION) == IDYES )
  1281. {
  1282. if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT, 0, (LPARAM)m_pSS->GetName())) != LB_ERR)
  1283. SendDlgItemMessage(hDlg, IDF_RANGES, CB_DELETESTRING, i, 0L);
  1284. m_pCollection->m_pSSList->DeleteSubset(m_pSS, NULL, m_hWndParent);
  1285. n = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCOUNT, 0, 0L);
  1286. n--;
  1287. i = min(n,i);
  1288. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, i, 0L);
  1289. i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L);
  1290. m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L);
  1291. InitDialog(hDlg, m_pSS->GetName());
  1292. m_bShouldSave = FALSE;
  1293. return(FALSE);
  1294. }
  1295. }
  1296. break;
  1297. case IDF_SAVE_EC:
  1298. switch (CmdCode)
  1299. {
  1300. case EN_UPDATE:
  1301. m_bShouldSave = TRUE;
  1302. SetSaveStatus(hDlg);
  1303. SetDefaultButton( hDlg, IDF_SAVE, FALSE );
  1304. break;
  1305. case EN_CHANGE:
  1306. m_bShouldSave = TRUE;
  1307. break;
  1308. }
  1309. break;
  1310. case IDF_RANGES:
  1311. switch (CmdCode)
  1312. {
  1313. case CBN_DROPDOWN:
  1314. il = (int)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETCURSEL,0,0L);
  1315. break;
  1316. case CBN_SELCHANGE:
  1317. i = (int)SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETCURSEL,0,0L);
  1318. SendDlgItemMessage(hDlg,IDF_RANGES,CB_GETLBTEXT,i,(LPARAM)sz);
  1319. if ( m_bShouldSave )
  1320. {
  1321. n = ShouldSave(hDlg);
  1322. if ( n == IDCANCEL )
  1323. goto cancel_it;
  1324. else if ( n == IDYES )
  1325. {
  1326. if (! SaveFilter(hDlg) )
  1327. goto cancel_it;
  1328. }
  1329. //SetDefaultButton( hDlg, IDCANCEL, TRUE );
  1330. }
  1331. i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETCURSEL, 0, 0L);
  1332. m_pSS = (CStructuralSubset*)SendDlgItemMessage(hDlg, IDF_RANGES, CB_GETITEMDATA, i, 0L);
  1333. m_bShouldSave = FALSE;
  1334. InitDialog(hDlg, sz);
  1335. return(FALSE);
  1336. cancel_it:
  1337. SendDlgItemMessage(hDlg,IDF_RANGES,CB_SETCURSEL,(WPARAM)il,0L);
  1338. }
  1339. break;
  1340. case IDHELP:
  1341. break;
  1342. case IDF_NEW:
  1343. m_bShouldSave = TRUE;
  1344. SetSaveStatus(hDlg);
  1345. break;
  1346. case IDF_REMOVE:
  1347. n = (int)SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETCOUNT, 0, 0L);
  1348. for (i = 0; i < n; i++)
  1349. {
  1350. if (SendDlgItemMessage(hDlg, IDF_RANGE, LB_GETSEL, i, 0L))
  1351. {
  1352. pFgt=(CFolder*)SendDlgItemMessage(hDlg,IDF_RANGE,LB_GETITEMDATA,i, (LPARAM)0);
  1353. RemoveNodeFromFilter(pFgt);
  1354. SendDlgItemMessage(hDlg, IDF_RANGE, LB_SETSEL, 0, (LPARAM)i);
  1355. m_bShouldSave = TRUE;
  1356. }
  1357. }
  1358. SetFocus(GetDlgItem(hDlg, IDF_RANGE));
  1359. return(TRUE);
  1360. break;
  1361. case IDF_ADDALL:
  1362. //
  1363. // Enumerate root level nodes Adding each!
  1364. //
  1365. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1366. while ( pFgt )
  1367. {
  1368. AddNode2Filter(pFgt);
  1369. pFgt = pFgt->pNext;
  1370. }
  1371. m_bShouldSave = TRUE;
  1372. SetFocus(GetDlgItem(hDlg, IDF_RANGE));
  1373. return(TRUE);
  1374. break;
  1375. case IDF_ADD:
  1376. n = (int)SendDlgItemMessage(hDlg, IDF_AVAIL, LB_GETCOUNT, 0, 0L);
  1377. for (i = 0; i < n; i++)
  1378. {
  1379. if (SendDlgItemMessage(hDlg, IDF_AVAIL, LB_GETSEL, i, 0L))
  1380. {
  1381. pFgt=(CFolder*)SendDlgItemMessage(hDlg,IDF_AVAIL,LB_GETITEMDATA,i, (LPARAM)0);
  1382. AddNode2Filter(pFgt);
  1383. SendDlgItemMessage(hDlg, IDF_AVAIL, LB_SETSEL, 0, (LPARAM)i);
  1384. m_bShouldSave = TRUE;
  1385. }
  1386. }
  1387. SetFocus(GetDlgItem(hDlg, IDF_AVAIL));
  1388. return(TRUE);
  1389. break;
  1390. case IDF_REMOVEALL:
  1391. //
  1392. // Enumerate root level nodes removing each!
  1393. //
  1394. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1395. while ( pFgt )
  1396. {
  1397. RemoveNodeFromFilter(pFgt);
  1398. pFgt = pFgt->pNext;
  1399. }
  1400. m_bShouldSave = TRUE;
  1401. SetFocus(GetDlgItem(hDlg, IDF_AVAIL));
  1402. return(TRUE);
  1403. break;
  1404. case IDF_RANGE:
  1405. switch (CmdCode)
  1406. {
  1407. case LBN_DBLCLK:
  1408. n = 0;
  1409. goto expcont;
  1410. }
  1411. break;
  1412. case IDF_AVAIL:
  1413. switch (CmdCode)
  1414. {
  1415. case LBN_DBLCLK:
  1416. n = 1;
  1417. expcont:
  1418. i = (int)SendDlgItemMessage(hDlg,CmdID,LB_GETCARETINDEX,0,0L);
  1419. if (i == (int)LB_ERR)
  1420. break;
  1421. pFgt=(CFolder*)SendDlgItemMessage(hDlg,CmdID,LB_GETITEMDATA,i, (LPARAM)0);
  1422. if ( !pFgt || pFgt == (CFolder*)-1 )
  1423. break;
  1424. //
  1425. // giXpos is set in my LB hook proc. If it's != -1 then this
  1426. // double click is intended as a collapsing dbl click and giXpos
  1427. // will indicate the x position within the LB where the double
  1428. // click occured. Sound reasonable ?
  1429. //
  1430. if ( m_giXpos > 0 )
  1431. {
  1432. int iLevel;
  1433. iLevel = m_giXpos / m_giIndentSpacing;
  1434. while ( (iLevel != pFgt->iLevel) && pFgt->pParent )
  1435. pFgt = pFgt->pParent;
  1436. }
  1437. ExpandContract(GetDlgItem(hDlg,CmdID), pFgt, -1, n);
  1438. break;
  1439. default:
  1440. break;
  1441. }
  1442. break;
  1443. }
  1444. switch( CmdCode )
  1445. {
  1446. case CBN_DROPDOWN:
  1447. hWndCombo = (HWND) lParam;
  1448. SetDefaultButton( hDlg, IDCANCEL, FALSE );
  1449. break;
  1450. case CBN_CLOSEUP:
  1451. hWndCombo = NULL;
  1452. SetDefaultButton( hDlg, IDCANCEL, FALSE );
  1453. break;
  1454. }
  1455. return(FALSE);
  1456. }
  1457. /*****************************************************************************
  1458. * SaveFilter()
  1459. *
  1460. * Function saves a filter to the filter list, insuring a read-only filter
  1461. * is not over-written.
  1462. *
  1463. * ENTRY:
  1464. * hDlg - Handle to the filter definition dialog.
  1465. *
  1466. * EXIT:
  1467. * BOOL - TRUE Indicates the filter was saved. FALSE indicates filter
  1468. * was not saved.
  1469. *
  1470. *****************************************************************************/
  1471. BOOL CDefineSS::SaveFilter(HWND hDlg)
  1472. {
  1473. char szGivenRN[MAX_SS_NAME_LEN];
  1474. int i = 0;
  1475. CStructuralSubset* pSS = NULL;
  1476. CStructuralSubset* pSSNew;
  1477. GetDlgItemText(hDlg, IDF_SAVE_EC, szGivenRN, sizeof(szGivenRN));
  1478. //
  1479. // Extract range from the filter LB.
  1480. //
  1481. if (! (pSSNew = GetRangeFromTree(szGivenRN)) )
  1482. return(FALSE);
  1483. //
  1484. // Insure we're not trashing a read only ramge.
  1485. //
  1486. while ( (pSS = m_pCollection->m_pSSList->GetNextSubset(pSS)) )
  1487. {
  1488. if (! lstrcmpi(pSS->GetName(), pSSNew->GetName()) )
  1489. {
  1490. if ( pSS->m_dwFlags & SS_READ_ONLY )
  1491. {
  1492. MsgBox(IDS_BAD_RANGE_NAME, MB_OK | MB_ICONEXCLAMATION);
  1493. return(FALSE);
  1494. }
  1495. // Sure you want to over-write the existing rnage ?
  1496. //
  1497. if ( MsgBox(IDS_OVERWRITE, MB_YESNO | MB_ICONQUESTION) == IDNO )
  1498. return(FALSE);
  1499. if ( (i = (int)SendDlgItemMessage(hDlg, IDF_RANGES, CB_FINDSTRINGEXACT, 0, (LPARAM)pSS->GetName())) != LB_ERR)
  1500. SendDlgItemMessage(hDlg, IDF_RANGES, CB_DELETESTRING, i, 0L);
  1501. m_pCollection->m_pSSList->DeleteSubset(pSS, pSSNew, m_hWndParent);
  1502. break;
  1503. }
  1504. }
  1505. // Add new subset to the list and update UI...
  1506. //
  1507. m_pCollection->m_pSSList->AddSubset(pSSNew, m_hWndParent);
  1508. SendDlgItemMessage(hDlg, IDF_RANGES, CB_INSERTSTRING, 0, (LPARAM)pSSNew->GetName());
  1509. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETITEMDATA, 0, (LPARAM)pSSNew);
  1510. SendDlgItemMessage(hDlg, IDF_RANGES, CB_SETCURSEL, 0, 0L);
  1511. EnableWindow(GetDlgItem(hDlg,IDF_SAVE), FALSE);
  1512. return(TRUE);
  1513. }
  1514. /*****************************************************************************
  1515. * RemoveNodeFromFilter()
  1516. *
  1517. * Function removes the node and all it's kids from the filter.
  1518. *
  1519. * ENTRY:
  1520. * pFgt - Poiner to the node to be removed.
  1521. *
  1522. * EXIT:
  1523. * None.
  1524. *
  1525. *****************************************************************************/
  1526. void CDefineSS::RemoveNodeFromFilter(CFolder* pFgti)
  1527. {
  1528. CFolder* pFgt;
  1529. CFolder* pFgtLast;
  1530. // First, de-select the node and any children of the node taking care
  1531. // to set the f_Available bit from each!
  1532. //
  1533. pFgt = pFgti;
  1534. if ( pFgt->pKid )
  1535. {
  1536. while ( pFgt )
  1537. {
  1538. do
  1539. {
  1540. pFgt->f_Available = 1;
  1541. pFgt->f_Filter = 0;
  1542. pFgtLast = pFgt;
  1543. pFgt = pFgt->pKid;
  1544. } while ( pFgt );
  1545. pFgt = pFgtLast;
  1546. while ( pFgt && (! (pFgt->pNext)) )
  1547. {
  1548. if ( pFgt->pParent != pFgti )
  1549. pFgt = pFgt->pParent;
  1550. else
  1551. break;
  1552. }
  1553. if ( pFgt )
  1554. pFgt = pFgt->pNext;
  1555. }
  1556. }
  1557. // Next, assure any parents of the node are marked as available. We also
  1558. // have to take care to see that a parent who has no children who are
  1559. // part of the filter are removed from the filter!
  1560. //
  1561. pFgt = pFgti;
  1562. pFgt->f_Filter = 0;
  1563. pFgt->f_Available = 1;
  1564. while ( pFgt = pFgt->pParent )
  1565. {
  1566. pFgt->f_Available = 1;
  1567. SetFilterStatus(pFgt);
  1568. }
  1569. }
  1570. /*****************************************************************************
  1571. * SetFilterStatus()
  1572. *
  1573. * If ALL children of the given node are marked as available, that nodes
  1574. * filter bit will be set to zero.
  1575. *
  1576. * ENTRY:
  1577. * pFgt - Pointer to the node to start from.
  1578. *
  1579. * EXIT:
  1580. *
  1581. ****************************************************************************/
  1582. void CDefineSS::SetFilterStatus(CFolder* pFgt)
  1583. {
  1584. CFolder* pFgtl = pFgt->pKid;
  1585. CFolder* pFgtLast;
  1586. while ( pFgtl )
  1587. {
  1588. do
  1589. {
  1590. if (! pFgtl->f_Available )
  1591. return;
  1592. pFgtLast = pFgtl;
  1593. pFgtl = pFgtl->pKid;
  1594. } while ( pFgtl );
  1595. pFgtl = pFgtLast;
  1596. while ( pFgtl && (! (pFgtl->pNext)) && (pFgtl->pParent != pFgt) )
  1597. pFgtl = pFgtl->pParent;
  1598. if ( pFgtl )
  1599. pFgtl = pFgtl->pNext;
  1600. }
  1601. pFgt->f_Filter = 0;
  1602. }
  1603. /*****************************************************************************
  1604. * AddNode2Filter()
  1605. *
  1606. * Function adds a node to the filter assuring that necessary parents are
  1607. * added, and necessary nodes are removed from the available listbox.
  1608. *
  1609. * ENTRY:
  1610. * pFgti = Node to be added.
  1611. *
  1612. * EXIT:
  1613. * None.
  1614. *
  1615. *****************************************************************************/
  1616. void CDefineSS::AddNode2Filter(CFolder* pFgti)
  1617. {
  1618. CFolder* pFgt;
  1619. CFolder* pFgtLast;
  1620. // First, select the node and any children of the node taking care
  1621. // to remove the f_Available bit from each!
  1622. //
  1623. pFgt = pFgti;
  1624. while ( pFgt )
  1625. {
  1626. do
  1627. {
  1628. pFgt->f_Available = 0;
  1629. pFgt->f_Filter = 1;
  1630. pFgtLast = pFgt;
  1631. pFgt = pFgt->pKid;
  1632. } while ( pFgt );
  1633. pFgt = pFgtLast;
  1634. if ( pFgt == pFgti )
  1635. break;
  1636. while ( pFgt && (! (pFgt->pNext)) )
  1637. {
  1638. if ( pFgt->pParent != pFgti )
  1639. pFgt = pFgt->pParent;
  1640. else
  1641. break;
  1642. }
  1643. if ( pFgt )
  1644. pFgt = pFgt->pNext;
  1645. }
  1646. // Next, assure parents are selected.
  1647. //
  1648. pFgt = pFgti;
  1649. if ( pFgt->pParent )
  1650. {
  1651. while ( pFgt = pFgt->pParent )
  1652. {
  1653. pFgt->f_Filter = 1;
  1654. pFgt->f_F_Open = 1;
  1655. SetAvailableStatus(pFgt); // Should it still be available ?
  1656. }
  1657. }
  1658. }
  1659. /*****************************************************************************
  1660. * SetAvailabilityStatus()
  1661. *
  1662. * If ALL children of the given node are selected as part of a filter, that
  1663. * nodes availability bit will be set to zero.
  1664. *
  1665. * ENTRY:
  1666. * pFgt - Pointer to the node to start from.
  1667. *
  1668. * EXIT:
  1669. *
  1670. ****************************************************************************/
  1671. void CDefineSS::SetAvailableStatus(CFolder* pFgt)
  1672. {
  1673. CFolder* pFgtl = pFgt->pKid;
  1674. CFolder* pFgtLast;
  1675. while ( pFgtl )
  1676. {
  1677. do
  1678. {
  1679. if (! pFgtl->f_Filter )
  1680. return;
  1681. pFgtLast = pFgtl;
  1682. pFgtl = pFgtl->pKid;
  1683. } while ( pFgtl );
  1684. pFgtl = pFgtLast;
  1685. while ( pFgtl && (! (pFgtl->pNext)) && (pFgtl->pParent != pFgt) )
  1686. pFgtl = pFgtl->pParent;
  1687. if ( pFgtl )
  1688. pFgtl = pFgtl->pNext;
  1689. }
  1690. pFgt->f_Available = 0;
  1691. }
  1692. /******************************************************************************
  1693. * ExpandContract()
  1694. *
  1695. * Function set's appropiate bits in the appropiate nodes to cause
  1696. * a parent node to expand or contract when FillRangeTree() is called.
  1697. *
  1698. * ENTRY:
  1699. * hwndLB - Handle to the listbox that contains the node were operating on.
  1700. *
  1701. * pFgt - Pointer to the node were expanding or contracting.
  1702. *
  1703. * sel - Identifies action: TRUE for Expansion
  1704. * FALSE for Contraction
  1705. * -1 for double-click which really means that
  1706. * we toggle the current state for the appropiate
  1707. * LB identified by the "which" arg.
  1708. *
  1709. * which - Which ListBox are we working with: TRUE == Available LB.
  1710. * FALSE == Range LB.
  1711. *
  1712. * EXIT:
  1713. * WORD - Returns the AX from FillRangeTree which happens to be the number
  1714. * of items placed in the LB.
  1715. *
  1716. *****************************************************************************/
  1717. WORD CDefineSS::ExpandContract(HWND hwndLB, CFolder* pFgt, int sel, BOOL which)
  1718. {
  1719. if (sel != 0 && sel != 1)
  1720. {
  1721. if (! pFgt->pKid )
  1722. return(0);
  1723. //
  1724. // This is the double click case.
  1725. //
  1726. if ( which ) {
  1727. if( pFgt->f_A_Open )
  1728. pFgt->f_A_Open = FALSE;
  1729. else
  1730. pFgt->f_A_Open = TRUE;
  1731. }
  1732. else
  1733. pFgt->f_F_Open = !pFgt->f_F_Open;
  1734. }
  1735. else
  1736. {
  1737. // This is the +/- case
  1738. //
  1739. // Contraction works a little differently than expansion.
  1740. // For contraction, if the selected node is not expanded, we close
  1741. // it's parent. If it is expanded, we close it.
  1742. //
  1743. if ( !sel ) // if we're doing contraction...
  1744. {
  1745. if ( ! (which ? pFgt->f_A_Open : pFgt->f_F_Open) ) // if node closed...
  1746. {
  1747. if ( pFgt->pParent )
  1748. pFgt = pFgt->pParent;
  1749. }
  1750. }
  1751. if (! pFgt->pKid && pFgt->pParent)
  1752. pFgt = pFgt->pParent;
  1753. if ( which )
  1754. pFgt->f_A_Open = sel;
  1755. else
  1756. pFgt->f_F_Open = sel;
  1757. }
  1758. return (WORD)FillFilterTree(hwndLB, which, sel);
  1759. }
  1760. /*****************************************************************************
  1761. * FillFilterTree()
  1762. *
  1763. * Function actually makes the send message calls to cause a repaint of
  1764. * the listbox identified by hwndLB.
  1765. *
  1766. * ENTRY:
  1767. * hwndLB - Identifies the listbox were working with (it's handle)
  1768. * fAvailable - Which ListBox are we working with: TRUE == Available LB.
  1769. * FALSE == Range LB.
  1770. * fScrollup - If TRUE and a parents children will appear off the bottom
  1771. * of the LB we'll scroll the parent to the top of the LB.
  1772. *
  1773. * EXIT:
  1774. * UINT - Returns the number of items placed in the LB.
  1775. *
  1776. *****************************************************************************/
  1777. UINT CDefineSS::FillFilterTree(HWND hwndLB, BOOL fAvailable, BOOL fScrollup)
  1778. {
  1779. UINT uiRet = 0;
  1780. int n, nVis, top, caret;
  1781. CFolder* pFgtTop, *pFgtCaret, *pFgt, *plFgt;
  1782. RECT rc;
  1783. /*
  1784. * Compute the number of visible lines, get the top and caret indicies.
  1785. */
  1786. GetClientRect(hwndLB,&rc);
  1787. n = (int)SendMessage(hwndLB,LB_GETITEMHEIGHT,0,0L);
  1788. nVis = rc.bottom / n;
  1789. SendMessage(hwndLB,WM_SETREDRAW,FALSE,0L); // Don't re-paint!
  1790. caret = (int)SendMessage(hwndLB,LB_GETCARETINDEX,0,0L);
  1791. top = (int)SendMessage(hwndLB,LB_GETTOPINDEX,0,0L);
  1792. /*
  1793. * Get the items living at the top and the caret position of the listbox.
  1794. */
  1795. if (top == (int)LB_ERR)
  1796. pFgtTop = NULL;
  1797. else
  1798. {
  1799. if ( (pFgtTop=(CFolder*)SendMessage(hwndLB, LB_GETITEMDATA, top, (LPARAM)0)) == (CFolder*)LB_ERR )
  1800. pFgtTop = NULL;
  1801. }
  1802. if (caret == (int)LB_ERR)
  1803. pFgtCaret = NULL;
  1804. else
  1805. {
  1806. if ( (pFgtCaret=(CFolder*)SendMessage(hwndLB, LB_GETITEMDATA, caret, (LPARAM)0)) == (CFolder*)LB_ERR )
  1807. pFgtCaret = NULL;
  1808. }
  1809. /*
  1810. * If the top entry is a child and it's not expanded, set it's parent
  1811. * as the top. ie it's been collapsed.
  1812. */
  1813. if ( pFgtTop && pFgtTop->pParent && !EXPANDED(fAvailable, pFgtTop->pParent) )
  1814. pFgtTop = pFgtTop->pParent;
  1815. /*
  1816. * If the caret position is on a child and it's not expanded, set it's
  1817. * parent as the caret position. ie it's been collapsed.
  1818. */
  1819. if ( pFgtCaret && pFgtCaret->pParent && !EXPANDED(fAvailable, pFgtCaret->pParent) )
  1820. pFgtCaret = pFgtCaret->pParent;
  1821. /*
  1822. * Insure we have not set the top or caret position to a non selected
  1823. * node.
  1824. */
  1825. if ( pFgtTop && !PRESENT(fAvailable,pFgtTop) )
  1826. {
  1827. plFgt = pFgtTop;
  1828. do
  1829. {
  1830. do
  1831. {
  1832. pFgtTop = pFgtTop->pNext;
  1833. } while ( pFgtTop && !PRESENT(fAvailable,pFgtTop) );
  1834. if (! pFgtTop )
  1835. {
  1836. pFgtTop = plFgt->pParent;
  1837. plFgt = pFgtTop;
  1838. }
  1839. else
  1840. break;
  1841. } while ( pFgtTop );
  1842. }
  1843. if ( pFgtCaret && !PRESENT(fAvailable,pFgtCaret) )
  1844. {
  1845. plFgt = pFgtCaret;
  1846. do
  1847. {
  1848. do
  1849. {
  1850. pFgtCaret = pFgtCaret->pNext;
  1851. } while ( pFgtCaret && !PRESENT(fAvailable,pFgtCaret) );
  1852. if (! pFgtCaret )
  1853. {
  1854. pFgtCaret = plFgt->pParent;
  1855. plFgt = pFgtCaret;
  1856. }
  1857. else
  1858. break;
  1859. } while ( pFgtCaret );
  1860. }
  1861. SendMessage(hwndLB,LB_RESETCONTENT,FALSE,0L);
  1862. /*
  1863. * Reset horizontal extent.
  1864. */
  1865. SendMessage(hwndLB, LB_SETHORIZONTALEXTENT, 0, 0L);
  1866. /*
  1867. * Now, add the appropiate items to the list box.
  1868. */
  1869. if ( fAvailable )
  1870. uiRet = AvailableWalk(hwndLB);
  1871. else
  1872. uiRet = FilteredWalk(hwndLB);
  1873. /*
  1874. * Lastly, insure a parent is scrolled to the top of the LB if it's kids
  1875. * have run off of the bottom of the LB.
  1876. */
  1877. if (pFgtTop)
  1878. top = (int)SendMessage(hwndLB,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtTop);
  1879. if (pFgtCaret)
  1880. caret = (int)SendMessage(hwndLB,LB_FINDSTRINGEXACT,0,(LPARAM)pFgtCaret);
  1881. if (!pFgtTop || top == (int)LB_ERR)
  1882. top = 0;
  1883. if (!pFgtCaret || caret == (int)LB_ERR)
  1884. caret = 0;
  1885. if ( fScrollup && pFgtCaret && pFgtCaret->pKid )
  1886. {
  1887. if (caret < top)
  1888. top = caret;
  1889. for (pFgt = pFgtCaret->pKid, n = 1; pFgt; pFgt = pFgt->pNext)
  1890. ++n;
  1891. if (n >= nVis)
  1892. top = caret;
  1893. else if (caret + n > top + nVis)
  1894. top = caret - nVis + n;
  1895. }
  1896. SendMessage(hwndLB, LB_SETTOPINDEX, top, 0L);
  1897. SendMessage(hwndLB, LB_SETCARETINDEX, caret, 0L);
  1898. SendMessage(hwndLB, LB_SETSEL, TRUE, MAKELPARAM(caret,0));
  1899. SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L);
  1900. InvalidateRect(hwndLB, NULL, TRUE);
  1901. return(uiRet);
  1902. }
  1903. /*****************************************************************************
  1904. * FilteredWalk()
  1905. *
  1906. * Helper function called only from FillFilterTree(). This bit of code walks
  1907. * the filter group tree and adds the selected nodes to the listbox given.
  1908. *
  1909. * ENTRY:
  1910. * hwndLB - Handle to the list box to which items are to be added.
  1911. *
  1912. * EXIT:
  1913. * uint - Returns the number of items added to the listbox.
  1914. *
  1915. ****************************************************************************/
  1916. UINT CDefineSS::FilteredWalk(HWND hwndLB)
  1917. {
  1918. CFolder* pFgt;
  1919. CFolder* pFgtLast;
  1920. UINT i = 0;
  1921. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1922. /*
  1923. * Ok, now we actually do all the walking of the filter linked list to
  1924. * re-generate the filter listbox contnets. This must be done in the
  1925. * order in which the items appear in the LB. ie. Depthwise.
  1926. */
  1927. while ( pFgt )
  1928. {
  1929. do
  1930. {
  1931. if ( pFgt->f_Filter && !pFgt->f_IsOrphan )
  1932. {
  1933. SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)pFgt);
  1934. i++;
  1935. }
  1936. pFgtLast = pFgt;
  1937. if ( pFgt->f_F_Open )
  1938. pFgt = pFgt->pKid;
  1939. else
  1940. break;
  1941. } while ( pFgt );
  1942. pFgt = pFgtLast;
  1943. while ( pFgt && (! (pFgt->pNext)) )
  1944. pFgt = pFgt->pParent;
  1945. if ( pFgt )
  1946. pFgt = pFgt->pNext;
  1947. }
  1948. return(i);
  1949. }
  1950. /*****************************************************************************
  1951. * AvailableWalk()
  1952. *
  1953. * Helper function called only from FillFilterTree(). This bit of code walks
  1954. * the filter group tree and adds the selected nodes to the listbox given.
  1955. *
  1956. * ENTRY:
  1957. * hwndLB - Handle to the list box to which items are to be added.
  1958. *
  1959. * EXIT:
  1960. * uint - Returns the number of items added to the listbox.
  1961. *
  1962. ****************************************************************************/
  1963. UINT CDefineSS::AvailableWalk(HWND hwndLB)
  1964. {
  1965. CFolder* pFgt;
  1966. CFolder* pFgtLast;
  1967. UINT i = 0;
  1968. pFgt = m_pCollection->m_Collection.GetVisableRootFolder();
  1969. /*
  1970. * Ok, now we actually do all the walking of the filter linked list to
  1971. * re-generate the filter listbox contnets. This must be done in the
  1972. * order in which the items appear in the LB. ie. Depthwise.
  1973. */
  1974. while ( pFgt )
  1975. {
  1976. do
  1977. {
  1978. if ( pFgt->f_Available && !pFgt->f_IsOrphan )
  1979. {
  1980. SendMessage(hwndLB, LB_ADDSTRING, 0, (LPARAM)pFgt);
  1981. i++;
  1982. }
  1983. pFgtLast = pFgt;
  1984. if ( pFgt->f_A_Open )
  1985. pFgt = pFgt->pKid;
  1986. else
  1987. break;
  1988. } while ( pFgt );
  1989. pFgt = pFgtLast;
  1990. while ( pFgt && (! (pFgt->pNext)) )
  1991. pFgt = pFgt->pParent;
  1992. if ( pFgt )
  1993. pFgt = pFgt->pNext;
  1994. }
  1995. return(i);
  1996. }
  1997. //
  1998. // Change a dialog's default push button
  1999. //
  2000. BOOL CDefineSS::SetDefaultButton( HWND hDlg, int iID, BOOL fFocus )
  2001. {
  2002. BOOL bReturn = FALSE;
  2003. if( hDlg ) {
  2004. // Get the current default push button and reset it.
  2005. ResetDefaultButton( hDlg );
  2006. // Update the default push button's control ID.
  2007. SendMessage( hDlg, DM_SETDEFID, (WPARAM) iID, 0L );
  2008. // Set the new style.
  2009. bReturn = (BOOL) SendDlgItemMessage( hDlg, iID, BM_SETSTYLE, (WPARAM) BS_DEFPUSHBUTTON, (LPARAM) TRUE );
  2010. // Set the focus to the new default push button.
  2011. if( fFocus )
  2012. bReturn &= (SetFocus( GetDlgItem( hDlg, iID ) ) != NULL);
  2013. }
  2014. return( bReturn );
  2015. }
  2016. //
  2017. // Clear the current default button status from the default push button
  2018. //
  2019. void CDefineSS::ResetDefaultButton( HWND hDlg )
  2020. {
  2021. DWORD dwResult;
  2022. if( hDlg ) {
  2023. // Get the current default push button.
  2024. dwResult = (DWORD) SendMessage( hDlg, DM_GETDEFID, 0, 0L );
  2025. // Reset the current default push button to a regular button.
  2026. if( HIWORD(dwResult) == DC_HASDEFID )
  2027. SendDlgItemMessage( hDlg, LOWORD(dwResult), BM_SETSTYLE, (WPARAM) BS_PUSHBUTTON, (LPARAM) TRUE );
  2028. }
  2029. return;
  2030. }