datasource.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. { ---------------------------------------------------------------------
  2. TDatalink
  3. ---------------------------------------------------------------------}
  4. Constructor TDataLink.Create;
  5. begin
  6. Inherited Create;
  7. FBufferCount:=1;
  8. FFirstRecord := 0;
  9. FDataSource := nil;
  10. FDatasourceFixed:=False;
  11. end;
  12. Destructor TDataLink.Destroy;
  13. begin
  14. Factive:=False;
  15. FEditing:=False;
  16. FDataSourceFixed:=False;
  17. DataSource:=Nil;
  18. Inherited Destroy;
  19. end;
  20. Procedure TDataLink.ActiveChanged;
  21. begin
  22. FFirstRecord := 0;
  23. end;
  24. Procedure TDataLink.CheckActiveAndEditing;
  25. Var
  26. B : Boolean;
  27. begin
  28. B:=Assigned(DataSource) and (DataSource.State<>dsInactive);
  29. If B<>FActive then
  30. begin
  31. FActive:=B;
  32. ActiveChanged;
  33. end;
  34. B:=Assigned(DataSource) and (DataSource.State in dsEditModes) and Not FReadOnly;
  35. If B<>FEditing Then
  36. begin
  37. FEditing:=B;
  38. EditingChanged;
  39. end;
  40. end;
  41. Procedure TDataLink.CheckBrowseMode;
  42. begin
  43. end;
  44. Function TDataLink.CalcFirstRecord(Index : Integer) : Integer;
  45. { recalculates index of first record in buffer,
  46. and returns number of record scrolled.}
  47. Var
  48. A, // Index of active record in buffer
  49. F, // Index of current first record in buffer
  50. L : Integer; // index of Last (for us) record in buffer;
  51. begin
  52. Result:=0;
  53. A:=DataSource.DataSet.FActiveRecord;
  54. F:=FFirstRecord+Index;
  55. L:=F+FBufferCount-1;
  56. If A>L Then
  57. Result:=A-L
  58. else If A<F Then
  59. Result:=A-F;
  60. FFirstRecord:=F+Result;
  61. {$IfDef dsDebug}
  62. WriteLn('CalcFirstRecord: FFirstRecord=',FFirstRecord,' Scrolled=',Result);
  63. {$Endif}
  64. end;
  65. Procedure TDataLink.CalcRange;
  66. var
  67. aMax, aMin: integer;
  68. begin
  69. aMin:= DataSet.FActiveRecord - FBufferCount + 1;
  70. If aMin < 0 Then aMin:= 0;
  71. aMax:= Dataset.FBufferCount - FBufferCount;
  72. If aMax < 0 then aMax:= 0;
  73. If aMax>DataSet.FActiveRecord Then aMax:=DataSet.FActiveRecord;
  74. If FFirstRecord < aMin Then FFirstRecord:= aMin;
  75. If FFirstrecord > aMax Then FFirstRecord:= aMax;
  76. If (FfirstRecord<>0) And
  77. (DataSet.FActiveRecord - FFirstRecord < FBufferCount -1) Then
  78. Dec(FFirstRecord, 1);
  79. end;
  80. Procedure TDataLink.DataEvent(Event: TDataEvent; Info: Ptrint);
  81. begin
  82. Case Event of
  83. deFieldChange, deRecordChange:
  84. If Not FUpdatingRecord then
  85. RecordChanged(TField(Info));
  86. deDataSetChange: begin
  87. SetActive(DataSource.DataSet.Active);
  88. CalcRange;
  89. CalcFirstRecord(Info);
  90. DatasetChanged;
  91. end;
  92. deDataSetScroll: DatasetScrolled(CalcFirstRecord(Info));
  93. deLayoutChange: begin
  94. CalcFirstRecord(Info);
  95. LayoutChanged;
  96. end;
  97. deUpdateRecord: UpdateRecord;
  98. deUpdateState: CheckActiveAndEditing;
  99. deCheckBrowseMode: CheckBrowseMode;
  100. deFocusControl: FocusControl(TFieldRef(Info));
  101. end;
  102. end;
  103. Procedure TDataLink.DataSetChanged;
  104. begin
  105. RecordChanged(Nil);
  106. end;
  107. Procedure TDataLink.DataSetScrolled(Distance: Integer);
  108. begin
  109. DataSetChanged;
  110. end;
  111. Procedure TDataLink.EditingChanged;
  112. begin
  113. end;
  114. Procedure TDataLink.FocusControl(Field: TFieldRef);
  115. begin
  116. end;
  117. Function TDataLink.GetActiveRecord: Integer;
  118. begin
  119. Result:=Dataset.FActiveRecord - FFirstRecord;
  120. end;
  121. Function TDatalink.GetDataSet : TDataset;
  122. begin
  123. If Assigned(Datasource) then
  124. Result:=DataSource.DataSet
  125. else
  126. Result:=Nil;
  127. end;
  128. Function TDataLink.GetBOF: Boolean;
  129. begin
  130. Result:=DataSet.BOF
  131. end;
  132. Function TDataLink.GetBufferCount: Integer;
  133. begin
  134. Result:=FBufferCount;
  135. end;
  136. Function TDataLink.GetEOF: Boolean;
  137. begin
  138. Result:=DataSet.EOF
  139. end;
  140. Function TDataLink.GetRecordCount: Integer;
  141. begin
  142. Result:=Dataset.FRecordCount;
  143. If Result>BufferCount then
  144. Result:=BufferCount;
  145. end;
  146. Procedure TDataLink.LayoutChanged;
  147. begin
  148. DataSetChanged;
  149. end;
  150. Function TDataLink.MoveBy(Distance: Integer): Integer;
  151. begin
  152. Result:=DataSet.MoveBy(Distance);
  153. end;
  154. Procedure TDataLink.RecordChanged(Field: TField);
  155. begin
  156. end;
  157. Procedure TDataLink.SetActiveRecord(Value: Integer);
  158. begin
  159. {$ifdef dsdebug}
  160. Writeln('Datalink. Setting active record to ',Value,' with firstrecord ',ffirstrecord);
  161. {$endif}
  162. Dataset.FActiveRecord:=Value + FFirstRecord;
  163. end;
  164. Procedure TDataLink.SetBufferCount(Value: Integer);
  165. begin
  166. If FBufferCount<>Value then
  167. begin
  168. FBufferCount:=Value;
  169. if Active then begin
  170. DataSet.RecalcBufListSize;
  171. CalcRange;
  172. end;
  173. end;
  174. end;
  175. procedure TDataLink.SetActive(AActive: Boolean);
  176. begin
  177. if Active <> AActive then
  178. begin
  179. FActive := AActive;
  180. // !!!: Set internal state
  181. ActiveChanged;
  182. end;
  183. end;
  184. Procedure TDataLink.SetDataSource(Value : TDatasource);
  185. begin
  186. if not FDataSourceFixed then
  187. begin
  188. if Assigned(DataSource) then
  189. Begin
  190. DataSource.UnregisterDatalink(Self);
  191. FDataSource := nil;
  192. CheckActiveAndEditing;
  193. End;
  194. FDataSource := Value;
  195. if Assigned(DataSource) then
  196. begin
  197. DataSource.RegisterDatalink(Self);
  198. CheckActiveAndEditing;
  199. End;
  200. end;
  201. end;
  202. Procedure TDatalink.SetReadOnly(Value : Boolean);
  203. begin
  204. If FReadOnly<>Value then
  205. begin
  206. FReadOnly:=Value;
  207. CheckActiveAndEditing;
  208. end;
  209. end;
  210. Procedure TDataLink.UpdateData;
  211. begin
  212. end;
  213. Function TDataLink.Edit: Boolean;
  214. begin
  215. If Not FReadOnly then
  216. DataSource.Edit;
  217. // Triggered event will set FEditing
  218. Result:=FEditing;
  219. end;
  220. Procedure TDataLink.UpdateRecord;
  221. begin
  222. FUpdatingRecord:=True;
  223. Try
  224. UpdateData;
  225. finally
  226. FUpdatingRecord:=False;
  227. end;
  228. end;
  229. { ---------------------------------------------------------------------
  230. TDetailDataLink
  231. ---------------------------------------------------------------------}
  232. Function TDetailDataLink.GetDetailDataSet: TDataSet;
  233. begin
  234. Result := nil;
  235. end;
  236. { ---------------------------------------------------------------------
  237. TMasterDataLink
  238. ---------------------------------------------------------------------}
  239. constructor TMasterDataLink.Create(ADataSet: TDataSet);
  240. begin
  241. inherited Create;
  242. FDetailDataSet:=ADataSet;
  243. FFields:=TList.Create;
  244. end;
  245. destructor TMasterDataLink.Destroy;
  246. begin
  247. FFields.Free;
  248. inherited Destroy;
  249. end;
  250. Procedure TMasterDataLink.ActiveChanged;
  251. begin
  252. FFields.Clear;
  253. if Active then
  254. try
  255. DataSet.GetFieldList(FFields, FFieldNames);
  256. except
  257. FFields.Clear;
  258. raise;
  259. end;
  260. if FDetailDataSet.Active and not (csDestroying in FDetailDataSet.ComponentState) then
  261. if Active and (FFields.Count > 0) then
  262. DoMasterChange
  263. else
  264. DoMasterDisable;
  265. end;
  266. Procedure TMasterDataLink.CheckBrowseMode;
  267. begin
  268. if FDetailDataSet.Active then FDetailDataSet.CheckBrowseMode;
  269. end;
  270. Function TMasterDataLink.GetDetailDataSet: TDataSet;
  271. begin
  272. Result := FDetailDataSet;
  273. end;
  274. Procedure TMasterDataLink.LayoutChanged;
  275. begin
  276. ActiveChanged;
  277. end;
  278. Procedure TMasterDataLink.RecordChanged(Field: TField);
  279. begin
  280. if (DataSource.State <> dsSetKey) and FDetailDataSet.Active and
  281. (FFields.Count > 0) and ((Field = nil) or
  282. (FFields.IndexOf(Field) >= 0)) then
  283. DoMasterChange;
  284. end;
  285. procedure TMasterDatalink.SetFieldNames(const Value: string);
  286. begin
  287. if FFieldNames <> Value then
  288. begin
  289. FFieldNames := Value;
  290. ActiveChanged;
  291. end;
  292. end;
  293. Procedure TMasterDataLink.DoMasterDisable;
  294. begin
  295. if Assigned(FOnMasterDisable) then
  296. FOnMasterDisable(Self);
  297. end;
  298. Procedure TMasterDataLink.DoMasterChange;
  299. begin
  300. If Assigned(FOnMasterChange) then
  301. FOnMasterChange(Self);
  302. end;
  303. { ---------------------------------------------------------------------
  304. TMasterDataLink
  305. ---------------------------------------------------------------------}
  306. constructor TMasterParamsDataLink.Create(ADataSet: TDataSet);
  307. Var
  308. P : TParams;
  309. begin
  310. inherited Create(ADataset);
  311. If (ADataset<>Nil) then
  312. begin
  313. P:=TParams(GetObjectProp(ADataset,'Params',TParams));
  314. if (P<>Nil) then
  315. Params:=P;
  316. end;
  317. end;
  318. Procedure TMasterParamsDataLink.SetParams(AVAlue : TParams);
  319. begin
  320. FParams:=AValue;
  321. If (AValue<>Nil) then
  322. RefreshParamNames;
  323. end;
  324. Procedure TMasterParamsDataLink.RefreshParamNames;
  325. Var
  326. FN : String;
  327. DS : TDataset;
  328. F : TField;
  329. I : Integer;
  330. begin
  331. FN:='';
  332. DS:=Dataset;
  333. If Assigned(FParams) then
  334. begin
  335. F:=Nil;
  336. For I:=0 to FParams.Count-1 do
  337. begin
  338. If Assigned(DS) then
  339. F:=DS.FindField(FParams[i].Name);
  340. If (Not Assigned(DS)) or (F<>Nil) then
  341. begin
  342. If (FN<>'') then
  343. FN:=FN+';';
  344. FN:=FN+FParams[i].Name;
  345. end;
  346. end;
  347. end;
  348. FieldNames:=FN;
  349. end;
  350. Procedure TMasterParamsDataLink.CopyParamsFromMaster(CopyBound : Boolean);
  351. begin
  352. if Assigned(FParams) then
  353. FParams.CopyParamValuesFromDataset(Dataset,CopyBound);
  354. end;
  355. Procedure TMasterParamsDataLink.DoMasterDisable;
  356. begin
  357. Inherited;
  358. If Assigned(DetailDataset) and DetailDataset.Active then
  359. DetailDataset.Close;
  360. end;
  361. Procedure TMasterParamsDataLink.DoMasterChange;
  362. begin
  363. Inherited;
  364. if Assigned(Params) and Assigned(DetailDataset) and DetailDataset.Active then
  365. begin
  366. DetailDataset.Close;
  367. DetailDataset.Open;
  368. end;
  369. end;
  370. { ---------------------------------------------------------------------
  371. TDatasource
  372. ---------------------------------------------------------------------}
  373. Constructor TDataSource.Create(AOwner: TComponent);
  374. begin
  375. Inherited Create(AOwner);
  376. FDatalinks := TList.Create;
  377. FEnabled := True;
  378. FAutoEdit := True;
  379. end;
  380. Destructor TDataSource.Destroy;
  381. begin
  382. FOnStateCHange:=Nil;
  383. Dataset:=Nil;
  384. With FDataLinks do
  385. While Count>0 do
  386. TDatalink(Items[Count - 1]).DataSource:=Nil;
  387. FDatalinks.Free;
  388. inherited Destroy;
  389. end;
  390. Procedure TDatasource.Edit;
  391. begin
  392. If (State=dsBrowse) and AutoEdit Then
  393. Dataset.Edit;
  394. end;
  395. Function TDataSource.IsLinkedTo(ADataSet: TDataSet): Boolean;
  396. begin
  397. Result:=False;
  398. end;
  399. procedure TDatasource.DistributeEvent(Event: TDataEvent; Info: Ptrint);
  400. Var
  401. i : Longint;
  402. begin
  403. With FDatalinks do
  404. begin
  405. For I:=0 to Count-1 do
  406. With TDatalink(Items[i]) do
  407. If Not VisualControl Then
  408. DataEvent(Event,Info);
  409. For I:=0 to Count-1 do
  410. With TDatalink(Items[i]) do
  411. If VisualControl Then
  412. DataEvent(Event,Info);
  413. end;
  414. end;
  415. procedure TDatasource.RegisterDataLink(DataLink: TDataLink);
  416. begin
  417. FDatalinks.Add(DataLink);
  418. if Assigned(DataSet) then
  419. DataSet.RecalcBufListSize;
  420. end;
  421. procedure TDatasource.SetDataSet(ADataSet: TDataSet);
  422. begin
  423. If FDataset<>Nil Then
  424. Begin
  425. FDataset.UnRegisterDataSource(Self);
  426. FDataSet:=nil;
  427. ProcessEvent(deUpdateState,0);
  428. End;
  429. If ADataset<>Nil Then
  430. begin
  431. ADataset.RegisterDatasource(Self);
  432. FDataSet:=ADataset;
  433. ProcessEvent(deUpdateState,0);
  434. End;
  435. end;
  436. procedure TDatasource.SetEnabled(Value: Boolean);
  437. begin
  438. FEnabled:=Value;
  439. end;
  440. Procedure TDatasource.DoDataChange (Info : Pointer);
  441. begin
  442. If Assigned(OnDataChange) Then
  443. OnDataChange(Self,TField(Info));
  444. end;
  445. Procedure TDatasource.DoStateChange;
  446. begin
  447. If Assigned(OnStateChange) Then
  448. OnStateChange(Self);
  449. end;
  450. Procedure TDatasource.DoUpdateData;
  451. begin
  452. If Assigned(OnUpdateData) Then
  453. OnUpdateData(Self);
  454. end;
  455. procedure TDatasource.UnregisterDataLink(DataLink: TDataLink);
  456. begin
  457. FDatalinks.Remove(Datalink);
  458. If Dataset<>Nil then
  459. DataSet.RecalcBufListSize;
  460. //Dataset.SetBufListSize(DataLink.BufferCount);
  461. end;
  462. procedure TDataSource.ProcessEvent(Event : TDataEvent; Info : Ptrint);
  463. Const
  464. OnDataChangeEvents = [deRecordChange, deDataSetChange, deDataSetScroll,
  465. deLayoutChange,deUpdateState];
  466. Var
  467. NeedDataChange : Boolean;
  468. FLastState : TdataSetState;
  469. begin
  470. // Special UpdateState handling.
  471. If Event=deUpdateState then
  472. begin
  473. NeedDataChange:=(FState=dsInactive);
  474. FLastState:=FState;
  475. If Assigned(Dataset) then
  476. FState:=Dataset.State
  477. else
  478. FState:=dsInactive;
  479. // Don't do events if nothing changed.
  480. If FState=FlastState then
  481. exit;
  482. end
  483. else
  484. NeedDataChange:=True;
  485. DistributeEvent(Event,Info);
  486. // Extra handlers
  487. If Not (csDestroying in ComponentState) then
  488. begin
  489. If (Event=deUpdateState) then
  490. DoStateChange;
  491. If (Event in OnDataChangeEvents) and
  492. NeedDataChange Then
  493. DoDataChange(Nil);
  494. If (Event = deFieldChange) Then
  495. DoDataCHange(Pointer(Info));
  496. If (Event=deUpdateRecord) then
  497. DoUpdateData;
  498. end;
  499. end;