Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   TreeView para manejar perfiles de usuario (https://www.clubdelphi.com/foros/showthread.php?t=46755)

martinzcr 08-08-2007 00:38:39

TreeView para manejar perfiles de usuario
 
Hola Foro!

Tengo un sistema dividido en varios módulos. El sistema tiene control de acceso y cada usuario tiene un perfil que le permite o no ingresar a ciertos módulos y ejecutar ciertas tareas.

Tengo una tabla de usuarios y una de perfiles. Cada usuario esta relacionado con un perfil.

La cuestión es que necesito armar en un TreeView que me muestre cada módulo con sus opciones para chequear o deschequear segun sea el caso.

Un ejemplo de como sería la estructura del arbol es el siguiente

> Modulo de Inventario
>>> Agregar
>>> Modificar
>>> Eliminar
>>> Módulo de Rubros
>>>>>> Agregar
>>>>>> Modificar
>>>>>> Eliminar
> Modulo de Clientes
>>> Agregar
>>> Modificar
>>> Eliminar

Todas las opciones del árbol deben poderse marcar o desmarcar. En caso de desmarcar un nodo, se tienen que desmarcar los hijos también.

Trate de probar con una tabla intermedia que tenga la estructura del arbol, para saber de alguna forma que módulo depende de cual... pero no pude avanzar mucho porque no supe como obtener los valores del árbol para guardar en la base de datos.

Si alguien tiene una idea que me pueda aportar para resolver este asunto, le agradezco de antemano.

Saludos!

Delphius 08-08-2007 04:05:18

Hola martinzcr,

Tal vez esto pueda darte una idea, si bien no lo que tu buscas. El problema se resume en como "explorar" cada nodo y su subnodo.

Como comentario:
hace tiempo vi un mensaje de los foros acerca de un sistema de ventas hecho en Delphi que se encuentra disponible en sourceforge.net, (Buscalo por ventas). Me asombró como maneja el tema de los perfiles y las opciones a habilitar/deshabilitar en los menus.
Al comienzo cuesta entenderle la mano a la "fórmula".
Si estas interesado... puedes darle una ojeada, puede que te sirva o te otra perspectiva.

Saludos,

martinzcr 08-08-2007 04:43:09

Delphius, gracias por responder. Voy a bajar el programa para ver como trabaja. Cuelquier comentario vuelvo a escribir. :)

Delphius 08-08-2007 04:52:41

Me parece bien que te tomes el tiempo para "estudiar" lo que te pasé.
Recuerda que se ha dicho mucho sobre el TreeView en los foros. Te aconsejo que primero busques y si hay algo en donde no entiendes o te falla avisas.

Saludos,

ArdiIIa 08-08-2007 11:26:08

Hola martinzcr

Yo tengo implementado un sistema consistente en lo siguiente:

Una tabla:
Código:

NOMBRE VAR_CHAR_15 NOT NULL ---->CODIFICADO
PASSWD VAR_CHAR_15 NOT NULL ---->CODIFICADO
PRIVILEGIOS BLOB

Los dos primeros campos, están codificados para que ningún listo toque nada de nada. El tercero no, pero se podría también....
El campo privilegios, viene a ser un INI con todas las opciones del programa, mas o menos así:

Código:

Cuentas Bancarias=S
Máquinas=S
Materiales=S
OT Fijas=S
Libreta de Contactos=S
Buscar Contactos=S
Pedidos de Clientes=S
Ofertas a Clientes=S
OT=S
Partes Diarios=S
Horas Trabajo Operarios=S
Pedidos a Proveedores=S
Petición de Presupuesto=S
Albaranes=S
Facturas=S
Notas de Entrega=S
Configuración=S
Ejercicios=N
Gestor de Correo=S
Usuarios=S

Donde cada elemento, se corresponde con un item del menú del programa. En mi caso, utilizo ActionManager, por lo que sería mas correcto decir, que cada elemento se corresponde con un TAction.


En el Form donde se encuentra el TreeView, el procedimiento que asisna los elementos, viene a ser algo así....



Código Delphi [-]
// ESTE PROCEDIMIENTO INICIALIZA el treevie de LOS OBJETOS DE SEGURIDAD
// PARA TENER PRIVILEGIOS DE ACCESO A LAS DIFERENTES SECCIONES DEL PROGRAMA
Procedure TFormUsuarios.MakeSecurity( TreeView : TTreeView);

Function Delsigno(Item : String) : String;
Begin
Delete( Item , Pos('&' , Item) ,1) ;
Result := Item;
End;

function FindAction (Caption : string) : TAction;
var
  i : Integer;
begin
  Result := nil;
  with FormMain.ActionManager1 do
   begin
    for I := 0 to ActionCount - 1 do    { Iterate }
     begin
      if TAction(Actions[i]).Caption = Caption then
      begin
        Result := TAction(Actions[i]);
        Break;
      end;
    end;    { for }
  end;  { with }
end;


Var
TreeNode, SubTreeNode : TTreeNode;
I,X : Integer;
cTemp : String;
Action : TAction;
Begin

LockWindowUpdate(Treeview.Handle);
TreeView.Items.Clear;

