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,

   uControllerDetallesBase, cxCurrencyEdit, ExtCtrls, Grids, DBGrids, StdCtrls,
  ExtActns, StdActns, cxRichEdit, JvExStdCtrls, JvCombobox, JvColorCombo,
  TB2Item, TBX, TB2Dock, TB2Toolbar, Menus;

type
  IViewDetallesBase = interface(IViewBase)
  ['{852EB860-13B6-4355-A6B0-4542AB16896F}']
  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;
    ToolButton5: TToolButton;
    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;
    TBXItem13: TTBXItem;
    RichEditAlignRight2: TRichEditAlignRight;
    GridPopupMenu: TPopupMenu;
    Modificar1: TMenuItem;
    Duplicar1: TMenuItem;
    N1: TMenuItem;
    Eliminar1: TMenuItem;
    Subir1: TMenuItem;
    Subir2: TMenuItem;

    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 cxGridViewEditValueChanged(Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem);
    procedure cxGridViewEditKeyDown(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit; var Key: Word;
      Shift: TShiftState);

    procedure cxGridViewInitEdit(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit);
    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);

  private
    FController : IControllerDetallesBase;
    FDetalles: IDAStronglyTypedDataTable;

    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;

  protected
    function HayQueRecalcular(AItem: TcxCustomGridTableItem): Boolean; virtual;
    function EsTipoEditable(AItem: TcxCustomGridTableItem): Boolean; virtual;
    function darTipoLetraPorDefecto: TFont; virtual;

  public
    property Controller: IControllerDetallesBase read GetController write SetController;
    property Detalles: IDAStronglyTypedDataTable read GetDetalles write SetDetalles;

  end;

implementation
{$R *.dfm}

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);
begin
  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;
  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);

      //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
  finally
    cxGridView.EndUpdate;
  end;
end;

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

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

function TfrViewDetallesBase.darTipoLetraPorDefecto: TFont;
begin
  Result := TFont.Create;
  Result.Name := 'Tahoma';
  Result.Size := 10;
end;

function TfrViewDetallesBase.CurrText: TTextAttributes;
begin
  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;
  CurEdit := Nil;
  FUpdating := False;
end;

procedure TfrViewDetallesBase.CustomViewDestroy(Sender: TObject);
begin
  CurEdit := Nil;
  FUpdating := False;  
  inherited;
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;
  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 Sender.Controller.EditingController.IsEditing then
                       Sender.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 cxGridView.Controller.IsFinish
                  and AItem.IsLast then
                  begin
                    Key := 0;
                    if Sender.Controller.EditingController.IsEditing then
                       Sender.Controller.EditingController.Edit.PostEditValue;
                    actAnadir.Execute;
                  end;
              end;
    end;
  finally
    cxGridView.EndUpdate;
  end;
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;
begin
  inherited;

  if AEdit is TcxRichEdit then
  begin
    FuentePorDefecto := darTipoLetraPorDefecto;
    //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(CurEdit.Text) = 0 then
         CurEdit.DefAttributes.Assign(FuentePorDefecto)
    end
    else
      if length(CurEdit.Text) = 0 then
         CurEdit.DefAttributes.Assign(FuentePorDefecto);

    FreeAndNil(FuentePorDefecto);
  end
  else
  begin
    CurEdit := Nil;
    FontEdit1.Enabled := False;
//    UpDown1.Enabled := False;
//    FontSize.Enabled := False;
//    FontName.Enabled := False;
  end;
end;

procedure TfrViewDetallesBase.cxGridViewStylesGetContentStyle(
  Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
  AItem: TcxCustomGridTableItem; out AStyle: TcxStyle);
var
  IndiceCol : Integer;
  ATipo : String;
begin
  if Assigned(ARecord) then
  begin
    IndiceCol := cxGridViewTIPO.Index;
    ATipo := VarToStr(ARecord.Values[IndiceCol]);
    if ATipo = TIPO_DETALLE_SUBTOTAL then
      AStyle := cxStyle_SUBTOTAL;
    if ATipo = TIPO_DETALLE_TITULO then
      AStyle := cxStyle_TITULO;
  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
  Result := -1;

  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;

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_SALTO) then
  begin
    IndiceCol := cxGridView.GetColumnByFieldName(CAMPO_CONCEPTO).Index;
    if AItem.Index >= IndiceCol then
       Result := False
  end
  else
  begin
    if (AItem.GridView.Items[IndiceCol].EditValue = TIPO_DETALLE_SUBTOTAL)
    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
  end;
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.HayQueRecalcular(AItem: TcxCustomGridTableItem): Boolean;
begin
  Result := (AItem = cxGridViewTIPO)
         or (AItem = cxGridViewCANTIDAD)
         or (AItem = cxGridViewIMPORTEUNIDAD);
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.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
    DADataSource.DataTable := FDetalles.DataTable
  else
    DADataSource.DataTable := NIL;
end;

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

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 Assigned(cxGridView.Controller.FocusedRow) then
    (Sender as TAction).Enabled := not (cxGridView.Controller.FocusedRow.IsLast)
  else
    (Sender as TAction).Enabled := False;
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.
