unit uViewDetallesBase;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uViewBase, cxStyles, ComCtrls, ToolWin, ActnList, cxCustomData,
  cxGraphics, cxFilter, cxData, cxDataStorage, cxEdit, DB, cxDBData,
  uDADataTable, cxGridLevel, cxClasses, cxControls, cxGridCustomView,
  cxGridCustomTableView, cxGridTableView, cxGridDBTableView, ImgList,
  PngImageList, cxGrid, cxImageComboBox, cxTextEdit, cxMaskEdit, cxCheckBox,
  uGridUtils, uControllerDetallesBase, cxCurrencyEdit, ExtCtrls, Grids, DBGrids, StdCtrls,
  ExtActns, StdActns, cxRichEdit, JvExStdCtrls, JvCombobox, JvColorCombo,
  TB2Item, TBX, TB2Dock, TB2Toolbar, uDAInterfaces;

type
  IViewDetallesBase = interface(IViewBase)
  ['{852EB860-13B6-4355-A6B0-4542AB16896F}']
    procedure ExpandirTodo;
    procedure ContraerTodo;
    procedure AjustarAncho;

    procedure SaveGridStatus;
    procedure RestoreGridStatus;

    procedure RestoreFromIniFile;
    procedure StoreToIniFile;

    procedure BeginUpdate;
    procedure EndUpdate;

    function IsEmpty : Boolean;

    function GetFocusedView : TcxGridDBTableView;
    property _FocusedView : TcxGridDBTableView read GetFocusedView;

    function GetGrid : TcxGrid;
    property _Grid : TcxGrid read GetGrid;
  end;

  TfrViewDetallesBase = class(TfrViewBase, IViewDetallesBase)
    ActionListContenido: TActionList;
    DADataSource: TDADataSource;
    actAnadir: TAction;
    actEliminar: TAction;
    actSubir: TAction;
    actBajar: TAction;
    ContenidoImageList: TPngImageList;
    ToolBar1: TToolBar;
    cxStyleRepository: TcxStyleRepository;
    cxStyleEven: TcxStyle;
    cxStyleOdd: TcxStyle;
    cxStyleSelection: TcxStyle;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    cxGrid: TcxGrid;
    cxGridView: TcxGridDBTableView;
    cxGridViewID: TcxGridDBColumn;
    cxGridViewPOSICION: TcxGridDBColumn;
    cxGridViewTIPO: TcxGridDBColumn;
    cxGridViewDESCRIPCION: TcxGridDBColumn;
    cxGridViewCANTIDAD: TcxGridDBColumn;
    cxGridViewIMPORTEUNIDAD: TcxGridDBColumn;
    cxGridViewIMPORTETOTAL: TcxGridDBColumn;
    cxGridViewVISIBLE: TcxGridDBColumn;
    cxGridLevel: TcxGridLevel;
    RichEditBold1: TRichEditBold;
    RichEditItalic1: TRichEditItalic;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    RichEditUnderline1: TRichEditUnderline;
    RichEditAlignLeft1: TRichEditAlignLeft;
    RichEditAlignRight1: TRichEditAlignRight;
    RichEditAlignCenter1: TRichEditAlignCenter;
    ToolButton8: TToolButton;
    ToolButton9: TToolButton;
    ToolButton10: TToolButton;
    ToolButton11: TToolButton;
    ToolButton12: TToolButton;
    ToolButton13: TToolButton;
    FontEdit1: TFontEdit;
    ToolButton14: TToolButton;
    UpDown1: TUpDown;
    FontSize: TEdit;
    FontName: TJvFontComboBox;
    TBXDock1: TTBXDock;
    TBXToolbar1: TTBXToolbar;
    TBXItem1: TTBXItem;
    TBXItem2: TTBXItem;
    TBXSeparatorItem1: TTBXSeparatorItem;
    TBXItem3: TTBXItem;
    TBXItem4: TTBXItem;
    TBXSeparatorItem2: TTBXSeparatorItem;
    TBXItem5: TTBXItem;
    TBXItem6: TTBXItem;
    TBXItem7: TTBXItem;
    TBXSeparatorItem3: TTBXSeparatorItem;
    TBXItem8: TTBXItem;
    TBXSeparatorItem4: TTBXSeparatorItem;
    TBXItem9: TTBXItem;
    TBXItem10: TTBXItem;
    TBXItem11: TTBXItem;
    cxStyle_IMPORTETOTAL: TcxStyle;
    cxStyle_SUBTOTAL: TcxStyle;
    cxStyle_TITULO: TcxStyle;
    RichEditAlignRight2: TRichEditAlignRight;
    actAnchoAutomatico: TAction;
    TBXSeparatorItem5: TTBXSeparatorItem;
    TBXItem13: TTBXItem;
    cxStyle_DESCUENTO: TcxStyle;
    cxStyleDesactivado: TcxStyle;
    cxGridViewVISIBLE2: TcxGridDBColumn;

    procedure actAnadirExecute(Sender: TObject);
    procedure actEliminarExecute(Sender: TObject);
    procedure actSubirExecute(Sender: TObject);
    procedure actBajarExecute(Sender: TObject);
    procedure actEliminarUpdate(Sender: TObject);
    procedure actSubirUpdate(Sender: TObject);
    procedure actBajarUpdate(Sender: TObject);
    procedure actAnadirUpdate(Sender: TObject);

    procedure cxGridViewEditValueChanged(Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem);
    procedure cxGridViewEditKeyDown(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit; var Key: Word;
      Shift: TShiftState);
    procedure FontEdit1BeforeExecute(Sender: TObject);
    procedure FontEdit1Accept(Sender: TObject);

    procedure CustomViewCreate(Sender: TObject);
    procedure CustomViewDestroy(Sender: TObject);
    procedure FontSizeChange(Sender: TObject);
    procedure FontNameChange(Sender: TObject);

    procedure cxGridViewEditing(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; var AAllow: Boolean);
    procedure cxGridViewStylesGetContentStyle(Sender: TcxCustomGridTableView;
      ARecord: TcxCustomGridRecord; AItem: TcxCustomGridTableItem;
      out AStyle: TcxStyle);
    procedure TBXItem13Click(Sender: TObject);
    procedure actAnchoAutomaticoExecute(Sender: TObject);
    procedure actAnchoAutomaticoUpdate(Sender: TObject);
    procedure cxGridViewInitEdit(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit);
    procedure cxGridViewKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);

  private
    FController : IControllerDetallesBase;
    FDetalles: IDAStronglyTypedDataTable;
    FGridStatus: TcxGridStatus;
    CurEdit: TcxRichEdit;
    FUpdating: Boolean;
    function CurrText: TTextAttributes;
    procedure OnSelectChange(Sender:TObject);

    function GetController: IControllerDetallesBase;
    procedure SetController(const Value: IControllerDetallesBase);
    function GetDetalles: IDAStronglyTypedDataTable;
    procedure SetDetalles(const Value: IDAStronglyTypedDataTable);

    function darPosicionCAMPO(const Nombre:String): Integer;
    function darListaSeleccionados: TIntegerArray;

    procedure TratamientoTeclas(Key: Word; Shift: TShiftState; AItem: TcxCustomGridTableItem = nil);
    procedure BestFitAllColumns;
  protected
    function HayQueRecalcular(AItem: TcxCustomGridTableItem): Boolean; virtual;
    function EsTipoEditable(AItem: TcxCustomGridTableItem): Boolean; virtual;
    function DarTipoConcepto(ARecord: TcxCustomGridRecord): string; virtual;
    function DarFuentePorDefecto(const ATipo : String = TIPO_DETALLE_CONCEPTO): TFont; virtual;
    function GetFocusedView : TcxGridDBTableView; virtual;
    function GetGrid : TcxGrid; virtual;

    procedure SeleccionarRowActual;

  public
    procedure BeginUpdate;
    procedure EndUpdate;
    procedure SaveGridStatus;
    procedure RestoreGridStatus;
    procedure RestoreFromIniFile;
    procedure StoreToIniFile;
    procedure ExpandirTodo;
    procedure ContraerTodo;
    procedure AjustarAncho;
    function IsEmpty : Boolean;
    destructor Destroy; override;
    property _FocusedView : TcxGridDBTableView read GetFocusedView;
    property _Grid : TcxGrid read GetGrid;
    property Controller: IControllerDetallesBase read GetController write SetController;
    property Detalles: IDAStronglyTypedDataTable read GetDetalles write SetDetalles;

  end;

