﻿unit fusuarios;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.DBCtrls, Vcl.StdCtrls, Vcl.ExtCtrls,
  Data.DB, ZDataset, ZAbstractRODataset, ZAbstractDataset, Vcl.Grids,
  Vcl.DBGrids;

type
  TDBGridCrack = class(TDBGrid);
  Tusuarios = class(TForm)
    DBGrid1: TDBGrid;
    dsqusuarios: TDataSource;
    qusuarios: TZQuery;
    qtrabajadores: TZReadOnlyQuery;
    qgrupos: TZReadOnlyQuery;
    dsqtrabajadores: TDataSource;
    dsqgrupos: TDataSource;
    qusuariosid: TIntegerField;
    qusuariosnombre: TWideStringField;
    qusuariosnif: TWideStringField;
    qusuariosempresa: TIntegerField;
    qusuariosdireccion: TWideStringField;
    qusuariosprovin: TWideStringField;
    qusuarioscity: TWideStringField;
    qusuarioscp: TWideStringField;
    qusuariosphone: TWideStringField;
    qusuariosmovil: TWideStringField;
    qusuariosusuario: TWideStringField;
    qusuarioscontra: TWideStringField;
    qusuariosadministrador: TIntegerField;
    qusuariosgestorgrupo: TIntegerField;
    qusuariosgrupo: TIntegerField;
    qusuariosgestorindividual: TIntegerField;
    qusuariosidemp: TIntegerField;
    qusuariosactive: TIntegerField;
    qmaxusuario: TZReadOnlyQuery;
    Panel7: TPanel;
    btAcancelar: TButton;
    btAmodificar: TButton;
    btAborrar: TButton;
    btAnuevo: TButton;
    btAguardar: TButton;
    combotrabajadores: TDBLookupComboBox;
    combogrupos: TDBLookupComboBox;
    qusuariosnomgrupo: TWideStringField;
    qusuariosnomtrabajador: TWideStringField;
    gcrpagado: TDBCheckBox;
    qgruposide: TIntegerField;
    qgruposid: TIntegerField;
    qgruposdescripcion: TWideStringField;
    qtrabajadoreside: TIntegerField;
    qtrabajadoresid: TSmallintField;
    qtrabajadoresnif: TWideStringField;
    qtrabajadoresnombre: TWideStringField;
    qtrabajadoresresponsable: TIntegerField;
    qtrabajadoresfumigador: TIntegerField;
    qmaxusuarioid: TLargeintField;
    qusuariosfumigador: TIntegerField;
    qusuariostecnico: TIntegerField;
    Button1: TButton;
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure FormShow(Sender: TObject);
    procedure DBGrid1CellClick(Column: TColumn);
    procedure btAnuevoClick(Sender: TObject);
    procedure btAborrarClick(Sender: TObject);
    procedure btAmodificarClick(Sender: TObject);
    procedure btAguardarClick(Sender: TObject);
    procedure btAcancelarClick(Sender: TObject);
    procedure qusuariosBeforePost(DataSet: TDataSet);
    procedure qusuariosAfterInsert(DataSet: TDataSet);
    procedure Button1Click(Sender: TObject);
    procedure DBGrid1ColEnter(Sender: TObject);
    procedure DBGrid1ColExit(Sender: TObject);
  private
    { Private declarations }
    procedure ActualizarControlFlotante(Control: TWinControl; Rect: TRect);
  public
    { Public declarations }
  end;

var
  usuarios: Tusuarios;
const
  rojo = $00AAAAFF;
  amarillo = $00B9FFFF;
  verde = $00C7FBAA;
  azul = $00FFFFBB;


implementation

uses funciones;

{$R *.dfm}




// --- Implementación de las funciones ---

// --- Implementación de la función (Versión a prueba de balas para XE3) ---

// --- NUEVA IMPLEMENTACIÓN - A PRUEBA DE ERRORES ---
// Esta versión no usa TArray<Char> ni SetLength



procedure Tusuarios.btAborrarClick(Sender: TObject);
begin
  qusuarios.Delete;
end;

procedure Tusuarios.btAcancelarClick(Sender: TObject);
begin
  qusuarios.Cancel;
