home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / DBINDEX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  10.6 KB  |  392 lines

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