datasource.inc 12 KB

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