end;

procedure Tusuarios.btAguardarClick(Sender: TObject);
begin
  qusuarios.Post;
end;

procedure Tusuarios.btAmodificarClick(Sender: TObject);
begin
  qusuarios.Edit;
end;

procedure Tusuarios.btAnuevoClick(Sender: TObject);
begin
  dbgrid1.SetFocus;
  qusuarios.Append;

end;

procedure Tusuarios.Button1Click(Sender: TObject);
var pass:string;
begin
  pass:=GenerarContraseñaSegura;
  qusuarios.Edit;
  qusuarioscontra.Value:=pass;
end;

{procedure Tusuarios.DBGrid1CellClick(Column: TColumn);
begin
    if column.Field.FieldName ='fumigador' then
    begin
        if qusuariosfumigador.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariosfumigador.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariosfumigador.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
    if column.Field.FieldName ='tecnico' then
    begin
        if qusuariostecnico.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariostecnico.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariostecnico.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
    if column.Field.FieldName ='active' then
    begin
        if qusuariosactive.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariosactive.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariosactive.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
    if column.Field.FieldName ='gestorindividual' then
    begin
        if qusuariosgestorindividual.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariosgestorindividual.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariosgestorindividual.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
    if column.Field.FieldName ='gestorgrupo' then
    begin
        if qusuariosgestorgrupo.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariosgestorgrupo.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariosgestorgrupo.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
    if column.Field.FieldName ='administrador' then
    begin
        if qusuariosadministrador.asinteger=1 then
         begin
           qusuarios.Edit;
           qusuariosadministrador.Value:=0;
           qusuarios.Post;
         end else
               begin
                 qusuarios.Edit;
                 qusuariosadministrador.Value:=1;
                 qusuarios.Post;
                 qusuarios.Refresh;
                 dbgrid1.SelectedIndex:=1;
               end;
    end;
  dbgrid1.SelectedIndex:=1;
end;
}
procedure Tusuarios.DBGrid1CellClick(Column: TColumn);
var
  FieldName: string;
begin
  FieldName := Column.FieldName;

  // Lista de campos que se comportan como CheckBox
  if (FieldName = 'fumigador') or (FieldName = 'tecnico') or
     (FieldName = 'active') or (FieldName = 'gestorindividual') or
     (FieldName = 'gestorgrupo') or (FieldName = 'administrador') then
  begin
    qusuarios.Edit;
    // Invertimos el valor: si es 1 pasa a 0, si es 0 pasa a 1
    if Column.Field.AsInteger = 1 then
      Column.Field.AsInteger := 0
    else
      Column.Field.AsInteger := 1;
    qusuarios.Post;
    DBGrid1.SelectedIndex := 0;

    
  end;
end;
procedure Tusuarios.DBGrid1ColEnter(Sender: TObject);
begin
// Verificamos que estamos en la columna de la contraseña
if DBGrid1.SelectedField.FieldName = 'contra' then
  begin
    // Forzamos al Grid a entrar en modo edición inmediatamente
    // Esto hace que el InplaceEditor se cree ANTES de que el usuario escriba
    DBGrid1.EditorMode := True;

    if TDBGridCrack(DBGrid1).InplaceEditor <> nil then
    begin
      SendMessage(TDBGridCrack(DBGrid1).InplaceEditor.Handle, EM_SETPASSWORDCHAR, Ord('*'), 0);

    end;
  end;
end;

procedure Tusuarios.DBGrid1ColExit(Sender: TObject);
begin
  if TDBGridCrack(DBGrid1).InplaceEditor <> nil then
  begin
    // Al poner 0, desactivamos el modo password para la siguiente celda
    SendMessage(TDBGridCrack(DBGrid1).InplaceEditor.Handle, EM_SETPASSWORDCHAR, 0, 0);
  end;
end;

