unit uCheckBoxSelectionThreadBPL;

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,
  syncobjs,uDBConnectionBPL,uSQLQueries,uTreeView,vcl.Dialogs,vcl.Forms,vcl.Controls;

type
  TCheckBoxSelectionThreadBPL = class(TThread)

    FDBConnectionThread:TDBConnectionBPL;
    FIDList:Tstringlist;
    FCS:TCritiCalSection;
    FSQLQueries:TSQLQueries;

    FDBTreeView:TDBTreeView;


    private


    Procedure ListParentAndAllChildren(NodeID:Integer); // <<Список всех потомков по базе
    procedure CheckListedInDB; // << Запись в базу всех "чекнутых" узлов
    procedure UncheckListedInDB(Node: TTreeNode); // << Запись в базу всех "Анчекнутых" узлов
    procedure CheckBoxSelection; // << Интеграция 3 предыдущих процедур

    function FindParent(Node:TTreeNode;ParentNode:TTreeNode):boolean;


    public

    procedure MyCreate;

    property
    DBTreeViewProperty:TDBTreeView read  FDBTreeView write FDBTreeView;

  protected
    procedure Execute; override;
  end;



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

{ TCheckBoxSelectionThreadBPL }


//-----------------------Отдельная процедура для создания переменных--------------------------------
//-----------------------Чтобы в поток можно было передать значение поля----------------------------
procedure TCheckBoxSelectionThreadBPL.MyCreate;
begin





  FDBConnectionThread:=TDBConnectionBPL.Create(nil);
  FDBConnectionThread.Connect;
  FIDList:=Tstringlist.Create;
  FSQLQueries:=TSQLQueries.Create(nil);





end;


//------------------------EXECUTE--------------------

procedure TCheckBoxSelectionThreadBPL.Execute;
begin
 { // Создаем в MyCreate, так как поток разорван

  FDBConnectionThread:=TDBConnectionBPL.Create(nil);
  FDBConnectionThread.Connect;
  FIDList:=Tstringlist.Create;
  FSQLQueries:=TSQLQueries.Create(nil);
  }



 Synchronize(CheckBoxSelection);


  //Освобождение
  FreeAndNil(FDBConnectionThread);
  FreeAndNil(FIDList);
  FreeAndNil(FSQLQueries);

end;



procedure TCheckBoxSelectionThreadBPL.ListParentAndAllChildren(NodeID: Integer);
var qSelectAllChildren:TFDQuery;
    idField:string;

begin

   //Создание
   qSelectAllChildren:=TFDQuery.Create(nil);
   qSelectAllChildren.Connection:=FDBConnectionThread.FDConnection;

   //Имя id поля из главного модуля компонента через поле-ссылку на главный класс

    idField:=FDBTreeView.DBTreeViewTable.id;
    FIDList.Add(NodeID.Tostring); // Записываем родителя и всех детей

   with qSelectAllChildren do
   begin

    SQL.Text:=FSQLQueries.SelectAllChildren.Text+NodeID.ToString;

    Open();

     while not eof do
     begin

     ListParentAndAllChildren(FieldByName(idField).AsInteger);

     Next;
     end;

    Close();
   end;


//Освобождение

   FreeAndNil(qSelectAllChildren);

end;



//---------------------------Ставим в базе галочки по списку ---------------------------------------


procedure TCheckBoxSelectionThreadBPL.CheckListedInDB;
// Расстановка галочек в базе
var i:integer; qCheckedUpdate:TFDQuery;

begin
//
   qCheckedUpdate:=TFDQuery.Create(nil);
   qCheckedUpdate.Connection:=FDBConnectionThread.FDConnection;;

   qCheckedUpdate.SQL.Text:=FSQLQueries.updateChecked.Text;

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

  begin
    qCheckedUpdate.Params.ParamValues['IsChecked']:=1;
    qCheckedUpdate.Params.ParamValues['id']:=FIDList[i];
    qCheckedUpdate.ExecSQL;
  end;


FreeAndNil(qCheckedUpdate);


end;

//---------------------------------Снимаем галочки по списку из базы


