unit uGridUtils;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, cxCustomData, cxGraphics, cxFilter, cxData,
  cxDataStorage, cxEdit, DB, cxDBData, cxGridLevel,
  cxClasses, cxControls, cxGridCustomView, cxGridCustomTableView,
  cxGridTableView, cxGridDBTableView, cxGrid,
  uDBSelectionListUtils;

type
  TRecordInfo = class
    KeyValues: Variant;
    ALevel: Integer;
  end;

  TRecordInfos = class(TList)
  private
    function GetItem(Index: Integer): TRecordInfo;
  protected
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  public
    property Items[Index: Integer]: TRecordInfo read GetItem; Default;
  end;

  TcxGridStatus = class
  protected
    GroupRecords: TRecordInfos;
    SelectedRecords: TRecordInfos;
    SelStartItem: Integer;
    SelEndItem: Integer;
    AFocusedRow: TRecordInfo;
    TopRow: TRecordInfo;

    function SaveRecord(AView: TcxGridDBTableView; GridRecord:
      TcxCustomGridRecord): TRecordInfo;
    function FindRecordEx(AView: TcxGridDBTableView; RecordInfo:
      TRecordInfo): TcxCustomGridRecord;

    procedure SaveGridViewSelection(AView: TcxGridDBTableView);
    procedure LoadGridViewSelection(AView: TcxGridDBTableView);
    procedure SaveGridViewTopFocusedRecords(AView: TcxGridDBTableView);
    procedure LoadGridViewTopFocusedRecords(AView: TcxGridDBTableView);
    procedure SaveGridViewExpanded(AView: TcxGridDBTableView);
    procedure LoadGridViewExpanded(AView: TcxGridDBTableView);
  public
    constructor Create(AGridView: TcxGridDBTableView);
    destructor Destroy; override;
    procedure Restore(AGridView: TcxGridDBTableView);
  end;

procedure SeleccionarFilasDesdeGrid(const AView : TcxGridDBTableView;
  ASelectedRowList : TSelectedRecords);

procedure AsignarAnchosPrefijadosAColumnas(const AView : TcxGridDBTableView);

implementation


uses
  uDADataTable, uDAInterfaces, cxVariants, uDMBase;


procedure TRecordInfos.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if Action in [lnExtracted, lnDeleted] then
    FreeAndNil(TRecordInfo(Ptr));
end;

function TRecordInfos.GetItem(Index: Integer): TRecordInfo;
begin
  Result := TRecordInfo(inherited Items[Index]);
end;

function TcxGridStatus.SaveRecord(AView: TcxGridDBTableView;
  GridRecord: TcxCustomGridRecord): TRecordInfo;
begin
  Result := TRecordInfo.Create;
  Result.KeyValues :=
    AView.DataController.GetRecordId(GridRecord.RecordIndex);
  Result.ALevel := GridRecord.Level;
end;

function TcxGridStatus.FindRecordEx(AView: TcxGridDBTableView; RecordInfo:
  TRecordInfo): TcxCustomGridRecord;
var
  I, ARecordIndex: Integer;
  AList: TList;
  AKeyValue: Variant;
begin
  I := 0;
  Result := nil;

  if not Assigned(RecordInfo) then
    Exit;

  ARecordIndex := AView.DataController.FindRecordIndexByKey(RecordInfo.KeyValues);
  AList := TList.Create;
  try
    while I < AView.ViewData.RowCount do
    begin
      if AView.ViewData.Rows[I] is TcxGridGroupRow then
      begin
        AList.Clear;
        AView.DataController.Groups.LoadRecordIndexesByRowIndex(AList, I);
        if AList.IndexOf(Pointer(ARecordIndex)) <> -1 then
        begin
          if AView.ViewData.Rows[I].Level < RecordInfo.ALevel then
            AView.ViewData.Rows[I].Expand(False)
          else
          begin
            Result := AView.ViewData.Rows[I];
            Break;
          end;
        end;
      end
      else
      begin
        AKeyValue := AView.DataController.GetRecordId(AView.ViewData.Rows[I].RecordIndex);
        if VarEquals(AKeyValue, RecordInfo.KeyValues) then
        begin
          Result := AView.ViewData.Rows[I];
          Break;
        end;
      end;
      Inc(I);
    end;
  finally
    FreeAndNil(AList);
  end;
end;

