home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / DBINDEX.PAS < prev    next >
Pascal/Delphi Source File  |  2001-06-24  |  11KB  |  390 lines

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