unit uListCopyOrCutOrDeleteBPL;

//Собирает список узлов и всех их потомоков для копирования, вырезки, удаления
//Список это поле экземпляра класса FIDListToCopyOrCutOrDelete
// Собирается либо выделенный узел и все его потомки, либо выделенные галочками и потомки

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, uDBConnectionBPL,uTreeView,uSelectionOptions;

type
TCopyOrCutOrDelete =class(TComponent)

private

  FCut:boolean;
  FIDListToCopyOrCutOrDelete:TStringList; // << Это список узлов для копирования, вырезки, удаления


  FDBTreeView:TDBTreeView; // Ccылка на экземпляр дерева

  Function FindNodeInTree(ID:Integer):TTreeNode;
  Procedure MarkCutted;
  Procedure ListParentAndAllChildren(NodeID:Integer);


  public

  Constructor Create(AOwner:TComponent); override;
  Destructor Destroy; override;

  Procedure ListCheckedOrSelected;

  property Cut:boolean Read FCut Write FCut;
  property DBTreeView:TDBTreeView read FDBTreeView write FDBTreeView;

  property IDListToCopyOrCutOrDelete:TstringList
  read FIDListToCopyOrCutOrDelete write FIDListToCopyOrCutOrDelete;

end;


//--------------------------------------------------------------------------------------------------
                                  IMPLEMENTATION
//--------------------------------------------------------------------------------------------------


{ TCopyOrCut }

//------------------------Конструктор, деструктор---------------------------------------------------

constructor TCopyOrCutOrDelete.Create(AOwner: TComponent);
begin
  inherited;
  FIDListToCopyOrCutOrDelete:=TStringList.Create;
end;

destructor TCopyOrCutOrDelete.Destroy;
begin
  FreeAndNil(FIDListToCopyOrCutOrDelete);
  inherited;
end;
//--------------------------------------------------------------------------------------------------

function TCopyOrCutOrDelete.FindNodeInTree(ID: Integer): TTreeNode;
var i:integer; DBTreeViewLocal:TDBTreeView;

begin

 DBTreeViewLocal:=FDBTreeView;

 Result:=nil; //Если родитель не будет найден, то это нулевой уровень
//Иначе, это будет какой-то конкретный узел
 for i := 0 to DBTreeViewLocal.Items.Count-1 do

 if DBTreeViewLocal.Items.Item[i].Data<>nil then

 begin
     if Integer(DBTreeViewLocal.Items.Item[i].Data^)=ID then

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

end;

//-------------------------Непосредственный сбор в список-------------------------------------------

procedure TCopyOrCutOrDelete.ListCheckedOrSelected;
var i:integer; fSelectionOptions: TfSelectionOptions;
    IDSelected:integer;
    NodeID:integer;
    DBTreeViewLocal:TDBTreeView;
    Node:TTreeNode;

begin

DBTreeViewLocal:=FDBTreeView;

FIDListToCopyOrCutOrDelete.Clear;
//CutInMain:=false; //Изначально подразумевается копирование


  if Assigned(DBTreeViewLocal.Selected) then
     IDSelected:=integer(DBTreeViewLocal.Selected.Data^) else
     IDSelected:=-2; // << Означает, что узел не выбран


// Спрашиваем, что будем выделять
fSelectionOptions:=TfSelectionOptions.Create(nil);
fSelectionOptions.ShowModal;

{ //Закоментировано, потому что вызывает течь памяти
//Если передумали и закрыли модальную форму
if fSelectionOptions.Tag=-3 then

begin
 FreeAndNil(fSelectionOptions);
 exit;
end;
}

   //Если один выделенный узел
if (fSelectionOptions.Tag=0) or (fSelectionOptions.Tag=-3) then
 begin

     if IDSelected=-2 then
     begin
     showmessage('Ни один элемент не выбран');
     exit
     end else

     ListParentAndAllChildren(IDSelected);


 end else
   //Если нужно выбрать узлы отмеченные галочками
 begin


 if DBTreeViewLocal.Items.GetFirstNode=nil then exit else

    Node:=DBTreeViewLocal.Items.GetFirstNode;

    repeat

    if (Node.StateIndex=2) then
     begin
      if Node.data=nil then exit;


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


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


 end;


MarkCutted;


// Освобождение
FreeAndNil(fSelectionOptions);

end;


//---------------------------Рекурсивная процедура------------------------------------------------

procedure TCopyOrCutOrDelete.ListParentAndAllChildren(NodeID: Integer);
var qSelectAllChildren:TFDQuery;
    DBConnectionLocal:TDBConnectionBPL;


begin

   DBConnectionLocal:=TDBConnectionBPL.Create(nil);

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

   //Если ID не был добавлен ранее, тогда добавляем
   if FIDListToCopyOrCutOrDelete.IndexOf(NodeID.Tostring)=-1 then
      FIDListToCopyOrCutOrDelete.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;


   FreeAndNil(qSelectAllChildren);
   FreeAndNil(DBConnectionLocal);


end;

//--------------------------------------------------------------------------------------------------

procedure TCopyOrCutOrDelete.MarkCutted;
var i:integer;
    Node:TTreeNode;
    DBtreeViewLocal:TDBTreeView;

begin

DBtreeViewLocal:=FDBTreeView;



if FCut then
 begin

 for i := 0 to FIDListToCopyOrCutOrDelete.Count-1 do

     begin
     Node:=FindNodeInTree(FIDListToCopyOrCutOrDelete[i].ToInteger);
     Node.Cut:=true;
     end;

//  CutInMain:=true;
 end;



end;


END.