implementation
{$R *.dfm}

uses
  uCalculosUtils, uSistemaFunc, SHFolder, uAppInfoUtils;

function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
  FontType: Integer; Data: Pointer): Integer; stdcall;
begin
  TStrings(Data).Add(LogFont.lfFaceName);
  Result := 1;
end;


procedure TfrViewDetallesBase.actAnadirExecute(Sender: TObject);
var
  bEsMultiSelect : Boolean;
begin
  // Debo quitar el multiselect porque provoca que se quede seleccionado
  // el registro actual y no el nuevo registro que voy a añadir
  bEsMultiSelect := cxGridView.OptionsSelection.MultiSelect;
  if bEsMultiSelect then
    cxGridView.OptionsSelection.MultiSelect := False;

  cxGridView.BeginUpdate;
  try
    if cxGridView.Controller.EditingController.IsEditing then
       cxGridView.Controller.EditingController.Edit.PostEditValue;

    if Assigned(Controller)
    and Assigned(FDetalles) then
        Controller.add(FDetalles, TIPO_DETALLE_CONCEPTO);
  finally
    cxGridView.EndUpdate;

    // Dejo la propiedad MultiSelect como estaba
    if bEsMultiSelect then
       cxGridView.OptionsSelection.MultiSelect := bEsMultiSelect;
  end;