{procedure Tusuarios.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const IsChecked : array[Boolean] of Integer =
 (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
  DrawState,imgindex,bmpwidth: Integer;
  DrawRect: TRect;
  s: string;
begin
if Column.FieldName = 'contra' then
  begin
    // Dibujamos el fondo estándar del Grid
    DBGrid1.Canvas.FillRect(Rect);

    // Si el campo no está vacío, creamos una cadena de asteriscos
    if not Column.Field.IsNull then
    begin
      // Creamos una cadena de '*' con la misma longitud que el texto original
      S := StringOfChar('*', 10);

      // Dibujamos el texto de asteriscos en el grid
      DBGrid1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, S);
    end;
  end
  else
    // Si no es la columna de password, que dibuje normal
    DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
    if (qusuariosactive.Asinteger=0)then
    begin
        DBGrid1.Canvas.brush.Color := rojo;
    end else DBGrid1.Canvas.brush.Color := verde;
    DBgrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'fumigador') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'fumigador') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;
if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'tecnico') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'tecnico') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;


if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'active') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'active') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;
if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'gestorindividual') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'gestorindividual') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;
if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'gestorgrupo') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'gestorgrupo') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;
if (gdFocused in State) then
begin

    if (Column.Field.FieldName = 'administrador') then
     begin
       gcrpagado.Left := Rect.Left + DBgrid1.Left + 2;
       gcrpagado.Top := Rect.Top + DBgrid1.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin

       if (Column.Field.FieldName = 'administrador') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         DBgrid1.Canvas.FillRect(Rect);
         DrawFrameControl(DBgrid1.Canvas.Handle, DrawRect,DFC_BUTTON, DrawState);
       end;
    end;
  gcrpagado.visible:=false;
  if (gdFocused in State) then
  begin
    if (Column.Field.FieldName = combogrupos.DataField) then
    with combogrupos do
    begin
      Left := Rect.Left + DBgrid1.Left + 2;
      Top := Rect.Top + DBgrid1.Top + 2;
      Width := Rect.Right - Rect.Left;
      Width := Rect.Right - Rect.Left;
      Height := Rect.Bottom - Rect.Top;
      Visible := True;
      setfocus;
      dropdown;
    end else combogrupos.Visible:=false;
    if (Column.Field.FieldName = combotrabajadores.DataField) then
    with combotrabajadores do
    begin
      Left := Rect.Left + DBgrid1.Left + 2;
      Top := Rect.Top + DBgrid1.Top + 2;
      Width := Rect.Right - Rect.Left;
      Width := Rect.Right - Rect.Left;
      Height := Rect.Bottom - Rect.Top;
      Visible := True;
      setfocus;
      dropdown;
    end else combotrabajadores.Visible:=false;

  end;
end;  }
procedure Tusuarios.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
  IsChecked : array[Boolean] of Integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
  DrawState: Integer;
  DrawRect: TRect;
  S: string;
