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.

437 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. //
  6. // File: winsplit.cxx
  7. //
  8. // Contents: Contains the code to do a window split.
  9. //
  10. // Classes: CTableWindowSplit
  11. //
  12. // Functions:
  13. //
  14. // History: 1-08-95 srikants Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "pch.cxx"
  18. #pragma hdrstop
  19. #include "winsplit.hxx"
  20. #include "tabledbg.hxx"
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Function: CTableWindowSplit ~ctor
  24. //
  25. // Synopsis: Constructor for the CTableWindowSplit class.
  26. //
  27. // Arguments: [srcWindow] - The source window that needs to be
  28. // split
  29. // [iSplitVisibleRowIndex] - Index in the source window's visible
  30. // row index which is the split index. All rows <=
  31. // iSplitVisibleRowIndex will be in the left hand window and the rest
  32. // in the right hand window after the split.
  33. //
  34. // History: 1-09-95 srikants Created
  35. //
  36. // Notes:
  37. //
  38. //----------------------------------------------------------------------------
  39. CTableWindowSplit::CTableWindowSplit( CTableWindow & srcWindow,
  40. ULONG iSplitQueryRowIndex,
  41. ULONG segIdLeft, ULONG segIdRight,
  42. BOOL fIsLastSegment )
  43. : _srcWindow(srcWindow),
  44. _pLeftWindow(0),
  45. _pRightWindow(0),
  46. _srcQueryRowIndex(srcWindow._GetInvisibleRowIndex()),
  47. _srcClientRowIndex(srcWindow._GetVisibleRowIndex()),
  48. _iSplitQueryRowIndex(iSplitQueryRowIndex),
  49. _iSplitClientRowIndex(-1),
  50. _segIdLeft(segIdLeft), _segIdRight(segIdRight),
  51. _fIsLastSegment(fIsLastSegment)
  52. {
  53. Win4Assert( _srcQueryRowIndex.RowCount() >= 2 );
  54. Win4Assert( iSplitQueryRowIndex < _srcQueryRowIndex.RowCount()-1 );
  55. if ( _srcWindow.IsWatched() )
  56. {
  57. //
  58. // The source window has watch regions. The dynamic rowindex must
  59. // also be split.
  60. //
  61. TBL_OFF oQuerySplitRow = _srcQueryRowIndex.GetRow( iSplitQueryRowIndex );
  62. _iSplitClientRowIndex = _srcClientRowIndex.FindSplitPoint( oQuerySplitRow )-1;
  63. }
  64. }
  65. //+---------------------------------------------------------------------------
  66. //
  67. // Function: ~CTableWindowSplit ~dtor for the CTableWindowSplit class
  68. //
  69. // Synopsis: Frees up the resources
  70. //
  71. // History: 1-09-95 srikants Created
  72. //
  73. // Notes:
  74. //
  75. //----------------------------------------------------------------------------
  76. CTableWindowSplit::~CTableWindowSplit()
  77. {
  78. delete _pLeftWindow;
  79. delete _pRightWindow;
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Function: CreateTargetWindows
  84. //
  85. // Synopsis: Creates the target windows and initializes their
  86. // notification region based on the source window notification
  87. // region.
  88. //
  89. // History: 1-09-95 srikants Created
  90. //
  91. // Notes:
  92. //
  93. //----------------------------------------------------------------------------
  94. void CTableWindowSplit::CreateTargetWindows()
  95. {
  96. //
  97. // First create the left and right windows
  98. //
  99. Win4Assert( 0 == _pLeftWindow );
  100. Win4Assert( 0 == _pRightWindow );
  101. _pLeftWindow = new CTableWindow( _srcWindow, _segIdLeft );
  102. _pRightWindow = new CTableWindow( _srcWindow, _segIdRight );
  103. }
  104. //+---------------------------------------------------------------------------
  105. //
  106. // Function: TransferTargetWindows
  107. //
  108. // Synopsis: Transfers the control of the target windows to the caller.
  109. //
  110. // Arguments: [ppLeftWindow] - (output) The pointer to the left window.
  111. // [ppRightWindow] - (output) The pointer to the right window.
  112. //
  113. // History: 1-09-95 srikants Created
  114. //
  115. // Notes:
  116. //
  117. //----------------------------------------------------------------------------
  118. void CTableWindowSplit::TransferTargetWindows( CTableWindow ** ppLeftWindow,
  119. CTableWindow ** ppRightWindow )
  120. {
  121. Win4Assert( 0 != ppLeftWindow && 0 != ppRightWindow );
  122. *ppLeftWindow = _pLeftWindow;
  123. _pLeftWindow = 0;
  124. *ppRightWindow = _pRightWindow;
  125. _pRightWindow = 0;
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Function: _CopyWithoutNotifications
  130. //
  131. // Synopsis: Copies rows from the source window to the destination window. Only
  132. // the rows in the "srcRowIndex" will be copied to the
  133. // destination.
  134. //
  135. // Arguments: [destWindow] - Target window to copy to.
  136. // [srcRowIndex] - The source row index.
  137. // [iStartRowIndex] - Starting offset in the row index to start
  138. // copying rows from.
  139. // [iEndRowIndex] - Ending offset in the row index to stop
  140. // copying.
  141. //
  142. // History: 1-09-95 srikants Created
  143. //
  144. // Notes:
  145. //
  146. //----------------------------------------------------------------------------
  147. void CTableWindowSplit::_CopyWithoutNotifications( CTableWindow & destWindow,
  148. CRowIndex & srcRowIndex,
  149. ULONG iStartRowIndex, ULONG iEndRowIndex )
  150. {
  151. Win4Assert( iEndRowIndex < srcRowIndex.RowCount() );
  152. for ( ULONG i = iStartRowIndex; i <= iEndRowIndex; i++ )
  153. {
  154. destWindow._PutRowToVisibleRowIndex( _srcWindow, srcRowIndex.GetRow(i) );
  155. }
  156. }
  157. //+---------------------------------------------------------------------------
  158. //
  159. // Function: _SimpleSplit
  160. //
  161. // Synopsis: Does a simple split in which the first half of the rows from
  162. // the source row index will be copied to the left window and the
  163. // second half to the right window.
  164. //
  165. // History: 1-31-95 srikants Created
  166. //
  167. // Notes: This must be called only when there is no notification region
  168. // in the source window.
  169. //
  170. //----------------------------------------------------------------------------
  171. void CTableWindowSplit::_SimpleSplit()
  172. {
  173. Win4Assert( !_srcWindow.IsWatched() );
  174. //
  175. // The source notifcation region is completely empty. We have to copy from
  176. // the visible row index only.
  177. //
  178. tbDebugOut(( DEB_WINSPLIT, "CTableWindowSplit::Simple Split\n" ));
  179. _CopyWithoutNotifications( *_pLeftWindow, _srcQueryRowIndex,
  180. 0, _iSplitQueryRowIndex );
  181. _CopyWithoutNotifications( *_pRightWindow, _srcQueryRowIndex,
  182. _iSplitQueryRowIndex+1,
  183. _srcQueryRowIndex.RowCount()-1 );
  184. }
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Function: DoSplit
  188. //
  189. // Synopsis: Splits the source window into left and right windows.
  190. //
  191. // History: 1-09-95 srikants Created
  192. //
  193. // Notes:
  194. //
  195. //----------------------------------------------------------------------------
  196. void CTableWindowSplit::DoSplit()
  197. {
  198. Win4Assert( 0 != _pLeftWindow && 0 != _pRightWindow );
  199. _pLeftWindow->_SetSplitInProgress();
  200. _pRightWindow->_SetSplitInProgress();
  201. if ( !_srcWindow.IsWatched() )
  202. {
  203. //
  204. // The source notifcation region is completely empty. We have to copy from
  205. // the visible row index only.
  206. //
  207. Win4Assert( -1 == _iSplitClientRowIndex );
  208. _SimpleSplit();
  209. _pLeftWindow->_SetSplitDone();
  210. _pRightWindow->_SetSplitDone();
  211. }
  212. else
  213. {
  214. //
  215. // If notifications are enabled in the target window, then we must copy
  216. // both the client row index and the query row index. O/W, just copy
  217. // the contents of the query row index.
  218. //
  219. //
  220. // Copy the contents to the target left window.
  221. //
  222. tbDebugOut(( DEB_WINSPLIT, "Left Window with Notifications\n" ));
  223. _CopyWithNotifications( *_pLeftWindow, 0, _iSplitQueryRowIndex,
  224. 0, _iSplitClientRowIndex );
  225. //
  226. // Copy the contents to the target right window.
  227. //
  228. tbDebugOut(( DEB_WINSPLIT, "Right Window with Notifications\n" ));
  229. _CopyWithNotifications( *_pRightWindow,
  230. _iSplitQueryRowIndex+1, _srcQueryRowIndex.RowCount()-1,
  231. _iSplitClientRowIndex+1, _srcClientRowIndex.RowCount()-1 );
  232. //
  233. // Now apply the watch regions on the new windows.
  234. //
  235. _CopyWatchRegions();
  236. //
  237. // Indicate that the split is done.
  238. //
  239. _pLeftWindow->_SetSplitDone();
  240. _pRightWindow->_SetSplitDone();
  241. //
  242. // If any of the windows doesn't have any watch regions, we have to
  243. // do a state change to delete the dynamic/static split.
  244. //
  245. Win4Assert( _pLeftWindow->IsWatched() || _pRightWindow->IsWatched() );
  246. if ( !_pLeftWindow->IsWatched() )
  247. {
  248. _pLeftWindow->_EndStaticDynamicSplit();
  249. }
  250. if ( !_pRightWindow->IsWatched() )
  251. {
  252. _pRightWindow->_EndStaticDynamicSplit();
  253. }
  254. }
  255. //
  256. // Setup the lowest & highest keys for the left and right windows.
  257. //
  258. _srcWindow.GetSortKey( 0, _pLeftWindow->GetLowestKey() );
  259. _srcWindow.GetSortKey( _iSplitQueryRowIndex+1, _pRightWindow->GetLowestKey() );
  260. _srcWindow.GetSortKey( _iSplitQueryRowIndex, _pLeftWindow->GetHighestKey() );
  261. _srcWindow.GetSortKey( (ULONG) _srcWindow.RowCount()-1, _pRightWindow->GetHighestKey() );
  262. }
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Function: _CopyWithNotifications
  266. //
  267. // Synopsis: Copies contents of both the "visible" and "dynamic" row index
  268. // from the source window to the destination window.
  269. //
  270. // Arguments: [destWindow] - Destination window to copy to.
  271. // [iStartVisRowIndex] - Starting offset in the visible rowindex.
  272. // [iEndVisRowIndex] - Ending offset in the visible rowindex.
  273. // [iStartDynRowIndex] - Starting offset in the dynamic rowindex.
  274. // [iEndDynRowIndex] - Ending offset in the dynamic rowindex.
  275. //
  276. // History: 1-09-95 srikants Created
  277. //
  278. // Notes:
  279. //
  280. //----------------------------------------------------------------------------
  281. void CTableWindowSplit::_CopyWithNotifications( CTableWindow & destWindow,
  282. ULONG iStartQueryRowIndex, ULONG iEndQueryRowIndex,
  283. LONG iStartClientRowIndex, LONG iEndClientRowIndex )
  284. {
  285. Win4Assert( _srcWindow.IsWatched() );
  286. Win4Assert( iStartQueryRowIndex < _srcQueryRowIndex.RowCount() );
  287. Win4Assert( iEndQueryRowIndex >= iStartQueryRowIndex &&
  288. iEndQueryRowIndex < _srcQueryRowIndex.RowCount() );
  289. //
  290. // Copy the rows from the client row index.
  291. //
  292. for ( LONG j = iStartClientRowIndex; j <= iEndClientRowIndex; j++ )
  293. {
  294. destWindow._PutRowToVisibleRowIndex( _srcWindow, _srcClientRowIndex.GetRow(j) );
  295. }
  296. //
  297. // Copy the rows from the query row index.
  298. //
  299. for ( ULONG i = iStartQueryRowIndex; i <= iEndQueryRowIndex; i++ )
  300. {
  301. destWindow._PutRowToDynRowIndex( _srcWindow, _srcQueryRowIndex.GetRow(i) );
  302. }
  303. }
  304. //+---------------------------------------------------------------------------
  305. //
  306. // Member: CTableWindowSplit::_IsOffsetInLeftWindow
  307. //
  308. // Synopsis:
  309. //
  310. // Arguments: [iOffset] -
  311. //
  312. // Returns:
  313. //
  314. // Modifies:
  315. //
  316. // History: 7-27-95 srikants Created
  317. //
  318. // Notes:
  319. //
  320. //----------------------------------------------------------------------------
  321. inline
  322. BOOL CTableWindowSplit::_IsOffsetInLeftWindow( long iOffset )
  323. {
  324. return iOffset <= _iSplitClientRowIndex;
  325. }
  326. //+---------------------------------------------------------------------------
  327. //
  328. // Member: CTableWindowSplit::_CopyWatchRegions
  329. //
  330. // Synopsis:
  331. //
  332. // Modifies:
  333. //
  334. // History: 7-27-95 srikants Created
  335. //
  336. // Notes:
  337. //
  338. //----------------------------------------------------------------------------
  339. void CTableWindowSplit::_CopyWatchRegions()
  340. {
  341. Win4Assert( _srcWindow.IsWatched() );
  342. for ( unsigned i = 0; i < _srcWindow._aWindowWatch.Count(); i++ )
  343. {
  344. CWindowWatch & watch = _srcWindow._aWindowWatch.Get(i);
  345. long cResidual = watch._cRowsLeft;
  346. if ( _IsOffsetInLeftWindow( watch._iRowStart ) )
  347. {
  348. cResidual -= _pLeftWindow->AddWatch( watch._hRegion,
  349. watch._iRowStart,
  350. cResidual,
  351. FALSE );
  352. if ( cResidual > 0 )
  353. {
  354. _pRightWindow->AddWatch( watch._hRegion,
  355. 0,
  356. cResidual,
  357. _fIsLastSegment );
  358. }
  359. }
  360. else
  361. {
  362. //
  363. // The offset must be in the right hand side window.
  364. //
  365. Win4Assert( watch._iRowStart > _iSplitClientRowIndex &&
  366. watch._iRowStart < (long) _srcWindow.RowCount() );
  367. Win4Assert( (long) _pLeftWindow->RowCount() == _iSplitClientRowIndex+1 );
  368. _pRightWindow->AddWatch( watch._hRegion,
  369. (LONG) (watch._iRowStart - _pLeftWindow->RowCount()),
  370. cResidual,
  371. _fIsLastSegment );
  372. }
  373. }
  374. }