end;

procedure TfrViewDetallesBase.actEliminarExecute(Sender: TObject);
var
  AuxTop, AuxRow:Integer;

begin
  cxGridView.BeginUpdate;
  try
    if Assigned(Controller)
    and Assigned(FDetalles) then
    begin
      AuxTop := cxGridView.Controller.TopRowIndex;
      AuxRow := cxGridView.DataController.FocusedRowIndex;

      Controller.delete(FDetalles, darListaSeleccionados);

      if(FDetalles.RecordCount > 0) then
      begin
        //Selecciona en el grid el registro siguiente
        if (AuxRow < cxGridView.DataController.RowCount-1) then
           Inc(AuxRow)
        else
           Dec(AuxRow);

        cxGridView.DataController.SelectRows(AuxRow,AuxRow);
        cxGridView.Controller.TopRowIndex := AuxTop;
      end;
    end
  finally
    cxGridView.EndUpdate;
  end;

  SeleccionarRowActual;
end;

procedure TfrViewDetallesBase.actEliminarUpdate(Sender: TObject);
begin
  if not Assigned(DADataSource.DataTable) then
    (Sender as TAction).Enabled := False
  else
    (Sender as TAction).Enabled := (not ReadOnly)
                                   and (not DADataSource.DataTable.IsEmpty)
end;

procedure TfrViewDetallesBase.actSubirUpdate(Sender: TObject);
begin
  inherited;
  if not Assigned(cxGridView.Controller.FocusedRow) then
    (Sender as TAction).Enabled := False
  else
    (Sender as TAction).Enabled := (not ReadOnly)
                                   and (not cxGridView.Controller.FocusedRow.IsFirst)
end;


procedure TfrViewDetallesBase.BestFitAllColumns;
var
  i : Integer ;