begin
if (gdFocused in State) and (Column.FieldName = 'contra') then
  begin
    // Usamos el Crack para llegar al editor
    if TDBGridCrack(DBGrid1).InplaceEditor <> nil then
    begin
      // Enviamos el mensaje varias veces o con un ligero retardo
      // para asegurar que el Grid no lo sobrescriba
      PostMessage(TDBGridCrack(DBGrid1).InplaceEditor.Handle, EM_SETPASSWORDCHAR, Ord('*'), 0);

      // Forzamos a que el editor se entere del cambio de estilo inmediatamente
      TDBGridCrack(DBGrid1).InplaceEditor.Invalidate;
    end;
  end;

  // Tu código de dibujo de asteriscos cuando NO se está editando
  if (Column.FieldName = 'contra') and not (gdFocused in State) then
  begin
    DBGrid1.Canvas.FillRect(Rect);
    if not Column.Field.IsNull then
    begin
      S := StringOfChar('*', 10);
      DBGrid1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, S);
    end;
  end;
  // 1. LÓGICA DE COLORES DE FONDO (Primero que nada)
  if qusuariosactive.AsInteger = 0 then
    DBGrid1.Canvas.Brush.Color := rojo
  else
    DBGrid1.Canvas.Brush.Color := verde;

  // Si la celda está seleccionada, mantenemos el color de selección estándar o uno personalizado
  if gdSelected in State then
    DBGrid1.Canvas.Brush.Color := clHighlight;

  DBGrid1.Canvas.FillRect(Rect);

  // 2. DIBUJO DE CAMPOS ESPECIALES

  // Caso A: Contraseña
  if Column.FieldName = 'contra' then
  begin
    if not Column.Field.IsNull then
    begin
      S := StringOfChar('*', 10);
      DBGrid1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, S);
    end;
  end

  // Caso B: Checkboxes (Fumigador, Tecnico, Active, etc.)
  else if (Column.FieldName = 'fumigador') or (Column.FieldName = 'tecnico') or
          (Column.FieldName = 'active') or (Column.FieldName = 'gestorindividual') or (Column.FieldName = 'gestorgrupo') or (Column.FieldName = 'administrador') then // ...añadir los demás
  begin
    DrawRect := Rect;
    InflateRect(DrawRect, -2, -2); // Margen para el checkbox

    DrawState := IsChecked[Column.Field.AsInteger = 1];

    // Dibujamos el frame del checkbox directamente en el Canvas del Grid
    DrawFrameControl(DBGrid1.Canvas.Handle, DrawRect, DFC_BUTTON, DrawState);
  end

  // Caso C: Dibujo por defecto para el resto de columnas
  else
  begin
    DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
  end;

  // 3. POSICIONAMIENTO DE CONTROLES (ComboBoxes)
  // Solo si la celda tiene el foco
  if (gdFocused in State) then
  begin
    if (Column.FieldName = combogrupos.DataField) then
      ActualizarControlFlotante(combogrupos, Rect)
    else
      combogrupos.Visible := False;

    if (Column.FieldName = combotrabajadores.DataField) then
      ActualizarControlFlotante(combotrabajadores, Rect)
    else
      combotrabajadores.Visible := False;
  end;
end;

// Procedimiento auxiliar para no repetir código de posicionamiento
procedure Tusuarios.ActualizarControlFlotante(Control: TWinControl; Rect: TRect);
begin
  Control.Left := Rect.Left + DBGrid1.Left + 1;
  Control.Top := Rect.Top + DBGrid1.Top + 1;
  Control.Width := (Rect.Right - Rect.Left) + 1;
  Control.Height := (Rect.Bottom - Rect.Top) + 1;

  if not Control.Visible then
  begin
    Control.Visible := True;
    Control.SetFocus; // Para que el usuario pueda empezar a escribir/seleccionar de inmediato

    // Si es un combo, podemos forzar que se despliegue automáticamente
    if Control is TDBLookupComboBox then
      TDBLookupComboBox(Control).DropDown;
  end;
end;

procedure Tusuarios.FormKeyPress(Sender: TObject; var Key: Char);
begin
   key:=upcase(key);
    if (key='.') and (activecontrol is tdbgrid) then
    begin
        key:=','
    end;
    if (activecontrol is tdbgrid) then
    begin
        if Key = #13 then Key :=#9;
    end;

    if (key=#13) then
    begin
        Perform(WM_NextDLGCtl,0,0);
        key:=#0;
    end;
// si presionamos ESC
    if (key=#$1B)  and (activecontrol is tdblookupcombobox )then
    begin
      activecontrol.Visible:=false;
    end;
end;

procedure Tusuarios.FormShow(Sender: TObject);
begin
  qtrabajadores.Open;
  qgrupos.Open;
  qusuarios.Open;
end;

procedure Tusuarios.qusuariosAfterInsert(DataSet: TDataSet);
begin
  qmaxusuario.Close;
  qmaxusuario.Open;
  qusuariosid.Value:=qmaxusuarioid.AsInteger;
end;

procedure Tusuarios.qusuariosBeforePost(DataSet: TDataSet);
var pass:string;
begin
    pass:=qusuarioscontra.AsString;
    qusuariosgrupo.Value:=qgruposid.AsInteger;
    qusuariosidemp.Value:=qtrabajadoresid.AsInteger;
    qusuariosnif.Value:=qtrabajadoresnif.AsString;
    qusuariosnombre.Value:=qtrabajadoresnombre.AsString;
    if validarcontraseña(pass)=false then showmessage ('La contraseña no cumple con los requisitos');
end;
initialization
  // Inicializa el generador de números aleatorios.
  Randomize;


end.
