MdDsCustom.pas
上传用户:fh681027
上传日期:2022-07-23
资源大小:1959k
文件大小:9k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit MdDsCustom;
  2. interface
  3. uses
  4.   SysUtils, Classes, Db;
  5. type
  6.   EMdDataSetError = class (Exception);
  7.   TMdRecInfo = record
  8.     Bookmark: Longint;
  9.     BookmarkFlag: TBookmarkFlag;
  10.   end;
  11.   PMdRecInfo = ^TMdRecInfo;
  12.   TMdCustomDataSet = class(TDataSet)
  13.   protected
  14.     // status
  15.     FIsTableOpen: Boolean;
  16.     // record data
  17.     FRecordSize, // the size of the actual data
  18.     FRecordBufferSize, // data + housekeeping (TRecInfo)
  19.     FCurrentRecord, // current record (0 to FRecordCount - 1)
  20.     BofCrack, // before the first record (crack)
  21.     EofCrack: Integer; // after the last record (crack)
  22.     // create, close, and so on
  23.     procedure InternalOpen; override;
  24.     procedure InternalClose; override;
  25.     function IsCursorOpen: Boolean; override;
  26.     // custom functions
  27.     function InternalRecordCount: Integer; virtual; abstract;
  28.     procedure InternalPreOpen; virtual;
  29.     procedure InternalAfterOpen; virtual;
  30.     procedure InternalLoadCurrentRecord(Buffer: PChar); virtual; abstract;
  31.     // memory management
  32.     function AllocRecordBuffer: PChar; override;
  33.     procedure InternalInitRecord(Buffer: PChar); override;
  34.     procedure FreeRecordBuffer(var Buffer: PChar); override;
  35.     function GetRecordSize: Word; override;
  36.     // movement and optional navigation (used by grids)
  37.     function GetRecord(Buffer: PChar; GetMode: TGetMode;
  38.       DoCheck: Boolean): TGetResult; override;
  39.     procedure InternalFirst; override;
  40.     procedure InternalLast; override;
  41.     function GetRecNo: Longint; override;
  42.     function GetRecordCount: Longint; override;
  43.     procedure SetRecNo(Value: Integer); override;
  44.     // bookmarks
  45.     procedure InternalGotoBookmark(Bookmark: Pointer); override;
  46.     procedure InternalSetToRecord(Buffer: PChar); override;
  47.     procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
  48.     procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
  49.     procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
  50.     function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
  51.     // editing (dummy vesions)
  52.     procedure InternalDelete; override;
  53.     procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
  54.     procedure InternalPost; override;
  55.     // other
  56.     procedure InternalHandleException; override;
  57.   published
  58.     // redeclared data set properties
  59.     property Active;
  60.     property BeforeOpen;
  61.     property AfterOpen;
  62.     property BeforeClose;
  63.     property AfterClose;
  64.     property BeforeInsert;
  65.     property AfterInsert;
  66.     property BeforeEdit;
  67.     property AfterEdit;
  68.     property BeforePost;
  69.     property AfterPost;
  70.     property BeforeCancel;
  71.     property AfterCancel;
  72.     property BeforeDelete;
  73.     property AfterDelete;
  74.     property BeforeScroll;
  75.     property AfterScroll;
  76.     property OnCalcFields;
  77.     property OnDeleteError;
  78.     property OnEditError;
  79.     property OnFilterRecord;
  80.     property OnNewRecord;
  81.     property OnPostError;
  82.   end;
  83. implementation
  84. /////////////////////////////////////////////////
  85. ////// Part I:
  86. ////// Initialization, opening, and closing
  87. /////////////////////////////////////////////////
  88. // I: open the dataset
  89. procedure TMDCustomDataSet.InternalOpen;
  90. begin
  91.   InternalPreOpen; // custom method for subclasses
  92.   // initialize the field definitions
  93.   // (another virtual abstract method of TDataSet)
  94.   InternalInitFieldDefs;
  95.   // if there are no persistent field objects,
  96.   // create the fields dynamically
  97.   if DefaultFields then
  98.     CreateFields;
  99.   // connect the TField objects with the actual fields
  100.   BindFields (True);
  101.   InternalAfterOpen; // custom method for subclasses
  102.   // sets cracks and record position and size
  103.   BofCrack := -1;
  104.   EofCrack := InternalRecordCount;
  105.   FCurrentRecord := BofCrack;
  106.   FRecordBufferSize := FRecordSize + sizeof (TMdRecInfo);
  107.   BookmarkSize := sizeOf (Integer);
  108.   // everything OK: table is now open
  109.   FIsTableOpen := True;
  110. end;
  111. procedure TMDCustomDataSet.InternalClose;
  112. begin
  113.   // disconnet field objects
  114.   BindFields (False);
  115.   // destroy field object (if not persistent)
  116.   if DefaultFields then
  117.     DestroyFields;
  118.   // close the file
  119.   FIsTableOpen := False;
  120. end;
  121. // I: is table open
  122. function TMDCustomDataSet.IsCursorOpen: Boolean;
  123. begin
  124.   Result := FIsTableOpen;
  125. end;
  126. ////////////////////////////////////////
  127. ////// Part II:
  128. ////// Bookmarks management and movement
  129. ////////////////////////////////////////
  130. // II: set the requested bookmark as current record
  131. procedure TMDCustomDataSet.InternalGotoBookmark (Bookmark: Pointer);
  132. var
  133.   ReqBookmark: Integer;
  134. begin
  135.   ReqBookmark := PInteger (Bookmark)^;
  136.   if (ReqBookmark >= 0) and (ReqBookmark < InternalRecordCount) then
  137.     FCurrentRecord := ReqBookmark
  138.   else
  139.     raise EMdDataSetError.Create ('Bookmark ' +
  140.       IntToStr (ReqBookmark) + ' not found');
  141. end;
  142. // II: same as above (but passes a buffer)
  143. procedure TMDCustomDataSet.InternalSetToRecord (Buffer: PChar);
  144. var
  145.   ReqBookmark: Integer;
  146. begin
  147.   ReqBookmark := PMdRecInfo(Buffer + FRecordSize).Bookmark;
  148.   InternalGotoBookmark (@ReqBookmark);
  149. end;
  150. // II: retrieve bookmarks flags from buffer
  151. function TMDCustomDataSet.GetBookmarkFlag (
  152.   Buffer: PChar): TBookmarkFlag;
  153. begin
  154.   Result := PMdRecInfo(Buffer + FRecordSize).BookmarkFlag;
  155. end;
  156. // II: change the bookmark flags in the buffer
  157. procedure TMDCustomDataSet.SetBookmarkFlag (Buffer: PChar;
  158.   Value: TBookmarkFlag);
  159. begin
  160.   PMdRecInfo(Buffer + FRecordSize).BookmarkFlag := Value;
  161. end;
  162. // II: Go to a special position before the first record
  163. procedure TMDCustomDataSet.InternalFirst;
  164. begin
  165.   FCurrentRecord := BofCrack;
  166. end;
  167. // II: Go to a special position after the last record
  168. procedure TMDCustomDataSet.InternalLast;
  169. begin
  170.   EofCrack := InternalRecordCount;
  171.   FCurrentRecord := EofCrack;
  172. end;
  173. // II: read the bookmark data from record buffer
  174. procedure TMDCustomDataSet.GetBookmarkData (
  175.   Buffer: PChar; Data: Pointer);
  176. begin
  177.   PInteger(Data)^ :=
  178.     PMdRecInfo(Buffer + FRecordSize).Bookmark;
  179. end;
  180. // II: set the bookmark data in the buffer
  181. procedure TMDCustomDataSet.SetBookmarkData (
  182.   Buffer: PChar; Data: Pointer);
  183. begin
  184.   PMdRecInfo(Buffer + FRecordSize).Bookmark :=
  185.     PInteger(Data)^;
  186. end;
  187. // II (optional): Record count
  188. function TMDCustomDataSet.GetRecordCount: Longint;
  189. begin
  190.   CheckActive;
  191.   Result := InternalRecordCount;
  192. end;
  193. // II (optional): Get the number of the current record
  194. function TMDCustomDataSet.GetRecNo: Longint;
  195. begin
  196.   UpdateCursorPos;
  197.   if FCurrentRecord < 0 then
  198.     Result := 1
  199.   else
  200.     Result := FCurrentRecord + 1;
  201. end;
  202. // II (optional): Move to the given record number
  203. procedure TMDCustomDataSet.SetRecNo(Value: Integer);
  204. begin
  205.   CheckBrowseMode;
  206.   if (Value >= 1) and (Value <= InternalRecordCount) then
  207.   begin
  208.     FCurrentRecord := Value - 1;
  209.     Resync([]);
  210.   end;
  211. end;
  212. //////////////////////////////////////////
  213. ////// Part III:
  214. ////// Record buffers and field management
  215. //////////////////////////////////////////
  216. // III: Retrieve data for current, previous, or next record
  217. // (eventually moving to it) and return the status
  218. function TMDCustomDataSet.GetRecord(Buffer: PChar;
  219.   GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  220. begin
  221.   Result := grOK; // default
  222.   case GetMode of
  223.     gmNext: // move on
  224.       if FCurrentRecord < InternalRecordCount - 1 then
  225.         Inc (FCurrentRecord)
  226.       else
  227.         Result := grEOF; // end of file
  228.     gmPrior: // move back
  229.       if FCurrentRecord > 0 then
  230.         Dec (FCurrentRecord)
  231.       else
  232.         Result := grBOF; // begin of file
  233.     gmCurrent: // check if empty
  234.       if FCurrentRecord >= InternalRecordCount then
  235.         Result := grError;
  236.   end;
  237.   // load the data
  238.   if Result = grOK then
  239.     InternalLoadCurrentRecord (Buffer)
  240.   else
  241.     if (Result = grError) and DoCheck then
  242.       raise EMdDataSetError.Create ('GetRecord: Invalid record');
  243. end;
  244. // III: Initialize the record (set to 0)
  245. procedure TMDCustomDataSet.InternalInitRecord(Buffer: PChar);
  246. begin
  247.   FillChar(Buffer^, FRecordBufferSize, 0);
  248. end;
  249. // III: Free the buffer
  250. procedure TMDCustomDataSet.FreeRecordBuffer (var Buffer: PChar);
  251. begin
  252.   FreeMem (Buffer);
  253. end;
  254. /// III: Determine the size of each record buffer in memory
  255. function TMDCustomDataSet.GetRecordSize: Word;
  256. begin
  257.   Result := FRecordSize; // data only
  258. end;
  259. /// III: Allocate a buffer for the record
  260. function TMDCustomDataSet.AllocRecordBuffer: PChar;
  261. begin
  262.   GetMem (Result, FRecordBufferSize);
  263. end;
  264. // III: Delete the current record
  265. procedure TMDCustomDataSet.InternalDelete;
  266. begin
  267.   // not supported in this generic version
  268.   raise EMdDataSetError.Create ('Delete: Operation not supported');
  269. end;
  270. // default exception handling
  271. procedure TMDCustomDataSet.InternalHandleException;
  272. begin
  273.   // special purpose exception handling
  274.   // do nothing
  275. end;
  276. procedure TMdCustomDataSet.InternalAddRecord(Buffer: Pointer;
  277.   Append: Boolean);
  278. begin
  279.   // not supported in this generic version
  280.   raise EMdDataSetError.Create ('AddRecord: Operation not supported');
  281. end;
  282. procedure TMdCustomDataSet.InternalPost;
  283. begin
  284.   // not supported in this generic version
  285.   raise EMdDataSetError.Create ('Post: Operation not supported');
  286. end;
  287. procedure TMdCustomDataSet.InternalAfterOpen;
  288. begin
  289.   // nothing to do: subclasses can hook in here
  290. end;
  291. procedure TMdCustomDataSet.InternalPreOpen;
  292. begin
  293.   // nothing to do: subclasses can hook in here
  294. end;
  295. end.