unit uCutAndPasteThread;

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
  Contnrs,vcl.dialogs,
  syncobjs,vcl.Forms,vcl.Controls, uDBConnection;




type
  TCutAndPasteThread = class(TThread)
  private

  FDConnection:TFDConnection;
  procedure Connect;

  function IsFolder(Node:TTreeNode):boolean;
  function IsFolderByID(NodeID:integer):boolean;

  Function CheckIfNodeInIDList(Node:TTreeNode):boolean;

  Procedure ListParentAndAllChildren(NodeID:Integer);
  Procedure ListAllChecked;


  function InsertFolderOrFileInDB(const idParent, index: Integer;
  const name: string; const TreeView: TTreeView; IsFolder: boolean): integer;

  function FindParentNode(Key: integer; TreeView: TTreeView): TTreeNode;

  procedure InsertFolderOrFileInTree(TreeView: TTreeView; IsFolderLocalVar:boolean; name:string);
  procedure InsertFolderOrFileInTree2(TreeView: TTreeView; IsFolderLocalVar:boolean; name:string);

  Procedure Paste;





    { Private declarations }
  protected
    procedure Execute; override;
  end;


 var IDList:Tstringlist;
     CheckedNodes:array of integer;
     CS:TCriticalSection;
     DBConnection:TDBConnection;

implementation

uses MainUnit;



function TCutAndPasteThread.CheckIfNodeInIDList(Node: TTreeNode): boolean;
//Проверка есть ли узел в списке
begin

if IDList.IndexOf(Node.Text)<>-1 then Result:=true else
Result:=false;


end;

procedure TCutAndPasteThread.Connect;
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 TCutAndPasteThread.Execute;

var i:integer;

begin

FDConnection:=TFDConnection.Create(nil);
Self.Connect;


//DBConnection:=TDBConnection.Create(nil);
//DBConnection.Connect;

IDList:=Tstringlist.Create;



Paste;

FDConnection.Free;
//DBConnection.Free;
IDList.Free;
  { Place thread code here }
end;


function TCutAndPasteThread.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;

function TCutAndPasteThread.InsertFolderOrFileInDB(const idParent, index: Integer;
  const name: string; const TreeView: TTreeView; IsFolder: boolean): integer;
var qInsert:TFDQuery;
    qGetKey:TFDQuery;
    qSelectChildren:TFDQuery;

//    DBConnection:TDBConnection;


begin

 //Создание
// DBConnection:=TDBConnection.Create(nil);

//---------------------Создание qInsert-------------------------------
 qInsert:=TFDQuery.Create(nil);

 qInsert.Connection:=FDConnection;

 qInsert.SQL.Text:=
'INSERT INTO `treeview_db`.`tree` (`IdParent`, `Name`, `Index`,`isChecked`,`Level`,`IsFolder`)'+
 'VALUES (:idParent, :name, :index,:isChecked,:Level,:IsFolder);';

 //---------------------Создание qGetKey------------------------

 qGetKey:=TFDQuery.Create(nil);
 qGetKey.Connection:=FDConnection;
 qGetKey.SQL.Text:='SELECT Max(id) as newkey FROM treeview_db.tree;';

//---------------------Основная работа по вставке узла в БД----------------

//Вставка записи
  with qInsert.Params do
   begin

     if IsFolder then

     begin

       ParamValues['idParent']:=idParent;
       ParamValues['Index']:=Index;
       ParamValues['Name']:=Trim(Name);
       ParamValues['isChecked']:=false; // По умолчанию галочка не отмечена
       ParamValues['IsFolder']:=true;

     end else

      begin

       ParamValues['idParent']:=idParent;
       ParamValues['Index']:=Index;
       ParamValues['Name']:=Trim(Name);
       ParamValues['isChecked']:=false; // По умолчанию галочка не отмечена
       ParamValues['IsFolder']:=false;

      end;



   // Записываем уровень вставляемого узла в базу
   if  FindParentNode(idParent,TreeView)<>nil then
   begin
     ParamValues['Level']:=FindParentNode(idParent,TreeView).Level+1
   end else ParamValues['Level']:=0;

   end;

qInsert.ExecSQL;

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



 // Освобождение
qGetKey.Free;
qInsert.Free;

{
//DBConnection.Free;

  //Эта рекурсия бесконечна, так как дети постоянно добавляются

 // Если у записи есть дети, то рекурсивно повторить её для всех детей

qSelectChildren:=TFDQuery.Create(nil);
qSelectChildren.Connection:=FDConnection;
qSelectChildren.SQL.Text:='SELECT * FROM treeview_db.tree where IdParent='+IDList[0];

with qSelectChildren do begin

 Open();
 showmessage(qSelectChildren.RecordCount.ToString());                    //Здесь
if not IsEmpty then

  while not eof do
  begin

    InsertFolderOrFileInDB(
    idParent,
    FieldByName('Index').AsInteger,
    FieldByName('Name').AsString,
    MainForm.TreeView1,
    FieldByName('Name').AsBoolean);

   Next;
  end;


 Close();



end;


qSelectChildren.Free;

}

end;


procedure TCutAndPasteThread.InsertFolderOrFileInTree(TreeView: TTreeView;
  IsFolderLocalVar: boolean; name: string);

// Вставка папки или файла в дерево и БД
var
    Node:TTreeNode;
    idParent,ItemIndex:integer; // Ключ и индекс узла

    ID:^Integer;
begin

//      if not Assigned(TreeView.Selected) then exit;

      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(ID);
            // Вставка в БД

       if IsFolderLocalVar then // Если папка
       begin
                        //Вставка в базу
           ID^:=InsertFolderOrFileInDB(idParent, Itemindex, name, TreeView, true);
                       // Вставка в само дерево
           Node:=TreeView.Items.AddChildObject(TreeView.Selected,name,ID);


             // Ставим "чек" как у родителя
                 if (Node.Parent<>nil) then
                 begin
                   if (Node.Parent.StateIndex=2) then Node.StateIndex:=2 else
                   Node.StateIndex:=1;
                 end else Node.StateIndex:=1;


            //Ставим иконку папки
   //             Node.ImageIndex:=1;


       end else
        // Если файл...
       begin

           //Вставка в базу
           ID^:=InsertFolderOrFileInDB(idParent, Itemindex, name, TreeView, false);
                       // Вставка в само дерево
           Node:=TreeView.Items.AddChildObject(TreeView.Selected,name,ID);


             // Ставим "чек" как у родителя
                 if (Node.Parent<>nil) then
                 begin
                   if (Node.Parent.StateIndex=2) then Node.StateIndex:=2 else
                   Node.StateIndex:=1;
                 end else Node.StateIndex:=1;


             //Ставим иконку файла
     //           Node.ImageIndex:=0;



       end;




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


    //   Node .Selected:=true;

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


// InsertNodeInTree
end;



procedure TCutAndPasteThread.InsertFolderOrFileInTree2(TreeView: TTreeView;
  IsFolderLocalVar: boolean; name: string);
// Вставка папки или файла в дерево и БД
var
    Node:TTreeNode;
    idParent,ItemIndex:integer; // Ключ и индекс узла

    ID:^Integer;
begin

//      if not Assigned(TreeView.Selected) then exit;

      if Assigned(TreeView.Selected) then
       begin
         //Назначаем родителя новому узлу
         idParent:=Integer(TreeView.Selected.Data^); //<<<<<
         ItemIndex:=TreeView.Items.Count+1;

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


       if IsFolderLocalVar then
        //Вставка в базу
           ID^:=InsertFolderOrFileInDB(idParent, Itemindex, name, TreeView, true)
       else
           ID^:=InsertFolderOrFileInDB(idParent, Itemindex, name, TreeView, false);


    TreeView.Selected.Collapse(false);
    TreeView.Selected.Expand(false);

end;



function TCutAndPasteThread.IsFolder(Node: TTreeNode): boolean;
// Проверка папка это или нет
var qCheckIsFolder:TFDQuery; ID:^integer;
begin

//DBConnection:=TDBConnection.Create(nil);
qCheckIsFolder:=TFDQuery.Create(nil);
qCheckIsFolder.Connection:=FDConnection;

new(ID);
if assigned(Node) then ID^:=Integer(Node.Data^);


qCheckIsFolder.SQL.Text:='Select * from `treeview_db`.`tree` where id='+ID^.ToString();

qCheckIsFolder.Open();

if qCheckIsFolder.FieldByName('IsFolder').AsBoolean=true then result:=true else
Result:=false;


qCheckIsFolder.Close;
qCheckIsFolder.Free;
//DBConnection.Free;


end;


function TCutAndPasteThread.IsFolderByID(NodeID: integer ): boolean;

var qCheckIsFolder:TFDQuery;
begin
qCheckIsFolder:=TFDQuery.Create(nil);
qCheckIsFolder.Connection:=FDConnection;

qCheckIsFolder.SQL.Text:='Select * from `treeview_db`.`tree` where id='+NodeID.ToString;

qCheckIsFolder.Open();

if qCheckIsFolder.FieldByName('IsFolder').AsBoolean=true then result:=true else
Result:=false;



qCheckIsFolder.Close;
qCheckIsFolder.Free;
//
end;

procedure TCutAndPasteThread.ListAllChecked;
var i:integer; Node:TTreeNode; NodeID:integer;
    TreeView:TTreeView;
begin

 TreeView:=MainForm.TreeView1;

 if TreeView.Items.GetFirstNode=nil then exit else

    Node:=TreeView.Items.GetFirstNode;

    repeat

    if (Node.StateIndex=2) then
     begin
      NodeID:=Integer(Node.Data^);
      ListParentAndAllChildren(NodeID); // Добавляем в ListID
     end;


    Node:=Node.GetNext;
    until not Assigned(Node) ;


end;


procedure TCutAndPasteThread.ListParentAndAllChildren(NodeID: Integer);
var qSelectAllChildren:TFDQuery;

begin

   qSelectAllChildren:=TFDQuery.Create(nil);
   qSelectAllChildren.Connection:=FDConnection;

   //Если ID не был добавлен ранее, тогда добавляем
   if IDList.IndexOf(NodeID.Tostring)=-1 then
   IDList.Add(NodeID.Tostring); // Записываем родителя и всех детей


   //Ищем всех детей
   with qSelectAllChildren do
   begin

    SQL.Text:='SELECT * FROM treeview_db.tree where IdParent='+NodeID.ToString;

    Open();

     while not eof do
     begin
     // Для каждого ребенка вызываем рекурсивно
     ListParentAndAllChildren(FieldByName('id').AsInteger);

     Next;
     end;

    Close();
   end;

   qSelectAllChildren.Free;

end;


procedure TCutAndPasteThread.Paste;

var TreeView:TTreeView;  i:integer;

begin
TreeView:=MainForm.TreeView1;

ListAllChecked;

//Проверка нет ли в списке вставляемых узлов выделенного
if CheckIfNodeInIDList(TreeView.Selected) then exit;

//Проверка папка ли это
if not IsFolder(TreeView.Selected) then exit;



for i := 0 to IDList.Count-1 do
 begin


    if IsFolderByID(IDList[0].ToInteger()) then



  InsertFolderOrFileInTree(TreeView,true,'CuttedFolder') else
  InsertFolderOrFileInTree(TreeView,false,'CuttedFile');

 end;


end;

end.