begin
  ShowHourglassCursor;
  _FocusedView.BeginUpdate;

  try
    AsignarAnchosPrefijadosAColumnas(_FocusedView);
    for i := 0 to _FocusedView.VisibleColumnCount-1 do
    begin
      _FocusedView.VisibleColumns[i].ApplyBestFit;
      if (_FocusedView.VisibleColumns[i].BestFitMaxWidth > 0) and
         (_FocusedView.VisibleColumns[i].Width > _FocusedView.VisibleColumns[i].BestFitMaxWidth) then
          _FocusedView.VisibleColumns[i].Width := _FocusedView.VisibleColumns[i].BestFitMaxWidth;
    end;
  finally
    _FocusedView.EndUpdate;
    HideHourglassCursor;
  end;
end;


procedure TfrViewDetallesBase.AjustarAncho;
begin
  if Assigned(_FocusedView) then begin
    BestFitAllColumns;
    _FocusedView.ApplyBestFit;
  end;
end;

procedure TfrViewDetallesBase.BeginUpdate;
begin
  if Assigned(_FocusedView) then
    _FocusedView.BeginUpdate;
end;

function TfrViewDetallesBase.DarTipoConcepto(
  ARecord: TcxCustomGridRecord): string;
var
  IndiceCol : Integer;
begin
  IndiceCol := cxGridView.GetColumnByFieldName(CAMPO_TIPO).Index;
  Result := ARecord.DisplayTexts[IndiceCol];
end;

destructor TfrViewDetallesBase.Destroy;
begin
  FController := NIL;
  FDetalles := NIL;  

  if Assigned(FGridStatus) then
    FreeAndNil(FGridStatus);
  inherited;
end;

procedure TfrViewDetallesBase.ContraerTodo;
begin
  if Assigned(_FocusedView) then
    _FocusedView.ViewData.Collapse(True);
end;

function TfrViewDetallesBase.CurrText: TTextAttributes;
begin
  Result := NIL;
  if Assigned(CurEdit) then
//    if CurEdit.FindSelection then
    if CurEdit.SelLength > 0 then
      Result := CurEdit.SelAttributes
    else
      Result := CurEdit.DefAttributes;
end;

procedure TfrViewDetallesBase.CustomViewCreate(Sender: TObject);
begin
  inherited;

  //Debemos tener la certeza de que las operaciones del grid estan deshabilitadas y que
 	//cuando pulsamos teclas de insercion flecha abajo y demas salta nuestra propia lógia del controlador
 	cxGridView.OptionsData.Appending := False;
 	cxGridView.OptionsData.Deleting := False;
 	cxGridView.OptionsData.Inserting := False;

  CurEdit := Nil;
  FUpdating := False;
end;

procedure TfrViewDetallesBase.CustomViewDestroy(Sender: TObject);
begin
  inherited;
  CurEdit := Nil;
  StoreToIniFile;
end;

procedure TfrViewDetallesBase.cxGridViewEditing(Sender: TcxCustomGridTableView;
  AItem: TcxCustomGridTableItem; var AAllow: Boolean);
begin
  AAllow := EsTipoEditable(AItem);
end;

procedure TfrViewDetallesBase.cxGridViewEditKeyDown(
  Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem;
  AEdit: TcxCustomEdit; var Key: Word; Shift: TShiftState);
begin
  inherited;
  TratamientoTeclas(Key, Shift, AItem);
end;

procedure TfrViewDetallesBase.cxGridViewEditValueChanged(Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem);
begin
  inherited;
  cxGridView.BeginUpdate;
  try
    if HayQueRecalcular(AItem) then
    begin
      if Sender.Controller.EditingController.IsEditing then
         Sender.Controller.EditingController.Edit.PostEditValue;

       Controller.actualizarTotales(Detalles);
    end;
  finally
    cxGridView.EndUpdate;
  end;
end;

procedure TfrViewDetallesBase.cxGridViewInitEdit(Sender: TcxCustomGridTableView;
  AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit);
var
  FuentePorDefecto: TFont;
  ARecord: TcxCustomGridRecord;
  AEditValue : String;