procedure TcxGridStatus.SaveGridViewSelection(
  AView: TcxGridDBTableView);
var
  i: Integer;
  SelectRecordInfo: TRecordInfo;
begin
  with AView.DataController, AView.Controller do
  begin
    for i := 0 To SelectedRecordCount - 1 do
    begin
      SelectRecordInfo := SaveRecord(AView, SelectedRecords[i]);
      Self.SelectedRecords.Add(SelectRecordInfo);
    end;
    if SelectedColumnCount = 0 then
    begin
      SelStartItem := -1;
      SelEndItem := -1;
    end
    else
    begin
      SelStartItem := SelectedColumns[0].Index;
      SelEndItem := SelectedColumns[SelectedColumnCount - 1].Index;
    end;
  end;
end;

procedure TcxGridStatus.LoadGridViewSelection(
  AView: TcxGridDBTableView);
var
  i: Integer;
  ARecord: TcxCustomGridRecord;
begin
  AView.Controller.ClearSelection;

  for i := 0 To SelectedRecords.Count - 1 do
  begin
    ARecord := FindRecordEx(AView, SelectedRecords[i]);
    if Assigned(ARecord) then
      ARecord.Selected := True;
  end;

  if SelStartItem <> -1 then
    AView.Controller.SelectColumns(AView.Columns[SelStartItem],
      AView.Columns[SelEndItem]);
end;

procedure TcxGridStatus.SaveGridViewTopFocusedRecords(AView: TcxGridDBTableView);
begin
  if AView.Controller.FocusedRow = nil then
    AFocusedRow := nil
  else
    AFocusedRow := SaveRecord(AView, AView.Controller.FocusedRow);
  TopRow := nil;
  if (AView.Controller.TopRowIndex <> -1) and
    (AView.Controller.TopRowIndex < AView.ViewData.RecordCount) then
      TopRow := SaveRecord(AView, AView.ViewData.Records[AView.Controller.TopRowIndex]);
end;

procedure TcxGridStatus.LoadGridViewTopFocusedRecords(AView: TcxGridDBTableView);
var
  ARecord: TcxCustomGridRecord;
begin
  ARecord := FindRecordEx(AView, AFocusedRow);
  if Assigned(ARecord) then
    ARecord.Focused := True;
  ARecord := FindRecordEx(AView, TopRow);
  if Assigned(ARecord) then
    AView.Controller.TopRowIndex := ARecord.Index;
end;

type
  TcxDataControllerGroupsAccess = class(TcxDataControllerGroups);
  TcxDataGroupsAccess = class(TcxDataGroups);

procedure TcxGridStatus.SaveGridViewExpanded(
  AView: TcxGridDBTableView);
var
  i: Integer;
  GroupRecordInfo: TRecordInfo;
begin
  for i := 0 To AView.DataController.RowCount - 1 do
    with AView.ViewData.Records[i] do
      if Expanded then
      begin
        GroupRecordInfo := SaveRecord(AView, AView.ViewData.Records[i]);
        GroupRecords.Add(GroupRecordInfo);
      end;
end;

procedure TcxGridStatus.LoadGridViewExpanded(
  AView: TcxGridDBTableView);
var
  i: Integer;
  ARecord: TcxCustomGridRecord;
begin
  for i := 0 to GroupRecords.Count - 1 do
  begin
    ARecord := FindRecordEx(AView, GroupRecords[i]);
    if Assigned(ARecord) then
      ARecord.Expand(False);
  end;
end;

constructor TcxGridStatus.Create(AGridView: TcxGridDBTableView);
begin
  inherited Create;
  GroupRecords := TRecordInfos.Create;
  SelectedRecords := TRecordInfos.Create;
  SaveGridViewSelection(AGridView);
  SaveGridViewExpanded(AGridView);
  SaveGridViewTopFocusedRecords(AGridView);
end;

destructor TcxGridStatus.Destroy;
begin
  FreeAndNil(GroupRecords);
  FreeAndNil(SelectedRecords);
  inherited;
end;

procedure TcxGridStatus.Restore(AGridView: TcxGridDBTableView);
begin
  SendMessage(AGridView.Site.Handle, WM_SETREDRAW, 0, 0);
  try
      AGridView.ViewData.Collapse(True);
      LoadGridViewExpanded(AGridView);
      LoadGridViewSelection(AGridView);
      LoadGridViewTopFocusedRecords(AGridView);
  finally
    SendMessage(AGridView.Site.Handle, WM_SETREDRAW, 1, 0);
    RedrawWindow(AGridView.Site.Handle, Nil, 0, RDW_FRAME Or RDW_NOFRAME Or
      RDW_ALLCHILDREN Or RDW_INVALIDATE);
  end;