procedure TCheckBoxSelectionThreadBPL.UncheckListedInDB(Node: TTreeNode);
var
  i: Integer;
  ParentNode:TTreeNode;
  qCheckedUpdate:TFDQuery;

begin

   qCheckedUpdate:=TFDQuery.Create(nil);
   qCheckedUpdate.Connection:=FDBConnectionThread.FDConnection;

   qCheckedUpdate.SQL.Text:=FSQLQueries.updateChecked.Text;

     // Снимаем галочку у всех родителей, если они есть
    if Node.Parent<>nil then
     begin
             ParentNode:=Node.Parent;
         while true do
          begin
             if ParentNode.Parent=nil then

             begin
              qCheckedUpdate.Params.ParamValues['IsChecked']:=0;
              qCheckedUpdate.Params.ParamValues['id']:=Integer(Node.Parent.Data^);
              qCheckedUpdate.ExecSQL;
              break;
             end;


              qCheckedUpdate.Params.ParamValues['IsChecked']:=0;
              qCheckedUpdate.Params.ParamValues['id']:=Integer(Node.Parent.Data^);
              qCheckedUpdate.ExecSQL;

              ParentNode:=ParentNode.Parent;
          end;

     end;


     //Снимаем галочку у всех, кто в списке
      for i := 0 to FIDList.Count-1 do

      begin

          qCheckedUpdate.Params.ParamValues['IsChecked']:=0;
          qCheckedUpdate.Params.ParamValues['id']:=FIDList[i];
          qCheckedUpdate.ExecSQL;
      end;

FreeAndNil(qCheckedUpdate);


end;


//------------------Поиск родительского узла в дереве

function TCheckBoxSelectionThreadBPL.FindParent(Node, ParentNode: TTreeNode): boolean;
begin

Result:=false;

Repeat

if Node=ParentNode then
    begin
     Result:=true;
     break;
    end;

Node:=Node.Parent;

Until not Assigned(Node);


end;



procedure TCheckBoxSelectionThreadBPL.CheckBoxSelection;
var NodeID:integer;
    Node:TTreeNode;
    ParentNode:TTreeNode;
    TreeView:TDBTreeView;

begin



 // До старта потока нужно передать ссылку на экземпляр TDBTreeView
 TreeView:=FDBTreeView;

 if not Assigned(TreeView.Selected) then exit;

 Node := TreeView.Selected;
 NodeID:=integer(TreeView.Selected.Data^);

 ListParentAndAllChildren(NodeID); // Собрали родителя и всех потомков в список

 //Если выделенный узел не отмечен галочкой

    if TreeView.Selected.StateIndex<>2 then
    begin


     //Отмечаем галочками все видимые, загруженные подузлы
     Node := TreeView.Selected;

      repeat
        Node.StateIndex:=2;
        Node:=Node.GetNext;
      until not (Assigned(Node)) or not FindParent(Node,TreeView.Selected);


    CheckListedInDB; //Отметили галочкой все подузлы в базе

      exit; // Выход, иначе далее галочка опять снимется
    end;


 //Если выделенный узел отмечен галочкой

     if TreeView.Selected.StateIndex=2 then
    begin


     //Снимаем галочки со всех родителей в TreeView

     if Node.Parent<>nil then
     begin

     ParentNode:=Node.Parent;
         while true do
          begin
                 if ParentNode.Parent=nil then

                 begin
                  ParentNode.StateIndex:=1;
                  break;
                 end;

              ParentNode.StateIndex:=1;
              ParentNode:=ParentNode.Parent;

          end;

     end;


     //Снимаем галочки со всех видимых, загруженных подузлов
     //Node стоит на Selected, начинаем перебор с него
      repeat
        Node.StateIndex:=1;
        Node:=Node.GetNext;
      until not (Assigned(Node)) or not FindParent(Node,TreeView.Selected);

     Node := TreeView.Selected; //Снова поставили ссылку на TreeView.Selected
     UncheckListedInDB(Node); // Сняли галочки с родителя и детей в базе

    exit;
    end;


FIDList.Clear; // Чистим список



end;





end.