begin
  inherited;

  if AEdit is TcxRichEdit then
  begin
    AEditValue := Trim(VarToStr(AItem.EditValue));
    ARecord := AItem.FocusedCellViewInfo.GridRecord;
    FuentePorDefecto := DarFuentePorDefecto(DarTipoConcepto(ARecord));
    try
      //La primera vez que accedemos al grid entra dos veces y perderiamos el editor
      //dando un pete.
      if not Assigned(CurEdit) then
      begin
        FontEdit1.Enabled := True;
    //    UpDown1.Enabled := True;
    //    FontSize.Enabled := True;
    //    FontName.Enabled := True;

        CurEdit := TcxRichEdit(AEdit);
        if Length(AEditValue) = 0 then
          CurEdit.DefAttributes.Assign(FuentePorDefecto)
      end
      else
        if Length(AEditValue) = 0 then
           CurEdit.DefAttributes.Assign(FuentePorDefecto);
    finally
      FreeAndNil(FuentePorDefecto);
    end;
  end
  else
  begin
    CurEdit := Nil;
    FontEdit1.Enabled := False;
//    UpDown1.Enabled := False;
//    FontSize.Enabled := False;
//    FontName.Enabled := False;
  end;
end;

procedure TfrViewDetallesBase.cxGridViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  inherited;
  TratamientoTeclas(Key, Shift);
end;

procedure TfrViewDetallesBase.cxGridViewStylesGetContentStyle(
  Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
  AItem: TcxCustomGridTableItem; out AStyle: TcxStyle);
var
  ATipo : String;
begin
  AStyle := cxStyleEven;
  if Assigned(ARecord) then
  begin
    ATipo := DarTipoConcepto(ARecord);

    if ((ATipo = TIPO_DETALLE_TITULO) or (ATipo = TIPO_DETALLE_TITULO_OPCIONAL)) then
      AStyle := cxStyle_TITULO;

    if ATipo = TIPO_DETALLE_SUBTOTAL then
      AStyle := cxStyle_SUBTOTAL;

    if ATipo = TIPO_DETALLE_DESCUENTO then
      AStyle := cxStyle_DESCUENTO;

    if ATipo = TIPO_DETALLE_CONCEPTO then
       if (AItem.Index = cxGridView.GetColumnByFieldName(CAMPO_IMPORTE_TOTAL).Index) then
//       or (AItem.Index = cxGridView.GetColumnByFieldName(CAMPO_DESCUENTO).Index)then
          AStyle := cxStyleDesactivado;
  end;
end;

function TfrViewDetallesBase.DarFuentePorDefecto(const ATipo: String): TFont;
begin
  Result := TFont.Create;

  if ATipo = TIPO_DETALLE_CONCEPTO then
  begin
    //SetDesktopIconFonts(Result);
    Result.Name := 'DejaVu Sans Mono';
    Result.Size := 9;
    Result.Style := [];
  end;

  if ((ATipo = TIPO_DETALLE_TITULO) or (ATipo = TIPO_DETALLE_TITULO_OPCIONAL)) then
  begin
    Result.Name := cxStyle_TITULO.Font.Name;
    Result.Color := cxStyle_TITULO.TextColor;
    Result.Size := cxStyle_TITULO.Font.Size;
    Result.Style := cxStyle_TITULO.Font.Style;
  end;

  if ATipo = TIPO_DETALLE_SUBTOTAL then
  begin
    Result.Name := cxStyle_SUBTOTAL.Font.Name;
    Result.Color := cxStyle_SUBTOTAL.TextColor;
    Result.Size := cxStyle_SUBTOTAL.Font.Size;
    Result.Style := cxStyle_SUBTOTAL.Font.Style;
  end;

  if ATipo = TIPO_DETALLE_DESCUENTO then
  begin
    Result.Name := cxStyle_DESCUENTO.Font.Name;
    Result.Color := cxStyle_DESCUENTO.TextColor;
    Result.Size := cxStyle_DESCUENTO.Font.Size;
    Result.Style := cxStyle_DESCUENTO.Font.Style;
  end;
end;