end;


procedure SeleccionarFilasDesdeGrid(const AView : TcxGridDBTableView;
    ASelectedRowList : TSelectedRecords);
var
  ARecord: TcxCustomGridRecord;
  i : Integer;
  AGridStatus : TcxGridStatus;

begin
  if not Assigned(AView) then
    raise Exception.Create('No hay vista asignada (SeleccionarFilasDesdeGrid)');

  ShowHourglassCursor;
  AGridStatus := TcxGridStatus.Create(AView);
  AView.BeginUpdate;
  try
    ASelectedRowList.Clear;
    for i := 0 to TcxCustomGridTableController(AView.Controller).SelectedRecordCount - 1 do
    begin
      ARecord := TcxCustomGridTableController(AView.Controller).SelectedRecords[i];
      if (ARecord is TcxGridDataRow) then
      begin
        (ARecord as TcxGridDataRow).Focused := True;
        ASelectedRowList.CurrentRowSelected := True;
      end;
    end;
  finally
    AView.EndUpdate;
    AGridStatus.Restore(AView);
    HideHourglassCursor;
  end;
end;


procedure AsignarAnchosPrefijadosAColumnas(const AView : TcxGridDBTableView);
var
  DefAnchos : TStringList;
  AColumn: TcxGridDBColumn;
  AIndex, i : Integer;
begin
  if not Assigned(AView) then
    raise Exception.Create('No hay vista asignada (AsignarAnchosPrefijadosAColumnas)');

  DefAnchos := TStringList.Create;
  with DefAnchos do begin
    CaseSensitive := False;
    Sorted := False;
    CommaText := 'CONCEPTO=500,' +
                 'NOMBRE=200,' +
                 'CANTIDAD=40,' +
                 'VISIBLE=20,' +
                 'VISIBLE2=20,' +
                 'DESCUENTO=60,' +
                 'IVA=60,' +
                 'RE=60,' +
                 'IMPORTE_UNIDAD=80' +
                 'REFERENCIA=100,' +
                 'REF_PEDIDO=100,' +
                 'REF_CONTRATO=100,' +
                 'REF_FACTURA=100,' +                 
                 'REFERENCIA_CLIENTE=100,' +
                 'REFERENCIA_PROVEEDOR=100,' +
                 'SITUACION=100,' +
                 'IMPORTE_NETO=80,' +
                 'IMPORTE_PORTE=80,' +
                 'IMPORTE_IVA=80,' +
                 'IMPORTE_RE=80,' +
                 'IMPORTE_TOTAL=150,' +
                 'TIPO=80,' +                 
                 'TIPO_CONTRATO=80,' +
                 'TIPO_PRESUPUESTO=80,' +
                 'VENDEDOR=60,' +
                 'TIENDA=60,' +
                 'NIF_CIF=60,' +
                 'FECHA_FACTURA=80,' +
                 'FECHA_VENCIMIENTO=80,' +
                 'FECHA_CONTRATO=80,' +
                 'FECHA_ALBARAN=80,' +
                 'FECHA_RECEPCION=80,' +
                 'FECHA_ENVIO=80,' +
                 'FECHA_VIGENCIA=80';
  end;

  ShowHourglassCursor;
  AView.BeginUpdate;
  try
    for i := 0 to (AView.ColumnCount - 1) do
    begin
      AColumn := AView.Columns[i];
      AColumn.BestFitMaxWidth := StrToIntDef(DefAnchos.Values[AColumn.DataBinding.FieldName], 60);
      Acolumn.MinWidth := 10;
      if AColumn.Width > AColumn.BestFitMaxWidth then
        AColumn.Width := AColumn.BestFitMaxWidth;
      //dmBase.EscribirLog(AColumn.DataBinding.FieldName + ' -> ' + IntToStr(AColumn.Width) + ' -> ' + IntToStr(AColumn.BestFitMaxWidth));
    end;
  finally
    AView.EndUpdate;
    HideHourglassCursor;
    FreeAndNil(DefAnchos);
  end;
end;

end.