For I := 0 To FormMain.ActionManager1.ActionBars.ActionBars[0].Items.Count -4 DO

Begin
cTemp := DelSigno(FormMain.ActionManager1.ActionBars.ActionBars[0].Items[i].Caption);
TreeNode := TreeView.Items.Add(nil,cTemp);
TreeNode.ImageIndex := -1;
TreeNode.SelectedIndex := -1;

    For X := 0 to FormMain.ActionManager1.ActionBars.ActionBars[0].Items[i].Items.Count -1 DO
    Begin
    cTemp := DelSigno(FormMain.ActionManager1.ActionBars.ActionBars[0].Items[i].Items[x].Caption);
    if cTemp = '-' then continue;
    Action := FindAction(cTemp);
    if Action <> NIL then
    Begin

    SubTreeNode := TreeView.Items.AddChild(TreeNode,cTemp);
    SubTreeNode.ImageIndex := Action.ImageIndex;
    SubTreeNode.SelectedIndex := Action.ImageIndex;

    if Seguridad.FindItem(Action.Caption) <> NIL then
    SubTreeNode.Data := Seguridad.FindItem(Action.Caption)
    End;
    End;

End;
Treeview.FullExpand;
Treeview.Selected := Treeview.Items[0];
LockWindowUpdate(0);
End;

Dos procedimientos de carga y grabación de datos, necesarios para la gestión:



Código Delphi [-]

//Graba Los valores a la base de datos
procedure TFormUsuarios.Button1Click(Sender: TObject);
Var
Stream : TMemoryStream;
begin
Stream := NIL;
Try

    Stream:= TMemoryStream.Create;
    Seguridad.SaveToStream(Stream);
    Datamodule1.IBTableUsuarios.Edit;
    TMemoField(Datamodule1.IBTableUsuarios.FieldByName('Privilegios')).LoadFromStream(Stream);
    Datamodule1.IBTableUsuarios.FieldByName('Nombre').AsString := FormMain.Encrypt(Edit1.Text ,55423);
    Datamodule1.IBTableUsuarios.FieldByName('PassWd').AsString := FormMain.Encrypt(Edit2.Text ,55423);
    Datamodule1.IBTableUsuarios.Post;
finally
    Stream.Free
End
end;

//Carga Seguridad con los valores de la base de datos
procedure TFormUsuarios.DataSourceUsuariosDataChange(Sender: TObject;  Field: TField);
Var
Stream : TMemoryStream;
begin
Stream := NIL;
IF Datamodule1.IBTableUsuarios.State IN dsEditModes then exit;
Try
Stream:= TMemoryStream.Create;
TMemoField(Datamodule1.IBTableUsuarios.FieldByName('Privilegios')).SaveToStream(Stream);
Seguridad.LoadFromStream(Stream);
MakeSecurity(TreeView1);
Edit1.Text := FormMain.Decrypt(Datamodule1.IBTableUsuarios.FieldByName('Nombre').AsString,55423);
Edit2.Text := FormMain.Decrypt(Datamodule1.IBTableUsuarios.FieldByName('PassWd').AsString,55423);
Finally
Stream.Free;
End;
end;


Y finalmente, verás que se cita por ahí un objeto llamado seguridad, que no es otra cosa que un objeto derivado de la clase TCollection, que contiene una lista (TStrings) de todos los objetos TAction del programa y que los activa o desactiva en base a las selecciones hechas por el usuario.
El código de seguridad, es este:

Código Delphi [-]
unit Unit_Objetos_Seguridad;

interface
uses Classes,SysUtils,ActnList;


type


TFormSectionItem = class(TCollectionItem)
  public
    Action : TAction;
    Accesible : Boolean;
  end;



  TFormSectionItems = class(TCollection)
  private
    FStream : TStrings;
    function GetItem(Index: Integer): TFormSectionItem;
    procedure SetItem(Index: Integer; Value: TFormSectionItem);
    Procedure Initial;
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create;
    destructor Destroy ; override;
    function Add: TFormSectionItem;
    Procedure SaveToStream( Stream : TMemoryStream);
    procedure LoadFromStream( Stream : TMemoryStream);
    Function FindItem(Caption : String) : TFormSectionItem;
    procedure SetActionValues;
    property Items[Index: Integer]: TFormSectionItem read GetItem write SetItem; default;
  end;