function TfrViewDetallesBase.DarListaSeleccionados: TIntegerArray;
var
  i, j: Integer;
begin
  j := DarPosicionCampo(CAMPO_POSICION);

  with cxGridView.Controller do
       for i:=0 to SelectedRecordCount-1 do
       begin
           SetLength(Result, i+1);
           Result[i] := SelectedRecords[i].Values[j];
       end;
end;

function TfrViewDetallesBase.DarPosicionCAMPO(const Nombre: String): Integer;
var
  i: Integer;
begin
  i:=0;
  while ((cxGridView.Columns[i].DataBinding.FieldName <> Nombre) and
         (i < cxGridView.ColumnCount)) do
    inc(i);

  if (i = cxGridView.ColumnCount) then
    raise Exception.Create('El campo ' + Nombre + ' no se ha encontrado en el grid (uViewDetallesBase)');

  Result := i;
end;

procedure TfrViewDetallesBase.EndUpdate;
begin
  if Assigned(_FocusedView) then
    _FocusedView.EndUpdate;
end;

function TfrViewDetallesBase.EsTipoEditable(AItem: TcxCustomGridTableItem): Boolean;
var
  IndiceCol : Integer;
begin
  Result := True;

  IndiceCol := cxGridView.GetColumnByFieldName(CAMPO_TIPO).Index;
  if (AItem.GridView.Items[IndiceCol].EditValue = TIPO_DETALLE_SUBTOTAL)
  or (AItem.GridView.Items[IndiceCol].EditValue = TIPO_DETALLE_TITULO_OPCIONAL)
  or (AItem.GridView.Items[IndiceCol].EditValue = TIPO_DETALLE_TITULO) then
  begin
    IndiceCol := cxGridView.GetColumnByFieldName(CAMPO_CONCEPTO).Index;
    if AItem.Index > IndiceCol then
       Result := False
  end
  else if (AItem.GridView.Items[IndiceCol].EditValue = TIPO_DETALLE_SALTO) then
  begin
    if AItem.Index >= 0 then
       Result := False
  end
end;

procedure TfrViewDetallesBase.ExpandirTodo;
begin
  if Assigned(_FocusedView) then
    _FocusedView.ViewData.Expand(True);
end;

procedure TfrViewDetallesBase.FontEdit1Accept(Sender: TObject);
begin
  inherited;
  CurrText.Assign(FontEdit1.Dialog.Font);
end;

procedure TfrViewDetallesBase.FontEdit1BeforeExecute(Sender: TObject);
begin
  inherited;
  FontEdit1.Dialog.Font.Assign(CurEdit.SelAttributes);
end;

procedure TfrViewDetallesBase.FontNameChange(Sender: TObject);
begin
  if FUpdating then Exit;
  CurrText.Name := FontName.Items[FontName.ItemIndex];
end;

procedure TfrViewDetallesBase.FontSizeChange(Sender: TObject);
begin
  if FUpdating then Exit;
  CurrText.Size := StrToInt(FontSize.Text);
end;

function TfrViewDetallesBase.GetController: IControllerDetallesBase;
begin
  Result := FController;
end;

function TfrViewDetallesBase.GetDetalles: IDAStronglyTypedDataTable;
begin
  Result := FDetalles;
end;

function TfrViewDetallesBase.GetFocusedView: TcxGridDBTableView;
begin
  Result := cxGridView;
end;

function TfrViewDetallesBase.GetGrid: TcxGrid;
begin
  Result := cxGrid;
end;

function TfrViewDetallesBase.HayQueRecalcular(AItem: TcxCustomGridTableItem): Boolean;
begin
  Result := (AItem = cxGridViewTIPO)
         or (AItem = cxGridViewCANTIDAD)
         or (AItem = cxGridViewIMPORTEUNIDAD);
end;

function TfrViewDetallesBase.IsEmpty: Boolean;
begin
  Result := (_FocusedView.ViewData.RowCount < 1);
end;

