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.

1165 lines
28 KiB

  1. //-------------------------------------------------------------------
  2. //
  3. // File: SelRange.cpp
  4. //
  5. // Contents:
  6. // This file contians Selection Range handling code.
  7. //
  8. //-------------------------------------------------------------------
  9. #include "ctlspriv.h"
  10. #include "selrange.h"
  11. #include "stdio.h"
  12. #include <shguidp.h>
  13. #define MINCOUNT 6 // number of sel ranges to start with amd maintain
  14. #define GROWSIZE 150 // percent to grow when needed
  15. #define COUNT_SELRANGES_NONE 2 // When count of selranges really means none
  16. typedef struct tag_SELRANGEITEM
  17. {
  18. LONG iBegin;
  19. LONG iEnd;
  20. } SELRANGEITEM, *PSELRANGEITEM;
  21. class CLVRange : public ILVRange
  22. {
  23. public:
  24. // *** IUnknown methods ***
  25. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppv);
  26. STDMETHODIMP_(ULONG) AddRef(void);
  27. STDMETHODIMP_(ULONG) Release(void);
  28. // *** ILVRange methods ***
  29. STDMETHODIMP IncludeRange(LONG iBegin, LONG iEnd);
  30. STDMETHODIMP ExcludeRange(LONG iBegin, LONG iEnd);
  31. STDMETHODIMP InvertRange(LONG iBegin, LONG iEnd);
  32. STDMETHODIMP InsertItem(LONG iItem);
  33. STDMETHODIMP RemoveItem(LONG iItem);
  34. STDMETHODIMP Clear();
  35. STDMETHODIMP IsSelected(LONG iItem);
  36. STDMETHODIMP IsEmpty();
  37. STDMETHODIMP NextSelected(LONG iItem, LONG *piItem);
  38. STDMETHODIMP NextUnSelected(LONG iItem, LONG *piItem);
  39. STDMETHODIMP CountIncluded(LONG *pcIncluded);
  40. protected:
  41. // Helper Functions.
  42. friend ILVRange *LVRange_Create();
  43. CLVRange();
  44. ~CLVRange();
  45. BOOL _Enlarge();
  46. BOOL _Shrink();
  47. BOOL _InsertRange(LONG iAfterItem, LONG iBegin, LONG iEnd);
  48. HRESULT _RemoveRanges(LONG iStartItem, LONG iStopItem, LONG *p);
  49. BOOL _FindValue(LONG Value, LONG* piItem);
  50. void _InitNew();
  51. int _cRef;
  52. PSELRANGEITEM _VSelRanges; // Vector of sel ranges
  53. LONG _cSize; // size of above vector in sel ranges
  54. LONG _cSelRanges; // count of sel ranges used
  55. LONG _cIncluded; // Count of Included items...
  56. };
  57. //-------------------------------------------------------------------
  58. //
  59. // Function: _Enlarge
  60. //
  61. // Summary:
  62. // This will enlarge the number of items the Sel Range can have.
  63. //
  64. // Arguments:
  65. // PSELRANGE [in] - SelRange to Enlarge
  66. //
  67. // Return: FALSE if failed.
  68. //
  69. // Notes: Though this function may fail, pselrange structure is still valid
  70. //
  71. // History:
  72. // 17-Oct-94 MikeMi Created
  73. //
  74. //-------------------------------------------------------------------
  75. BOOL CLVRange::_Enlarge()
  76. {
  77. LONG cNewSize;
  78. PSELRANGEITEM pTempSelRange;
  79. BOOL frt = FALSE;
  80. cNewSize = _cSize * GROWSIZE / 100;
  81. pTempSelRange = (PSELRANGEITEM) GlobalReAlloc( (HGLOBAL)_VSelRanges,
  82. cNewSize * sizeof( SELRANGEITEM ),
  83. GMEM_ZEROINIT | GMEM_MOVEABLE );
  84. if (NULL != pTempSelRange)
  85. {
  86. _VSelRanges = pTempSelRange;
  87. _cSize = cNewSize;
  88. frt = TRUE;
  89. }
  90. return( frt );
  91. }
  92. //-------------------------------------------------------------------
  93. //
  94. // Function: _Shrink
  95. //
  96. // Summary:
  97. // This will reduce the number of items the Sel Range can have.
  98. //
  99. // Arguments:
  100. //
  101. // Return: FALSE if failed
  102. //
  103. // Notes: Shrink only happens when a significant size below the next size
  104. // is obtained and the new size is at least the minimum size.
  105. // Though this function may fail, pselrange structure is still valid
  106. //
  107. // History:
  108. // 17-Oct-94 MikeMi Created
  109. //
  110. //-------------------------------------------------------------------
  111. BOOL CLVRange::_Shrink()
  112. {
  113. LONG cNewSize;
  114. LONG cTriggerSize;
  115. PSELRANGEITEM pTempSelRange;
  116. BOOL frt = TRUE;
  117. // check if we are below last grow area by a small percent
  118. cTriggerSize = _cSize * 90 / GROWSIZE;
  119. cNewSize = _cSize * 100 / GROWSIZE;
  120. if ((_cSelRanges < cTriggerSize) && (cNewSize >= MINCOUNT))
  121. {
  122. pTempSelRange = (PSELRANGEITEM) GlobalReAlloc( (HGLOBAL)_VSelRanges,
  123. cNewSize * sizeof( SELRANGEITEM ),
  124. GMEM_ZEROINIT | GMEM_MOVEABLE );
  125. if (NULL != pTempSelRange)
  126. {
  127. _VSelRanges = pTempSelRange;
  128. _cSize = cNewSize;
  129. }
  130. else
  131. {
  132. frt = FALSE;
  133. }
  134. }
  135. return( frt );
  136. }
  137. //-------------------------------------------------------------------
  138. //
  139. // Function: _InsertRange
  140. //
  141. // Summary:
  142. // inserts a single range item into the range vector
  143. //
  144. // Arguments:
  145. // iAfterItem [in] - Index to insert range after, -1 means insert as first item
  146. // iBegin [in] - begin of range
  147. // iEnd [in] - end of the range
  148. //
  149. // Return:
  150. // TRUE if succesful, otherwise FALSE
  151. //
  152. // Notes:
  153. //
  154. // History:
  155. // 17-Oct-94 MikeMi Created
  156. //
  157. //-------------------------------------------------------------------
  158. BOOL CLVRange::_InsertRange(LONG iAfterItem,
  159. LONG iBegin,
  160. LONG iEnd )
  161. {
  162. LONG iItem;
  163. BOOL frt = TRUE;
  164. ASSERT( iAfterItem >= -1 );
  165. ASSERT( iBegin >= SELRANGE_MINVALUE );
  166. ASSERT( iEnd >= iBegin );
  167. ASSERT( iEnd <= SELRANGE_MAXVALUE );
  168. ASSERT( _cSelRanges < _cSize );
  169. // shift all over one
  170. for (iItem = _cSelRanges; iItem > iAfterItem + 1; iItem--)
  171. {
  172. _VSelRanges[iItem] = _VSelRanges[iItem-1];
  173. }
  174. _cSelRanges++;
  175. // make the insertion
  176. _VSelRanges[iAfterItem+1].iBegin = iBegin;
  177. _VSelRanges[iAfterItem+1].iEnd = iEnd;
  178. // make sure we have room next time
  179. if (_cSelRanges == _cSize)
  180. {
  181. frt = _Enlarge();
  182. }
  183. return( frt );
  184. }
  185. //-------------------------------------------------------------------
  186. //
  187. // Function: _RemoveRanges
  188. //
  189. // Summary:
  190. // Removes all ranged between and including the speicifed indexes
  191. //
  192. // Arguments:
  193. // iStartItem [in] - Index to start removal
  194. // iStopItem [in] - Index to stop removal
  195. //
  196. // Return:
  197. // SELRANGE_ERROR on memory allocation error
  198. // The number of items that are unselected by this removal
  199. //
  200. // Notes:
  201. //
  202. // History:
  203. // 17-Oct-94 MikeMi Created
  204. //
  205. //-------------------------------------------------------------------
  206. HRESULT CLVRange::_RemoveRanges(LONG iStartItem, LONG iStopItem, LONG *pc )
  207. {
  208. LONG iItem;
  209. LONG diff;
  210. LONG cUnSelected = 0;
  211. HRESULT hres = S_OK;
  212. ASSERT( iStartItem > 0 );
  213. ASSERT( iStopItem >= iStartItem );
  214. ASSERT( iStartItem < _cSelRanges - 1 );
  215. ASSERT( iStopItem < _cSelRanges - 1 );
  216. diff = iStopItem - iStartItem + 1;
  217. for (iItem = iStartItem; iItem <= iStopItem; iItem++)
  218. cUnSelected += _VSelRanges[iItem].iEnd -
  219. _VSelRanges[iItem].iBegin + 1;
  220. // shift all over the difference
  221. for (iItem = iStopItem+1; iItem < _cSelRanges; iItem++, iStartItem++)
  222. _VSelRanges[iStartItem] = _VSelRanges[iItem];
  223. _cSelRanges -= diff;
  224. if (!_Shrink())
  225. {
  226. hres = E_FAIL;
  227. }
  228. else if (pc)
  229. *pc = cUnSelected;
  230. return( hres );
  231. }
  232. //-------------------------------------------------------------------
  233. //
  234. // Function: SelRange_FindValue
  235. //
  236. // Summary:
  237. // This function will search the ranges for the value, returning true
  238. // if the value was found within a range. The piItem will contain the
  239. // the index at which it was found or the index before where it should be
  240. // The piItem may be set to -1, meaning that there are no ranges in the list
  241. // This functions uses a non-recursive binary search algorithm.
  242. //
  243. // Arguments:
  244. // piItem [out] - Return of found range index, or one before
  245. // Value [in] - Value to find within a range
  246. //
  247. // Return: True if found, False if not found
  248. //
  249. // Notes: The piItem will return one before if return is false.
  250. //
  251. // History:
  252. // 14-Oct-94 MikeMi Created
  253. //
  254. //-------------------------------------------------------------------
  255. BOOL CLVRange::_FindValue(LONG Value, LONG* piItem )
  256. {
  257. LONG First;
  258. LONG Last;
  259. LONG Item;
  260. BOOL fFound = FALSE;
  261. ASSERT( piItem );
  262. ASSERT( _cSize >= COUNT_SELRANGES_NONE );
  263. ASSERT( Value >= SELRANGE_MINVALUE );
  264. ASSERT( Value <= SELRANGE_MAXVALUE );
  265. First = 0;
  266. Last = _cSelRanges - 1;
  267. Item = Last / 2;
  268. do
  269. {
  270. if (_VSelRanges[Item].iBegin > Value)
  271. { // Value before this Item
  272. Last = Item;
  273. Item = (Last - First) / 2 + First;
  274. if (Item == Last)
  275. {
  276. Item = First;
  277. break;
  278. }
  279. }
  280. else if (_VSelRanges[Item].iEnd < Value)
  281. { // Value after this Item
  282. First = Item;
  283. Item = (Last - First) / 2 + First;
  284. if (Item == First)
  285. {
  286. break;
  287. }
  288. }
  289. else
  290. { // Value at this Item
  291. fFound = TRUE;
  292. }
  293. } while (!fFound);
  294. *piItem = Item;
  295. return( fFound );
  296. }
  297. //-------------------------------------------------------------------
  298. //
  299. // Function: _InitNew
  300. //
  301. // Summary:
  302. // This function will initialize a SelRange object.
  303. //
  304. // Arguments:
  305. //
  306. // Return:
  307. //
  308. // Notes:
  309. //
  310. // History:
  311. // 18-Oct-94 MikeMi Created
  312. //
  313. //-------------------------------------------------------------------
  314. void CLVRange::_InitNew()
  315. {
  316. _cSize = MINCOUNT;
  317. _cSelRanges = COUNT_SELRANGES_NONE;
  318. _VSelRanges[0].iBegin = LONG_MIN;
  319. // -2 and +2 below are to stop consecutive joining of end markers
  320. _VSelRanges[0].iEnd = SELRANGE_MINVALUE - 2;
  321. _VSelRanges[1].iBegin = SELRANGE_MAXVALUE + 2;
  322. _VSelRanges[1].iEnd = SELRANGE_MAXVALUE + 2;
  323. _cIncluded = 0;
  324. }
  325. //-------------------------------------------------------------------
  326. //
  327. // Function: SelRange_Create
  328. //
  329. // Summary:
  330. // This function will create and initialize a SelRange object.
  331. //
  332. // Arguments:
  333. //
  334. // Return: HSELRANGE that is created or NULL if it failed.
  335. //
  336. // Notes:
  337. //
  338. // History:
  339. // 14-Oct-94 MikeMi Created
  340. //
  341. //-------------------------------------------------------------------
  342. ILVRange *LVRange_Create( )
  343. {
  344. CLVRange *pselrange = new CLVRange;
  345. if (NULL != pselrange)
  346. {
  347. pselrange->_VSelRanges = (PSELRANGEITEM) GlobalAlloc( GPTR,
  348. sizeof( SELRANGEITEM ) * MINCOUNT );
  349. if (NULL != pselrange->_VSelRanges)
  350. {
  351. pselrange->_InitNew();
  352. }
  353. else
  354. {
  355. delete pselrange;
  356. pselrange = NULL;
  357. }
  358. }
  359. return( pselrange? SAFECAST(pselrange, ILVRange*) : NULL);
  360. }
  361. //-------------------------------------------------------------------
  362. //
  363. // Function: Constructor
  364. //
  365. //-------------------------------------------------------------------
  366. CLVRange::CLVRange()
  367. {
  368. _cRef = 1;
  369. }
  370. //-------------------------------------------------------------------
  371. //
  372. // Function: Destructor
  373. //
  374. //-------------------------------------------------------------------
  375. CLVRange::~CLVRange()
  376. {
  377. GlobalFree( _VSelRanges );
  378. }
  379. //-------------------------------------------------------------------
  380. //
  381. // Function: QueryInterface
  382. //
  383. //-------------------------------------------------------------------
  384. HRESULT CLVRange::QueryInterface(REFIID iid, void **ppv)
  385. {
  386. if (IsEqualIID(iid, IID_ILVRange) || IsEqualIID(iid, IID_IUnknown))
  387. {
  388. *ppv = SAFECAST(this, ILVRange *);
  389. }
  390. else
  391. {
  392. *ppv = NULL;
  393. return E_NOINTERFACE;
  394. }
  395. _cRef++;
  396. return NOERROR;
  397. }
  398. //-------------------------------------------------------------------
  399. //
  400. // Function: AddRef
  401. //
  402. //-------------------------------------------------------------------
  403. ULONG CLVRange::AddRef()
  404. {
  405. return ++_cRef;
  406. }
  407. //-------------------------------------------------------------------
  408. //
  409. // Function: Release
  410. //
  411. //-------------------------------------------------------------------
  412. ULONG CLVRange::Release()
  413. {
  414. if (--_cRef)
  415. return _cRef;
  416. delete this;
  417. return 0;
  418. }
  419. //-------------------------------------------------------------------
  420. //
  421. // Function: IncludeRange
  422. //
  423. // Summary:
  424. // This function will include the range defined into the current
  425. // ranges, compacting as needed.
  426. //
  427. // Arguments:
  428. // hselrange [in] - Handle to the SelRange
  429. // iBegin [in] - Begin of new range
  430. // iEnd [in] - End of new range
  431. //
  432. // Notes:
  433. //
  434. // History:
  435. // 14-Oct-94 MikeMi Created
  436. //
  437. //-------------------------------------------------------------------
  438. HRESULT CLVRange::IncludeRange(LONG iBegin, LONG iEnd )
  439. {
  440. LONG iFirst; // index before or contains iBegin value
  441. LONG iLast; // index before or contains iEnd value
  442. BOOL fExtendFirst; // do we extend the iFirst or create one after it
  443. LONG iRemoveStart; // start of ranges that need to be removed
  444. LONG iRemoveFinish; // end of ranges that need to be removed
  445. LONG iNewEnd; // calculate new end value as we go
  446. BOOL fEndFound; // was the iEnd found in a range already
  447. BOOL fBeginFound; // was the iEnd found in a range already
  448. LONG cSelected = 0;
  449. HRESULT hres = S_OK;
  450. ASSERT( iEnd >= iBegin );
  451. ASSERT( iBegin >= SELRANGE_MINVALUE );
  452. ASSERT( iEnd <= SELRANGE_MAXVALUE );
  453. // find approximate locations
  454. fBeginFound = _FindValue( iBegin, &iFirst );
  455. fEndFound = _FindValue( iEnd, &iLast );
  456. //
  457. // Find First values
  458. //
  459. // check for consecutive End-First values
  460. if ((_VSelRanges[iFirst].iEnd == iBegin - 1) ||
  461. (fBeginFound))
  462. {
  463. // extend iFirst
  464. fExtendFirst = TRUE;
  465. iRemoveStart = iFirst + 1;
  466. }
  467. else
  468. {
  469. // create one after the iFirst
  470. fExtendFirst = FALSE;
  471. iRemoveStart = iFirst + 2;
  472. }
  473. //
  474. // Find Last values
  475. //
  476. if (fEndFound)
  477. {
  478. // Use [iLast].iEnd value
  479. iRemoveFinish = iLast;
  480. iNewEnd = _VSelRanges[iLast].iEnd;
  481. }
  482. else
  483. {
  484. // check for consecutive First-End values
  485. if (_VSelRanges[iLast + 1].iBegin == iEnd + 1)
  486. {
  487. // Use [iLast + 1].iEnd value
  488. iNewEnd = _VSelRanges[iLast+1].iEnd;
  489. iRemoveFinish = iLast + 1;
  490. }
  491. else
  492. {
  493. // Use iEnd value
  494. iRemoveFinish = iLast;
  495. iNewEnd = iEnd;
  496. }
  497. }
  498. //
  499. // remove condenced items if needed
  500. //
  501. if (iRemoveStart <= iRemoveFinish)
  502. {
  503. LONG cChange;
  504. hres = _RemoveRanges(iRemoveStart, iRemoveFinish, &cChange );
  505. if (FAILED(hres))
  506. return hres;
  507. else
  508. {
  509. cSelected -= cChange;
  510. }
  511. }
  512. //
  513. // insert item and reset values as needed
  514. //
  515. if (fExtendFirst)
  516. {
  517. cSelected += iNewEnd - _VSelRanges[iFirst].iEnd;
  518. _VSelRanges[iFirst].iEnd = iNewEnd;
  519. }
  520. else
  521. {
  522. if (iRemoveStart > iRemoveFinish + 1)
  523. {
  524. cSelected += iEnd - iBegin + 1;
  525. // create one
  526. if (!_InsertRange(iFirst, iBegin, iNewEnd ))
  527. {
  528. hres = E_FAIL;
  529. }
  530. }
  531. else
  532. {
  533. cSelected += iNewEnd - _VSelRanges[iFirst+1].iEnd;
  534. cSelected += _VSelRanges[iFirst+1].iBegin - iBegin;
  535. // no need to create one since the Removal would have left us one
  536. _VSelRanges[iFirst+1].iEnd = iNewEnd;
  537. _VSelRanges[iFirst+1].iBegin = iBegin;
  538. }
  539. }
  540. _cIncluded += cSelected;
  541. return( hres );
  542. }
  543. //-------------------------------------------------------------------
  544. //
  545. // Function: SelRange_ExcludeRange
  546. //
  547. // Summary:
  548. // This function will exclude the range defined from the current
  549. // ranges, compacting and enlarging as needed.
  550. //
  551. // Arguments:
  552. // hselrange [in] - Handle to the SelRange
  553. // iBegin [in] - Begin of range to remove
  554. // iEnd [in] - End of range to remove
  555. //
  556. // Return:
  557. // SELRANGE_ERROR if memory allocation error
  558. // the number actual items that changed state
  559. //
  560. // Notes:
  561. //
  562. // History:
  563. // 17-Oct-94 MikeMi Created
  564. //
  565. //-------------------------------------------------------------------
  566. HRESULT CLVRange::ExcludeRange( LONG iBegin, LONG iEnd )
  567. {
  568. LONG iFirst; // index before or contains iBegin value
  569. LONG iLast; // index before or contains iEnd value
  570. LONG iRemoveStart; // start of ranges that need to be removed
  571. LONG iRemoveFinish; // end of ranges that need to be removed
  572. LONG iFirstNewEnd; // calculate new end value as we go
  573. BOOL fBeginFound; // was the iBegin found in a range already
  574. BOOL fEndFound; // was the iEnd found in a range already
  575. LONG cUnSelected = 0;
  576. HRESULT hres = S_OK;
  577. ASSERT( iEnd >= iBegin );
  578. ASSERT( iBegin >= SELRANGE_MINVALUE );
  579. ASSERT( iEnd <= SELRANGE_MAXVALUE );
  580. // find approximate locations
  581. fBeginFound = _FindValue( iBegin, &iFirst );
  582. fEndFound = _FindValue( iEnd, &iLast );
  583. //
  584. // Find First values
  585. //
  586. // start removal after first
  587. iRemoveStart = iFirst + 1;
  588. // save FirstEnd as we may need to modify it
  589. iFirstNewEnd = _VSelRanges[iFirst].iEnd;
  590. if (fBeginFound)
  591. {
  592. // check for complete removal of first
  593. // (first is a single selection or match?)
  594. if (_VSelRanges[iFirst].iBegin == iBegin)
  595. {
  596. iRemoveStart = iFirst;
  597. }
  598. else
  599. {
  600. // otherwise truncate iFirst
  601. iFirstNewEnd = iBegin - 1;
  602. }
  603. }
  604. //
  605. // Find Last values
  606. //
  607. // end removal on last
  608. iRemoveFinish = iLast;
  609. if (fEndFound)
  610. {
  611. // check for complete removal of last
  612. // (first/last is a single selection or match?)
  613. if (_VSelRanges[iLast].iEnd != iEnd)
  614. {
  615. if (iFirst == iLast)
  616. {
  617. // split
  618. if (!_InsertRange(iFirst, iEnd + 1, _VSelRanges[iFirst].iEnd ))
  619. {
  620. return( E_FAIL );
  621. }
  622. cUnSelected -= _VSelRanges[iFirst].iEnd - iEnd;
  623. }
  624. else
  625. {
  626. // truncate Last
  627. iRemoveFinish = iLast - 1;
  628. cUnSelected += (iEnd + 1) - _VSelRanges[iLast].iBegin;
  629. _VSelRanges[iLast].iBegin = iEnd + 1;
  630. }
  631. }
  632. }
  633. // Now set the new end, since Last code may have needed the original values
  634. cUnSelected -= iFirstNewEnd - _VSelRanges[iFirst].iEnd;
  635. _VSelRanges[iFirst].iEnd = iFirstNewEnd;
  636. //
  637. // remove items if needed
  638. //
  639. if (iRemoveStart <= iRemoveFinish)
  640. {
  641. LONG cChange;
  642. if (SUCCEEDED(hres = _RemoveRanges(iRemoveStart, iRemoveFinish, &cChange )))
  643. cUnSelected += cChange;
  644. }
  645. _cIncluded -= cUnSelected;
  646. return( hres );
  647. }
  648. //-------------------------------------------------------------------
  649. //
  650. // Function: SelRange_Clear
  651. //
  652. // Summary:
  653. // This function will remove all ranges within the SelRange object.
  654. //
  655. // Arguments:
  656. // hselrange [in] - the hselrange object to clear
  657. //
  658. // Return: FALSE if failed.
  659. //
  660. // Notes:
  661. // This function may return FALSE on memory allocation problems, but
  662. // will leave the SelRange object in the last state before this call.
  663. //
  664. // History:
  665. // 14-Oct-94 MikeMi Created
  666. //
  667. //-------------------------------------------------------------------
  668. HRESULT CLVRange::Clear()
  669. {
  670. PSELRANGEITEM pNewItems;
  671. HRESULT hres = S_OK;
  672. pNewItems = (PSELRANGEITEM) GlobalAlloc( GPTR,
  673. sizeof( SELRANGEITEM ) * MINCOUNT );
  674. if (NULL != pNewItems)
  675. {
  676. GlobalFree( _VSelRanges );
  677. _VSelRanges = pNewItems;
  678. _InitNew();
  679. }
  680. else
  681. {
  682. hres = E_FAIL;
  683. }
  684. return( hres );
  685. }
  686. //-------------------------------------------------------------------
  687. //
  688. // Function: SelRange_IsSelected
  689. //
  690. // Summary:
  691. // This function will return if the value iItem is within a
  692. // selected range.
  693. //
  694. // Arguments:
  695. // hselrange [in] - the hselrange object to use
  696. // iItem [in] - value to check for
  697. //
  698. // Return: TRUE if selected, FALSE if not.
  699. //
  700. // Notes:
  701. //
  702. // History:
  703. // 17-Oct-94 MikeMi Created
  704. //
  705. //-------------------------------------------------------------------
  706. HRESULT CLVRange::IsSelected( LONG iItem )
  707. {
  708. LONG iFirst;
  709. ASSERT( iItem >= 0 );
  710. ASSERT( iItem <= SELRANGE_MAXVALUE );
  711. return( _FindValue( iItem, &iFirst ) ? S_OK : S_FALSE);
  712. }
  713. //-------------------------------------------------------------------
  714. //
  715. // Function: SelRange_IsEmpty
  716. //
  717. // Summary:
  718. // This function will return TRUE if the range is empty
  719. //
  720. // Arguments:
  721. // hselrange [in] - the hselrange object to use
  722. //
  723. // Return: TRUE if empty
  724. //
  725. // Notes:
  726. //
  727. // History:
  728. //
  729. //-------------------------------------------------------------------
  730. HRESULT CLVRange::IsEmpty()
  731. {
  732. return (_cSelRanges == COUNT_SELRANGES_NONE)? S_OK : S_FALSE;
  733. }
  734. HRESULT CLVRange::CountIncluded(LONG *pcIncluded)
  735. {
  736. *pcIncluded = _cIncluded;
  737. return S_OK;
  738. }
  739. //-------------------------------------------------------------------
  740. //
  741. // Function: SelRange_InsertItem
  742. //
  743. // Summary:
  744. // This function will insert a unselected item at the location,
  745. // which will push all selections up one index.
  746. //
  747. // Arguments:
  748. // hselrange [in] - the hselrange object to use
  749. // iItem [in] - value to check for
  750. //
  751. // Return:
  752. // False on memory allocation error
  753. // otherwise TRUE
  754. //
  755. // Notes:
  756. //
  757. // History:
  758. // 20-Dec-94 MikeMi Created
  759. //
  760. //-------------------------------------------------------------------
  761. HRESULT CLVRange::InsertItem( LONG iItem )
  762. {
  763. LONG iFirst;
  764. LONG i;
  765. LONG iBegin;
  766. LONG iEnd;
  767. ASSERT( iItem >= 0 );
  768. ASSERT( iItem <= SELRANGE_MAXVALUE );
  769. if (_FindValue( iItem, &iFirst ) )
  770. {
  771. // split it
  772. if ( _VSelRanges[iFirst].iBegin == iItem )
  773. {
  774. // but don't split if starts with value
  775. iFirst--;
  776. }
  777. else
  778. {
  779. if (!_InsertRange(iFirst, iItem, _VSelRanges[iFirst].iEnd ))
  780. {
  781. return( E_FAIL );
  782. }
  783. _VSelRanges[iFirst].iEnd = iItem - 1;
  784. }
  785. }
  786. // now walk all ranges past iFirst, incrementing all values by one
  787. for (i = _cSelRanges-2; i > iFirst; i--)
  788. {
  789. iBegin = _VSelRanges[i].iBegin;
  790. iEnd = _VSelRanges[i].iEnd;
  791. iBegin = min( SELRANGE_MAXVALUE, iBegin + 1 );
  792. iEnd = min( SELRANGE_MAXVALUE, iEnd + 1 );
  793. _VSelRanges[i].iBegin = iBegin;
  794. _VSelRanges[i].iEnd = iEnd;
  795. }
  796. return( S_OK );
  797. }
  798. //-------------------------------------------------------------------
  799. //
  800. // Function: SelRange_RemoveItem
  801. //
  802. // Summary:
  803. // This function will remove an item at the location,
  804. // which will pull all selections down one index.
  805. //
  806. // Arguments:
  807. // hselrange [in] - the hselrange object to use
  808. // iItem [in] - value to check for
  809. // pfWasSelected [out] - was the removed item selected before the removal
  810. //
  811. // Return:
  812. // TRUE if the item was removed
  813. // FALSE if the an error happend
  814. //
  815. // Notes:
  816. //
  817. // History:
  818. // 20-Dec-94 MikeMi Created
  819. //
  820. //-------------------------------------------------------------------
  821. HRESULT CLVRange::RemoveItem(LONG iItem )
  822. {
  823. LONG iFirst;
  824. LONG i;
  825. LONG iBegin;
  826. LONG iEnd;
  827. HRESULT hres = S_OK;
  828. ASSERT( iItem >= SELRANGE_MINVALUE );
  829. ASSERT( iItem <= SELRANGE_MAXVALUE );
  830. if (_FindValue( iItem, &iFirst ) )
  831. {
  832. // item within, change the end value
  833. iEnd = _VSelRanges[iFirst].iEnd;
  834. iEnd = min( SELRANGE_MAXVALUE, iEnd - 1 );
  835. _VSelRanges[iFirst].iEnd = iEnd;
  836. _cIncluded--;
  837. }
  838. else
  839. {
  840. // check for merge situation
  841. if ((iFirst < _cSelRanges - 1) &&
  842. (_VSelRanges[iFirst].iEnd == iItem - 1) &&
  843. (_VSelRanges[iFirst+1].iBegin == iItem + 1))
  844. {
  845. _VSelRanges[iFirst].iEnd =
  846. _VSelRanges[iFirst + 1].iEnd - 1;
  847. if (FAILED(hres = _RemoveRanges(iFirst + 1, iFirst + 1, NULL )))
  848. return( hres );
  849. }
  850. }
  851. // now walk all ranges past iFirst, decrementing all values by one
  852. for (i = _cSelRanges-2; i > iFirst; i--)
  853. {
  854. iBegin = _VSelRanges[i].iBegin;
  855. iEnd = _VSelRanges[i].iEnd;
  856. iBegin = min( SELRANGE_MAXVALUE, iBegin - 1 );
  857. iEnd = min( SELRANGE_MAXVALUE, iEnd - 1 );
  858. _VSelRanges[i].iBegin = iBegin;
  859. _VSelRanges[i].iEnd = iEnd;
  860. }
  861. return( hres );
  862. }
  863. //-------------------------------------------------------------------
  864. //
  865. // Function: NextSelected
  866. //
  867. // Summary:
  868. // This function will start with given item and find the next
  869. // item that is selected. If the given item is selected, that
  870. // item number will be returned.
  871. //
  872. // Arguments:
  873. // hselrange [in] - the hselrange object to use
  874. // iItem [in] - value to start check at
  875. //
  876. // Return:
  877. // -1 if none found, otherwise the item
  878. //
  879. // Notes:
  880. //
  881. // History:
  882. // 04-Jan-95 MikeMi Created
  883. //
  884. //-------------------------------------------------------------------
  885. HRESULT CLVRange::NextSelected( LONG iItem, LONG *piItem )
  886. {
  887. LONG i;
  888. ASSERT( iItem >= SELRANGE_MINVALUE );
  889. ASSERT( iItem <= SELRANGE_MAXVALUE );
  890. if (!_FindValue( iItem, &i ) )
  891. {
  892. i++;
  893. if (i < _cSelRanges-1)
  894. {
  895. iItem = _VSelRanges[i].iBegin;
  896. }
  897. else
  898. {
  899. iItem = -1;
  900. }
  901. }
  902. ASSERT( iItem >= -1 );
  903. ASSERT( iItem <= SELRANGE_MAXVALUE );
  904. *piItem = iItem;
  905. return S_OK;
  906. }
  907. //-------------------------------------------------------------------
  908. //
  909. // Function: NextUnSelected
  910. //
  911. // Summary:
  912. // This function will start with given item and find the next
  913. // item that is not selected. If the given item is not selected, that
  914. // item number will be returned.
  915. //
  916. // Arguments:
  917. // hselrange [in] - the hselrange object to use
  918. // iItem [in] - value to start check at
  919. //
  920. // Return:
  921. // -1 if none found, otherwise the item
  922. //
  923. // Notes:
  924. //
  925. // History:
  926. // 04-Jan-95 MikeMi Created
  927. //
  928. //-------------------------------------------------------------------
  929. HRESULT CLVRange::NextUnSelected( LONG iItem, LONG *piItem )
  930. {
  931. LONG i;
  932. ASSERT( iItem >= SELRANGE_MINVALUE );
  933. ASSERT( iItem <= SELRANGE_MAXVALUE );
  934. if (_FindValue( iItem, &i ) )
  935. {
  936. if (i < _cSelRanges-1)
  937. {
  938. iItem = _VSelRanges[i].iEnd + 1;
  939. if (iItem > SELRANGE_MAXVALUE)
  940. {
  941. iItem = -1;
  942. }
  943. }
  944. else
  945. {
  946. iItem = -1;
  947. }
  948. }
  949. ASSERT( iItem >= -1 );
  950. ASSERT( iItem <= SELRANGE_MAXVALUE );
  951. *piItem = iItem;
  952. return S_OK;
  953. }
  954. //-------------------------------------------------------------------
  955. //
  956. // Function: InvertRange
  957. //
  958. // Summary:
  959. // This function will invert the range defined from the current
  960. // ranges, compacting and enlarging as needed.
  961. //
  962. // Arguments:
  963. // iBegin [in] - Begin of range to invert
  964. // iEnd [in] - End of range to invert
  965. //
  966. // Return:
  967. // SELRANGE_ERROR on memory error
  968. // The difference in items selected from previous to current.
  969. // negative values means less items are selected in that range now.
  970. //
  971. // Notes:
  972. //
  973. // History:
  974. // 13-Dec-95 MikeMi Created
  975. //
  976. //-------------------------------------------------------------------
  977. LONG CLVRange::InvertRange( LONG iBegin, LONG iEnd )
  978. {
  979. LONG iFirst; // index before or contains iBegin value
  980. BOOL fSelect; // are we selecting or unselecting
  981. LONG iTempE;
  982. LONG iTempB;
  983. HRESULT hres = S_OK;
  984. ASSERT( iEnd >= iBegin );
  985. ASSERT( iBegin >= SELRANGE_MINVALUE );
  986. ASSERT( iEnd <= SELRANGE_MAXVALUE );
  987. // find if first is selected or not
  988. fSelect = !_FindValue( iBegin, &iFirst );
  989. iTempE = iBegin - 1;
  990. do
  991. {
  992. iTempB = iTempE + 1;
  993. if (fSelect)
  994. NextSelected( iTempB, &iTempE );
  995. else
  996. NextUnSelected( iTempB, &iTempE );
  997. if (-1 == iTempE)
  998. {
  999. iTempE = SELRANGE_MAXVALUE;
  1000. }
  1001. else
  1002. {
  1003. iTempE--;
  1004. }
  1005. iTempE = min( iTempE, iEnd );
  1006. if (fSelect)
  1007. {
  1008. if (FAILED(hres = IncludeRange( iTempB, iTempE )))
  1009. {
  1010. return( hres );
  1011. }
  1012. }
  1013. else
  1014. {
  1015. if (FAILED(hres = ExcludeRange( iTempB, iTempE )))
  1016. {
  1017. return( hres );
  1018. }
  1019. }
  1020. fSelect = !fSelect;
  1021. } while (iTempE < iEnd );
  1022. return( hres );
  1023. }