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
[-]
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
begin
if TAction(Actions[i]).Caption = Caption then
begin
Result := TAction(Actions[i]);
Break;
end;
end;
end;
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
[-]
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;
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;
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
begin
if TAction(Actions[i]).Caption = Caption then
begin
Result := TAction(Actions[i]);
Break;
end;
end;
end;
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.SaveToStream(Stream);
Stream.Position := 0;
end;
procedure TFormSectionItems.LoadFromStream(Stream : TMemoryStream);
Var
I,Z : Integer;
begin
Stream.Position := 0;
FStream.LOadFromStream(Stream);
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');
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);
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.