unit uDMDB;

interface

uses
  System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
  FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf, FireDAC.Stan.Async,
  FireDAC.DApt, FireDAC.UI.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Phys,
  FireDAC.VCLUI.Wait, FireDAC.Phys.MySQLDef, FireDAC.Phys.MySQL, Data.DB, FireDAC.Comp.Client,
  FireDAC.Comp.DataSet,
  Vcl.ComCtrls, // Для TTreeView
  Vcl.Dialogs  // Для InputQuery
  ;

type
  TDMDB = class(TDataModule) // TDataModuleDataBase
    qSelect: TFDQuery;
    qInsert: TFDQuery;
    qEdit: TFDQuery;
    qDelete: TFDQuery;
    qGetKey: TFDQuery;
    FDConnection: TFDConnection;
    FDPhysMySQLDriverLink: TFDPhysMySQLDriverLink;
    procedure Connect(Sender:TObject);
    procedure DataModuleCreate(Sender: TObject);

    //Вставка записи в БД и дерево
    function InsertNodeInDB(const idParent,index:integer;
    const name:string):integer;
    procedure InsertNodeInTree(Sender:TObject; TreeView:TTreeView);

    //Редактирование записи в дереве и БД
    procedure EditNode(Sender:TObject; TreeView:TTreeView);

    //UPDATE Cбор информации о дереве
    Function FindParentNode(Key:integer;TreeView:TTreeView):TTreeNode; //Вспомогательная
    Procedure UpdateTree(Sender:Tobject;TreeView:TTreeView);

    //Очистка дерева
    Procedure ClearTree(TreeView:TTreeView);

    //Удвление узла
    Procedure DeleteRecord(Node:TTreeNode);
    Procedure DeleteNode(Sender:TObject;TreeView:TTreeView);


  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DMDB: TDMDB;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

procedure TDMDB.ClearTree(TreeView:TTreeView);
var i:integer;
begin
//   showmessage('TreeView.Items.Count-1 ='+inttostr(TreeView.Items.Count-1));
  for i := 0 to TreeView.Items.Count-1  do
  begin
    if TreeView.Items.Item[i].Data<>nil then
    Dispose(TreeView.Items.Item[i].Data);

  end;
    TreeView.Items.Clear;
end;

procedure TDMDB.Connect(Sender: TObject);
var oParams:Tstrings;
begin
     oParams := TStringList.Create;
//  oParams.Add('DriverID='+DriverID);
  oParams.Add('DataBase=treeview_db');
  oParams.Add('Password=masterkey');
  oParams.Add('User_Name=root');
  oParams.Add('Port=3306');
  oParams.Add('Server=localhost');
  oParams.Add('CharacterSet=utf8');

   FDConnection.Params.Assign(oParams);
   FDConnection.DriverName:='MySQL';

   FDConnection.Connected:=true;

   oParams.Free;
end;

procedure TDMDB.DataModuleCreate(Sender: TObject);
var i:integer;
begin
//Подключение
Self.Connect(Self);

for I := 0 to Self.ComponentCount-1 do
  begin
    if Components[i] is TFDQuery then
     (Components[i] as TFDQUery).Connection:=FDConnection;
  end;

end;

procedure TDMDB.DeleteNode(Sender: TObject; TreeView: TTreeView);
var Node:TTreeNode;
begin
  if not Assigned(TreeView.Selected) then exit;

  //Удаляем всех детей
  while TreeView.Selected.HasChildren do
    begin
      Node:=TreeView.Selected.GetLastChild;
      while Node.HasChildren do Node:=Node.GetLastChild;
      DeleteRecord(Node); //Удаляем из базы
      TreeView.Items.Delete(Node); // Удаляем из дерева
    end;

 //Удаляем родителя
 DeleteRecord(TreeView.Selected);
 TreeView.Selected.Delete;
end;

procedure TDMDB.DeleteRecord(Node: TTreeNode);
var Obj:^Integer;
begin
  Obj:=Node.Data;
  qDelete.Params.ParamValues['id']:=Obj^;
  qDelete.ExecSQL;
  Dispose(Obj);
end;

procedure TDMDB.EditNode(Sender: TObject; TreeView: TTreeView);
var Node:TTreeNode;
    s:string;

begin
 if Assigned(TreeView.Selected) then
 begin

         Node:=TreeView.Selected;
         S:=Node.Text;

         if InputQuery('Редактируем узел','Новое название',s)=true then

    begin
         with qEdit.Params do
         begin
           ParamValues['name']:=S;
           ParamValues['id']:=Integer(Node.Data^);
        end;
        qEdit.ExecSQL;
        Node.Text:=s;
    end else exit;
 end;

end;



function TDMDB.InsertNodeInDB(const idParent, index: integer; const name: string): integer;
begin

//Вставка записи
  with qInsert.Params do
   begin
     ParamValues['idParent']:=idParent;
     ParamValues['Index']:=Index;
     ParamValues['Name']:=Trim(Name);

   end;

qInsert.ExecSQL;

 //Получение id последней записи
 with qGetKey do
 begin
   Open;
   Result:=qGetKey.FieldByName('NewKey').AsInteger;
   Close;
 end;

end;

procedure TDMDB.InsertNodeInTree(Sender: TObject; TreeView: TTreeView);
var name:string;
    Node:TTreeNode;
    idParent,ItemIndex:integer; // Ключ и индекс узла

    Obj:^Integer;
begin
    if InputQuery('Новая запись','',name)=true then
    begin
      if Assigned(TreeView.Selected) then
       begin
         //Назначаем родителя новому узлу
         idParent:=Integer(TreeView.Selected.Data^);
         ItemIndex:=TreeView.Items.Count+1;

       end else
       //Если никакой узел не выбран, владельца нет
       begin
        idParent:=-1;
        ItemIndex:=0;
       end;


       //Собственно вставка в дерево

       New(Obj);
            // Вставка в БД
       Obj^:=InsertNodeInDB(idParent,itemIndex,name);
            // Вставка в само дерево
       Node:=TreeView.Items.AddChildObject(
       TreeView.Selected,name,obj
       );



   // Оставляем фокус на том узле, на который нажали
      if TreeView.Selected<>nil then
      begin
      TreeView.Selected.Expanded:=true;
      TreeView.SetFocus;
      TreeView.Selected.Selected:=true;
      end;




    //   Node .Selected:=true;

      //Dispose(Obj) <<Высвобождать будем при закрытии либо
      //Удалении, иначе выскакивает ошибка Invalid Pointer Operation
    end;

// InsertNodeInTree
end;


function TDMDB.FindParentNode(Key: integer;TreeView:TTreeView): TTreeNode;
var i:integer;
begin
 Result:=nil; //Если родитель не будет найден, то это нулевой уровень
//Иначе, это будет какой-то конкретный узел
 for i := 0 to TreeView.Items.Count-1 do
  if Integer(TreeView.Items.Item[i].Data^)=Key then

   begin
     Result:=TreeView.Items.Item[i];
     Break;
   end;


end;

procedure TDMDB.UpdateTree(Sender: Tobject;TreeView:TTreeView);
var Obj:^Integer; Node:TTreeNode;
begin



TreeView.Items.BeginUpdate;
  ClearTree(TreeView);

  with qSelect do
   begin
     Open();

     while eof<>true do
     begin
       New(Obj);
       Obj^:=FieldByName('id').AsInteger;
       Node:=Self.FindParentNode(FieldByName('idParent').AsInteger,TreeView);
       TreeView.Items.AddChildObject(Node,FieldByName('name').AsString,Obj);
       Next;
     end;
      Close;
   end;

TreeView.Items.EndUpdate;
end;

end.