(*
TFormSecurityItem = class(TCollectionItem)
  public
    FormName : String;
    Accesible : Boolean;
    Secciones : TFormSectionItems;
  end;


TFormSecurityItems = class(TCollection)
  private
    function GetItem(Index: Integer): TFormSecurityItem;
    procedure SetItem(Index: Integer; Value: TFormSecurityItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create;
    function Add: TFormSecurityItem;
    property Items[Index: Integer]: TFormSecurityItem read GetItem write SetItem; default;
  end;

  *)



implementation

uses UnitMain;


//******************//
constructor TFormSectionItems.Create;
begin
  inherited Create(TFormSectionItem);
  FStream := TStringList.Create;
  Initial;
end;


destructor TFormSectionItems.Destroy;
begin
   FStream.Free;
  inherited Destroy;
end;


Function TFormSectionItems.FindItem(Caption : String) : TFormSectionItem;
Var I : Integer;
Begin
Result := NIL;
For I := 0 to Count -1 DO
if Items[i].Action.Caption = Caption then
Begin
Result := Items[i];
Break;
End;

End;



Procedure TFormSectionItems.Initial;

Function Delsigno(Item : String) : String;
Begin
System.Delete( Item , Pos('&' , Item) ,1) ;
Result := Item;
End;

Function FindAction (Caption : string) : TAction;
var
  i : Integer;
begin
  Result := nil;
  with FormMain.ActionManager1 do
   begin
    for I := 0 to ActionCount - 1 do    { Iterate }
     begin
      if TAction(Actions[i]).Caption = Caption then
      begin
        Result := TAction(Actions[i]);
        Break;
      end;
    end;    { for }
  end;  { with }
end;


Var
Item : TFormSectionItem;
I,X : Integer;
cTemp : String;
Action : TAction;
Begin

For I := 0 To FormMain.ActionManager1.ActionBars.ActionBars[0].Items.Count -4 DO
Begin
    For X := 0 to FormMain.ActionManager1.ActionBars.ActionBars[0].Items[i].Items.Count -1 DO
    Begin
    cTemp := DelSigno(FormMain.ActionManager1.ActionBars.ActionBars[0].Items[i].Items[x].Caption);
    if cTemp = '-' then continue;
    Action := FindAction(cTemp);
    if Action <> NIL then
    Begin
    Item := Add;
    Item.Action := Action;
    Item.Accesible := Action.Enabled;
    End;
    End;
End;

End;



procedure TFormSectionItems.SaveToStream( Stream : TMemoryStream);
Var
I : Integer;
cTemp : String;
begin
FStream.Clear;
For I := 0 To Count -1 DO
    Begin
    if Items[i].Accesible then
    cTemp := '=S'
    else
    cTemp := '=N';
    FStream.Add( Items[i].Action.Caption + cTemp)
    End;
   //FStream.Text := FormMain.Encrypt(FStream.Text,761);
   FStream.SaveToStream(Stream);
   Stream.Position := 0;
end;


procedure TFormSectionItems.LoadFromStream(Stream : TMemoryStream);
Var
I,Z : Integer;
begin
Stream.Position := 0;
FStream.LOadFromStream(Stream);
//FStream.Text := FormMain.Decrypt(FStream.Text,761);
For I := 0 To Count -1 DO
    Begin
    Z := FStream.IndexOfName( Items[i].Action.Caption );
    if Z <> -1 then
       Begin
       Items[i].Accesible := (FStream.ValueFromIndex[Z] = 'S');
       //Items[i].Action.Enabled := Items[i].Accesible;
       End;
     End;

End;




procedure TFormSectionItems.SetActionValues;
Var
I : Integer;
begin
For I := 0 To Count -1 DO
    Items[i].Action.Enabled := Items[i].Accesible;
end;




procedure TFormSectionItems.Update(Item: TCollectionItem);
begin
  inherited;
end;

function TFormSectionItems.GetItem(Index: Integer): TFormSectionItem;
begin
  Result := TFormSectionItem(inherited GetItem(Index));
end;

procedure TFormSectionItems.SetItem(Index: Integer; Value: TFormSectionItem);
begin
  inherited SetItem(Index, Value);
end;

function TFormSectionItems.Add: TFormSectionItem;
begin
  Result := TFormSectionItem(inherited Add);
end;


A la hora de ejecutar el programa y establecer la parametrización de cada usuario, sería algo tal como esto...

Código Delphi [-]
    Seguridad := TFormSectionItems.Create;


    TMemoField(Datamodule1.IBTableUsuarios.FieldByName('Privilegios')).SaveToStream(Stream);
    Seguridad.LoadFromStream(Stream);
    // Pone todas las TAction del Menú
    // Conforme a los valores del usuario que hizo login
    Seguridad.SetActionValues;

Verás que la table IBTableUsuarios, ya estaría posionada sobre el usuario en cuestión, por que previamente se habría identificado.... (otra cuestión aparte)



Básicamente, eso es todo. Lo único comentarte que en mi sistema, utilizo un TreeView normal y corriente, por lo que para que comentas y la forma en la que lo planteas:

Cita:

Todas las opciones del árbol deben poderse marcar o desmarcar. En caso de desmarcar un nodo, se tienen que desmarcar los hijos también.
Creo que lo ideal sería que utilizaras un VirtualTreeView, que si te lo permitiría. (es que en aquellas fecha, yo no conocía ese excelente componente...).

Espero que te sirva de orientación.

NOTA: El código está adaptado a un programa específico y no garantizo que su uso tal cual está, vaya a funcionar en cualquier otro programa.

Saludos.

roman 08-08-2007 17:21:45

Cita:

Empezado por martinzcr (Mensaje 221428)
Todas las opciones del árbol deben poderse marcar o desmarcar. En caso de desmarcar un nodo, se tienen que desmarcar los hijos también.

Para esta parte, podría valerte mi TCheckTreeView

// Saludos


La franja horaria es GMT +2. Ahora son las 08:49:20.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi