Dbindex.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:11k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997 Master-Bank                }
  7. {                                                       }
  8. {*******************************************************}
  9. unit DBIndex;
  10. interface
  11. {$I RX.INC}
  12. {$IFDEF WIN32}
  13. uses SysUtils, Windows, Messages, Classes, Controls, Forms,
  14.   Graphics, Menus, StdCtrls, ExtCtrls, DB, DBTables;
  15. {$ELSE}
  16. uses SysUtils, WinTypes, WinProcs, Messages, Classes, Controls, Forms,
  17.   Graphics, Menus, StdCtrls, ExtCtrls, DB, DBTables;
  18. {$ENDIF}
  19. type
  20.   TIdxDisplayMode = (dmFieldLabels, dmFieldNames, dmIndexName);
  21. { TDBIndexCombo }
  22.   TDBIndexCombo = class(TCustomComboBox)
  23.   private
  24.     FDataLink: TDataLink;
  25.     FUpdate: Boolean;
  26.     FNoIndexItem: PString;
  27.     FEnableNoIndex: Boolean;
  28.     FChanging: Boolean;
  29.     FDisplayMode: TIdxDisplayMode;
  30.     function GetDataSource: TDataSource;
  31.     procedure SetDataSource(Value: TDataSource);
  32.     function GetIndexFieldName(var AName: string): Boolean;
  33.     procedure SetNoIndexItem(const Value: string);
  34.     function GetNoIndexItem: string;
  35.     procedure SetEnableNoIndex(Value: Boolean);
  36.     procedure SetDisplayMode(Value: TIdxDisplayMode);
  37.     procedure ActiveChanged;
  38.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  39.   protected
  40.     procedure Loaded; override;
  41.     procedure Notification(AComponent: TComponent;
  42.       Operation: TOperation); override;
  43.     procedure FillIndexList(List: TStrings);
  44.     procedure Change; override;
  45.     procedure UpdateList; virtual;
  46.   public
  47.     constructor Create(AOwner: TComponent); override;
  48.     destructor Destroy; override;
  49.   published
  50.     { published properties }
  51.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  52.     property NoIndexItem: string read GetNoIndexItem write SetNoIndexItem;
  53.     property EnableNoIndex: Boolean read FEnableNoIndex write SetEnableNoIndex default False;
  54.     property DisplayMode: TIdxDisplayMode read FDisplayMode write SetDisplayMode default dmFieldLabels;
  55.     property DragCursor;
  56.     property DragMode;
  57.     property Enabled;
  58.     property Color;
  59.     property Ctl3D;
  60.     property DropDownCount;
  61.     property Font;
  62. {$IFDEF RX_D4}
  63.     property Anchors;
  64.     property BiDiMode;
  65.     property Constraints;
  66.     property DragKind;
  67.     property ParentBiDiMode;
  68. {$ENDIF}
  69. {$IFDEF WIN32}
  70.   {$IFNDEF VER90}
  71.     property ImeMode;
  72.     property ImeName;
  73.   {$ENDIF}
  74. {$ENDIF}
  75.     property ItemHeight;
  76.     property ParentCtl3D;
  77.     property ParentFont;
  78.     property ParentShowHint;
  79.     property PopupMenu;
  80.     property ShowHint;
  81.     property Sorted;
  82.     property TabOrder;
  83.     property TabStop;
  84.     property Visible;
  85.     property OnChange;
  86.     property OnClick;
  87.     property OnDblClick;
  88.     property OnDragDrop;
  89.     property OnDragOver;
  90.     property OnEndDrag;
  91.     property OnEnter;
  92.     property OnExit;
  93.     property OnKeyDown;
  94.     property OnKeyPress;
  95.     property OnKeyUp;
  96. {$IFDEF RX_D5}
  97.     property OnContextPopup;
  98. {$ENDIF}
  99. {$IFDEF WIN32}
  100.     property OnStartDrag;
  101. {$ENDIF}
  102. {$IFDEF RX_D4}
  103.     property OnEndDock;
  104.     property OnStartDock;
  105. {$ENDIF}
  106.   end;
  107. implementation
  108. uses {$IFDEF WIN32} Bde, {$ELSE} DbiErrs, DbiTypes, DbiProcs, {$ENDIF}
  109.   DBConsts, rxStrUtils, DBUtils, BdeUtils;
  110. { TKeyDataLink }
  111. type
  112.   TKeyDataLink = class(TDataLink)
  113.   private
  114.     FCombo: TDBIndexCombo;
  115.   protected
  116.     procedure ActiveChanged; override;
  117.     procedure DataSetChanged; override;
  118.     procedure DataSetScrolled(Distance: Integer); override;
  119.   public
  120.     constructor Create(ACombo: TDBIndexCombo);
  121.     destructor Destroy; override;
  122.   end;
  123. constructor TKeyDataLink.Create(ACombo: TDBIndexCombo);
  124. begin
  125.   inherited Create;
  126.   FCombo := ACombo;
  127. end;
  128. destructor TKeyDataLink.Destroy;
  129. begin
  130.   FCombo := nil;
  131.   inherited Destroy;
  132. end;
  133. procedure TKeyDataLink.ActiveChanged;
  134. begin
  135.   if FCombo <> nil then FCombo.ActiveChanged;
  136. end;
  137. procedure TKeyDataLink.DataSetChanged;
  138. begin
  139.   if FCombo <> nil then FCombo.ActiveChanged;
  140. end;
  141. procedure TKeyDataLink.DataSetScrolled(Distance: Integer);
  142. begin
  143.   { ignore this data event }
  144. end;
  145. { TDBIndexCombo }
  146. constructor TDBIndexCombo.Create(AOwner: TComponent);
  147. begin
  148.   inherited Create(AOwner);
  149.   FDataLink := TKeyDataLink.Create(Self);
  150.   Style := csDropDownList;
  151.   FUpdate := False;
  152.   FNoIndexItem := NullStr;
  153.   FEnableNoIndex := False;
  154. end;
  155. destructor TDBIndexCombo.Destroy;
  156. begin
  157.   FDataLink.Free;
  158.   FDataLink := nil;
  159.   DisposeStr(FNoIndexItem);
  160.   FNoIndexItem := NullStr;
  161.   inherited Destroy;
  162. end;
  163. procedure TDBIndexCombo.SetNoIndexItem(const Value: string);
  164. begin
  165.   if Value <> FNoIndexItem^ then begin
  166.     AssignStr(FNoIndexItem, Value);
  167.     if not (csLoading in ComponentState) then ActiveChanged;
  168.   end;
  169. end;
  170. procedure TDBIndexCombo.SetEnableNoIndex(Value: Boolean);
  171. begin
  172.   if FEnableNoIndex <> Value then begin
  173.     FEnableNoIndex := Value;
  174.     if not (csLoading in ComponentState) then ActiveChanged;
  175.   end;
  176. end;
  177. procedure TDBIndexCombo.SetDisplayMode(Value: TIdxDisplayMode);
  178. begin
  179.   if (Value <> FDisplayMode) then begin
  180.     FDisplayMode := Value;
  181.     if not (csLoading in ComponentState) then UpdateList;
  182.   end;
  183. end;
  184. function TDBIndexCombo.GetNoIndexItem: string;
  185. begin
  186.   Result := FNoIndexItem^;
  187. end;
  188. function TDBIndexCombo.GetDataSource: TDataSource;
  189. begin
  190.   if FDataLink <> nil then Result := FDataLink.DataSource
  191.   else Result := nil;
  192. end;
  193. procedure TDBIndexCombo.SetDataSource(Value: TDataSource);
  194. begin
  195.   FDataLink.DataSource := Value;
  196. {$IFDEF WIN32}
  197.   if Value <> nil then Value.FreeNotification(Self);
  198. {$ENDIF}
  199.   if not (csLoading in ComponentState) then ActiveChanged;
  200. end;
  201. procedure TDBIndexCombo.ActiveChanged;
  202. begin
  203.   if not (Enabled and FDataLink.Active and
  204.     FDataLink.DataSet.InheritsFrom(TTable)) then
  205.   begin
  206.     Clear;
  207.     ItemIndex := -1;
  208.   end
  209.   else UpdateList;
  210. end;
  211. procedure TDBIndexCombo.Loaded;
  212. begin
  213.   inherited Loaded;
  214.   ActiveChanged;
  215. end;
  216. procedure TDBIndexCombo.Notification(AComponent: TComponent;
  217.   Operation: TOperation);
  218. begin
  219.   inherited Notification(AComponent, Operation);
  220.   if (Operation = opRemove) and (FDataLink <> nil) and
  221.     (AComponent = DataSource) then DataSource := nil;
  222. end;
  223. procedure TDBIndexCombo.CMEnabledChanged(var Message: TMessage);
  224. begin
  225.   inherited;
  226.   if not (csLoading in ComponentState) then ActiveChanged;
  227. end;
  228. function TDBIndexCombo.GetIndexFieldName(var AName: string): Boolean;
  229. begin
  230.   Result := True;
  231.   if ItemIndex >= 0 then begin
  232.     if EnableNoIndex and (Items[ItemIndex] = NoIndexItem) then AName := ''
  233.     else begin
  234.       AName := TIndexDef(Items.Objects[ItemIndex]).Fields;
  235.       if AName = '' then begin
  236.         AName := TIndexDef(Items.Objects[ItemIndex]).Name;
  237.         Result := False;
  238.       end;
  239.     end;
  240.   end
  241.   else AName := '';
  242. end;
  243. procedure TDBIndexCombo.FillIndexList(List: TStrings);
  244. var
  245.   AFld: string;
  246.   Pos: Integer;
  247.   I: Integer;
  248. begin
  249.   List.Clear;
  250.   if not FDataLink.Active then Exit;
  251.   with FDataLink.DataSet as TTable do begin
  252.     for I := 0 to IndexDefs.Count - 1 do
  253.       with IndexDefs[I] do
  254.         if not (ixExpression in Options) then begin
  255.           if FDisplayMode = dmIndexName then AFld := Name
  256.           else begin
  257.             AFld := '';
  258.             Pos := 1;
  259.             while Pos <= Length(Fields) do begin
  260.               if AFld <> '' then AFld := AFld + '; ';
  261.               case FDisplayMode of
  262.                 dmFieldLabels:
  263.                   AFld := AFld + FieldByName(ExtractFieldName(Fields, Pos)).DisplayLabel;
  264.                 dmFieldNames:
  265.                   AFld := AFld + FieldByName(ExtractFieldName(Fields, Pos)).FieldName;
  266.               end;
  267.             end;
  268.           end;
  269.           if List.IndexOf(AFld) < 0 then List.AddObject(AFld, IndexDefs[I]);
  270.         end;
  271.   end;
  272.   if EnableNoIndex then
  273.     if List.IndexOf(NoIndexItem) < 0 then List.AddObject(NoIndexItem, nil);
  274. end;
  275. procedure TDBIndexCombo.Change;
  276. var
  277.   ABookmark: TBookmark;
  278.   AName: string;
  279. begin
  280.   if Enabled and FDataLink.Active and not FChanging and
  281.     FDataLink.DataSet.InheritsFrom(TTable) and
  282.     not (csLoading in ComponentState) then
  283.   begin
  284.     ABookmark := nil;
  285.     with FDataLink.DataSet as TTable do begin
  286.       if Database.IsSQLBased then ABookmark := GetBookmark;
  287.       try
  288.         if GetIndexFieldName(AName) then begin
  289.           IndexFieldNames := AName;
  290.           if (AName = '') and (IndexDefs.Count > 0) then
  291.             IndexName := '';
  292.         end
  293.         else begin
  294.           if AName = '' then IndexFieldNames := '';
  295.           IndexName := AName;
  296.         end;
  297.         if (ABookmark <> nil) then
  298.           SetToBookmark(TTable(Self.FDataLink.DataSet), ABookmark);
  299.       finally
  300.         if ABookmark <> nil then FreeBookmark(ABookmark);
  301.       end;
  302.     end;
  303.   end;
  304.   inherited Change;
  305. end;
  306. procedure TDBIndexCombo.UpdateList;
  307.   function FindIndex(Table: TTable): Integer;
  308.   var
  309.     I: Integer;
  310.     IdxFields: string;
  311.   begin
  312.     Result := -1;
  313.     IdxFields := '';
  314.     if Table.IndexFieldNames <> '' then
  315.       for I := 0 to Table.IndexFieldCount - 1 do begin
  316.         if IdxFields <> '' then IdxFields := IdxFields + ';';
  317.         IdxFields := IdxFields + Table.IndexFields[I].FieldName;
  318.       end;
  319.     for I := 0 to Items.Count - 1 do begin
  320.       if (Items.Objects[I] <> nil) and
  321.         (((IdxFields <> '') and
  322.         (AnsiCompareText(TIndexDef(Items.Objects[I]).Fields, IdxFields) = 0)) or
  323.         ((Table.IndexName <> '') and
  324.         (AnsiCompareText(TIndexDef(Items.Objects[I]).Name, Table.IndexName) = 0))) then
  325.       begin
  326.         Result := I;
  327.         Exit;
  328.       end;
  329.     end;
  330.     if EnableNoIndex and FDataLink.Active then
  331.       if (Table.IndexFieldNames = '') and (Table.IndexName = '') then
  332.         Result := Items.IndexOf(NoIndexItem);
  333.   end;
  334. begin
  335.   if Enabled and FDataLink.Active then
  336.     try
  337.       Items.BeginUpdate;
  338.       try
  339.         if FDataLink.DataSet.InheritsFrom(TTable) then begin
  340.           TTable(FDataLink.DataSet).IndexDefs.Update;
  341.           FillIndexList(Items);
  342.           ItemIndex := FindIndex(TTable(FDataLink.DataSet));
  343.           FChanging := True;
  344.         end
  345.         else Items.Clear;
  346.       finally
  347.         Items.EndUpdate;
  348.       end;
  349.     finally
  350.       FChanging := False;
  351.     end;
  352. end;
  353. end.