procedure TfrViewDetallesBase.OnSelectChange(Sender: TObject);
begin
  if (csDestroying in ComponentState) then
    Exit;

  try
    FUpdating := True;
//    FontSize.Text := IntToStr(CurEdit.SelAttributes.Size);
//    FontName.FontName := CurEdit.SelAttributes.Name;
  finally
    FUpdating := False;
  end;
end;

procedure TfrViewDetallesBase.RestoreFromIniFile;
var
  AIniFile : String;
begin
  inherited;
  if Assigned(_FocusedView) then
  begin

    AIniFile := GetSpecialFolderPath(CSIDL_APPDATA); //[Current Users]\Application Data
    AIniFile := AIniFile + PathDelim + 'Rodax Software' + PathDelim + GetAppName + PathDelim;

    if not DirectoryExists(AIniFile) then
      ForceDirectories(AIniFile);

    _FocusedView.RestoreFromIniFile(AIniFile + 'grid.xml', True, False, []);
  end;
end;

procedure TfrViewDetallesBase.RestoreGridStatus;
begin
  if Assigned(FGridStatus) and (not IsEmpty) then
    FGridStatus.Restore(_FocusedView);
end;

procedure TfrViewDetallesBase.SaveGridStatus;
begin
  FreeAndNil(FGridStatus);
  if not IsEmpty then
    FGridStatus := TcxGridStatus.Create(_FocusedView);
end;

procedure TfrViewDetallesBase.SeleccionarRowActual;
begin
  //Quitamos lo que hubiera seleccionado
  cxGrid.ActiveView.DataController.ClearSelection;
  with cxGrid.ActiveView.DataController do
       if RowCount > 0 then
          SelectRows(GetFocusedRowIndex,GetFocusedRowIndex);
end;

procedure TfrViewDetallesBase.SetController(const Value: IControllerDetallesBase);
var
  AListaValores : TStringList;
  AItem : TcxImageComboBoxItem;
  i: integer;
  DC: HDC;
begin
  FController := Value;

  //Rellenamos los tipos de letra que tenemos
  FontName.Items.Clear;
  DC := GetDC(0);
  EnumFonts(DC, nil, @EnumFontsProc, Pointer(FontName.Items));
  ReleaseDC(0, DC);
  FontName.Sorted := True;

  //Rellenamos los tipos de conceptos que hay
  if Assigned(FController) then
  begin
    AListaValores := FController.DarListaTIPOSDETALLE;
    with (cxGridViewTIPO.Properties as TcxImageComboBoxProperties) do
    if Items.Count = 0 then
    begin
      Items.BeginUpdate;
      try
        Items.Clear;
        for i:=0 to AListaValores.Count-1 do
        begin
          AItem := Items.Add;
          AItem.Tag := i;
          AItem.Description := AListaValores.ValueFromIndex[i];
          AItem.Value := AListaValores.Names[i];
        end;
      finally
        DefaultDescription := AListaValores.ValueFromIndex[0];
        FreeAndNil(AListaValores);
        Items.EndUpdate;
      end;
    end;
  end;
end;

procedure TfrViewDetallesBase.SetDetalles(const Value: IDAStronglyTypedDataTable);
begin
  FDetalles := Value;
  if Assigned(FDetalles) then
  begin
    DADataSource.DataTable := FDetalles.DataTable;
    RestoreFromIniFile; // la restauración de las columnas sólo funciona cuando hay datos.
    AjustarAncho;
  end
  else
    DADataSource.DataTable := NIL;
end;

procedure TfrViewDetallesBase.StoreToIniFile;
var
  AIniFile : String;
begin
  inherited;

  if Assigned(_FocusedView) then
  begin

    AIniFile := GetSpecialFolderPath(CSIDL_APPDATA); //[Current Users]\Application Data
    AIniFile := AIniFile + PathDelim + 'Rodax Software' + PathDelim + GetAppName + PathDelim;

    if not DirectoryExists(AIniFile) then
      ForceDirectories(AIniFile);

      _FocusedView.StoreToIniFile(AIniFile + 'grid.xml', False, []);
//      _FocusedView.StoreToRegistry(Path + '\\GridSettings\\' + Self.Name, False, [], Self.Name);
  end;
end;

procedure TfrViewDetallesBase.TBXItem13Click(Sender: TObject);
begin
  inherited;
  if cxGridView.Controller.EditingController.IsEditing then
    cxGridView.Controller.EditingController.Edit.PostEditValue;
end;

procedure TfrViewDetallesBase.TratamientoTeclas(Key: Word; Shift: TShiftState;
  AItem: TcxCustomGridTableItem);
begin
  cxGridView.BeginUpdate;
  try
    case Key of
    VK_DOWN  : begin
                  //En el caso de ser la última fila hacemos un append nosotros no el grid
                  //ya que se saltaria la lógica del controllerDetallesBase
                  if cxGridView.Controller.IsFinish then
                  begin
                    Key := 0;
                    if _FocusedView.Controller.EditingController.IsEditing then
                       _FocusedView.Controller.EditingController.Edit.PostEditValue;
                    actAnadir.Execute;
                  end;

                  //Baja los conceptos seleccionados
                  if Shift = [ssAlt] then
                  begin
                     Key := 0;
                     actBajar.Execute;
                  end;
               end;
    VK_UP    : begin
                  //Sube los conceptos seleccionados
                  if Shift = [ssAlt] then
                  begin
                     Key := 0;
                     actSubir.Execute;
                  end;
               end;

    VK_RETURN, VK_RIGHT
             : begin
                  //En el caso de ser la última fila hacemos un append nosotros no el grid
                  //ya que se saltaria la lógica del controllerDetallesBase
                  if Assigned(AItem) and
                  cxGridView.Controller.IsFinish and AItem.IsLast then
                  begin
                    Key := 0;
                    if  _FocusedView.Controller.EditingController.IsEditing then
                       _FocusedView.Controller.EditingController.Edit.PostEditValue;
                    actAnadir.Execute;
                  end;
              end;
    end;
  finally
    cxGridView.EndUpdate;
  end;
end;

procedure TfrViewDetallesBase.actAnadirUpdate(Sender: TObject);
begin
  inherited;
  (Sender as TAction).Enabled := not ReadOnly;
end;

procedure TfrViewDetallesBase.actAnchoAutomaticoExecute(Sender: TObject);
begin
  inherited;
  cxGridView.ApplyBestFit;
end;

procedure TfrViewDetallesBase.actAnchoAutomaticoUpdate(Sender: TObject);
begin
  inherited;
  (Sender as TAction).Enabled := not IsEmpty;
end;

procedure TfrViewDetallesBase.actBajarExecute(Sender: TObject);
begin
  cxGridView.BeginUpdate;
  try
    if cxGridView.Controller.EditingController.IsEditing then
       cxGridView.Controller.EditingController.Edit.PostEditValue;

    if Assigned(Controller)
    and Assigned(FDetalles) then
       Controller.move(FDetalles, darListaSeleccionados, 1);
  finally
    cxGridView.EndUpdate;
  end;
end;

procedure TfrViewDetallesBase.actBajarUpdate(Sender: TObject);
begin
  inherited;
  if not Assigned(cxGridView.Controller.FocusedRow) then
    (Sender as TAction).Enabled := False
  else
    (Sender as TAction).Enabled := (not ReadOnly)
                                   and (not cxGridView.Controller.FocusedRow.IsLast)
end;

procedure TfrViewDetallesBase.actSubirExecute(Sender: TObject);
begin
  cxGridView.BeginUpdate;
  try
    if cxGridView.Controller.EditingController.IsEditing then
       cxGridView.Controller.EditingController.Edit.PostEditValue;

    if Assigned(Controller) and Assigned(FDetalles) then
      Controller.Move(FDetalles, DarListaSeleccionados, -1);
  finally
    cxGridView.EndUpdate;
  end;
end;

end.
