{ Copyright (C) 2004-2013

 *****************************************************************************
  See the file COPYING.modifiedLGPL.txt, included in this distribution,
  for details about the license.
 *****************************************************************************

  Author: Lagunov Aleksey

  Abstract:
    Property Editors for Database components of FCL and LCL.
}
unit DBPropEdits;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, ObjInspStrConsts, Dialogs, PropEdits, PropEditUtils,
  ComponentEditors, TypInfo, DB, DbCtrls, DBGrids, Forms,
  DBGridColumnsPropEditForm;

type
  TFieldProperty = class(TStringPropertyEditor)
  public
    function  GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
    procedure FillValues(const Values: TStringList); virtual;
  end;

 { TDBGridColumnsPropertyEditor }

 TDBGridColumnsPropertyEditor = class (TCollectionPropertyEditor)
 public
   class function ShowCollectionEditor(ACollection: TCollection;
   OwnerPersistent: TPersistent; const PropName: String): TCustomForm; override;
 end;

  { TLookupFieldProperty }

  TLookupFieldProperty = class(TFieldProperty)
  public
    procedure FillValues(const Values: TStringList); override;
  end;

  TDBGridFieldProperty = class(TFieldProperty)
  public
    procedure FillValues(const Values: TStringList); override;
  end;

  { TDBGridComponentEditor }

  TDBGridComponentEditor = class(TComponentEditor)
  public
    function GetVerbCount: Integer; override;
    function GetVerb({%H-}Index: Integer): string; override;
    procedure ExecuteVerb({%H-}Index: Integer); override;
  end;

function GetFieldDefsLookupRoot(APersistent: TPersistent): TPersistent;
procedure ListDataSourceFields(DataSource: TDataSource; List: TStrings);
procedure EditDBGridColumns(AComponent: TComponent; ACollection: TCollection; APropertyName: String);

implementation

procedure ListDataSourceFields(DataSource: TDataSource; List: TStrings);
var
  DataSet: TDataSet;
  i: Integer;
begin
  if Assigned(DataSource) then
  begin
    DataSet := DataSource.DataSet;
    if Assigned(DataSet) then
    begin
      if DataSet.Fields.Count > 0 then
        DataSet.GetFieldNames(List)
      else
      begin
        try
          DataSet.FieldDefs.Update;
        except
          // some FPC versions will fail here, but having persistent fields should
          // actually work or else present an empty list of fields... but not crash/freeze
          if Dataset.FieldDefs.Count=0 then begin
            List.Clear;
            ShowMessage(dpeUnableToRetrieveFieldsDefinitions);
            exit;
          end;
        end;
        for i := 0 to DataSet.FieldDefs.Count - 1 do
          List.Add(DataSet.FieldDefs[i].Name);
      end;
    end;
  end;
end;

function GetFieldDefsLookupRoot(APersistent: TPersistent): TPersistent;
var
  aFieldDefs: TFieldDefs;
begin
  Result:=nil;
  if not (APersistent is TFieldDefs) then exit;
  aFieldDefs:=TFieldDefs(APersistent);
  Result:=aFieldDefs.Owner;
  if Result=nil then
    Result:=aFieldDefs.Dataset;
  Result:=GetLookupRootForComponent(Result);
end;

procedure EditDBGridColumns(AComponent: TComponent; ACollection: TCollection;
  APropertyName: String);
begin
  TDBGridColumnsPropertyEditor.ShowCollectionEditor(ACollection, AComponent, APropertyName);
end;

{ TDBGridColumnsPropertyEditor }
const
  DBGridColumnsForm:  TDBGridColumnsPropertyEditorForm = nil;

class function TDBGridColumnsPropertyEditor.ShowCollectionEditor(
  ACollection: TCollection; OwnerPersistent: TPersistent; const PropName: String
  ): TCustomForm;
begin
  if DBGridColumnsForm = nil then
    DBGridColumnsForm := TDBGridColumnsPropertyEditorForm.Create(Application);
  DBGridColumnsForm.SetCollection(ACollection, OwnerPersistent, PropName);
  DBGridColumnsForm.EnsureVisible;
  Result:=DBGridColumnsForm;
  //  Result:=inherited ShowCollectionEditor(ACollection, OwnerPersistent, PropName );
end;

{ TFieldProperty }

function TFieldProperty.GetAttributes: TPropertyAttributes;
begin
  Result:= [paValueList, paSortList, paMultiSelect];
end;

procedure TFieldProperty.GetValues(Proc: TGetStrProc);
var
  I: Integer;
  Values: TStringList;
begin
  Values := TStringList.Create;
  try
    FillValues(Values);
    for I := 0 to Values.Count - 1 do Proc(Values[I]);
  finally
    Values.Free;
  end;
end;

procedure TFieldProperty.FillValues(const Values: TStringList);
var
  DataSource: TDataSource;
begin
  DataSource := GetObjectProp(GetComponent(0), 'DataSource') as TDataSource;
  ListDataSourceFields(DataSource, Values);
end;

{ TDBGridFieldProperty }

procedure TDBGridFieldProperty.FillValues(const Values: TStringList);
var
  Column: TColumn;
  Grid: TdbGrid;
begin
  Column:=TColumn(GetComponent(0));
  if not (Column is TColumn) then exit;
  Grid:=TdbGrid(Column.Grid);
  if not (Grid is TdbGrid) then exit;
  ListDataSourceFields(Grid.DataSource, Values);
end;

{ TDBGridComponentEditor }

function TDBGridComponentEditor.GetVerbCount: Integer;
begin
  Result:= 1;
end;

function TDBGridComponentEditor.GetVerb(Index: Integer): string;
begin
  Result:= sccsLvColEdt;
end;

procedure TDBGridComponentEditor.ExecuteVerb(Index: Integer);
var
  Hook: TPropertyEditorHook;
  DBGrid: TDBGrid;
begin
  DBGrid := GetComponent as TDBGrid;
  GetHook(Hook);
  EditDBGridColumns( DBGrid, DBGrid.Columns, 'Columns' );
  if Assigned(Hook) then Hook.Modified(Self);
end;

{ TLookupFieldProperty }

procedure TLookupFieldProperty.FillValues(const Values: TStringList);
var
  DataSource: TDataSource;
begin
  DataSource := GetObjectProp(GetComponent(0), 'ListSource') as TDataSource;
  ListDataSourceFields(DataSource, Values);
end;

initialization
  RegisterPropertyEditor(TypeInfo(string), TComponent, 'DataField', TFieldProperty);
  RegisterPropertyEditor(TypeInfo(string), TDBLookupListBox, 'KeyField', TLookupFieldProperty);
  RegisterPropertyEditor(TypeInfo(string), TDBLookupListBox, 'ListField', TLookupFieldProperty);
  RegisterPropertyEditor(TypeInfo(string), TDBLookupComboBox, 'KeyField', TLookupFieldProperty);
  RegisterPropertyEditor(TypeInfo(string), TDBLookupComboBox, 'ListField', TLookupFieldProperty);
  RegisterPropertyEditor(TypeInfo(string), TColumn, 'FieldName', TDBGridFieldProperty);
  RegisterComponentEditor(TDBGrid,TDBGridComponentEditor);
  RegisterGetLookupRoot(@GetFieldDefsLookupRoot);
  RegisterPropertyEditor(TypeInfo(TDBGridColumns), nil, '', TDBGridColumnsPropertyEditor);
end.

