unit U_MasterCableCanalTracing;

interface

uses
  Windows, U_LNG, Messages, SysUtils, Variants, Classes, Graphics, Controls, Contnrs, Forms,
  Dialogs, cxLookAndFeelPainters, StdCtrls, cxButtons, ExtCtrls, RzPanel,
  RzTabs, cxRadioGroup, ComCtrls, cxControls, cxContainer, cxEdit,
  cxTextEdit, RzTreeVw, cxCheckBox, RzListVw, RzButton, Mask, RzEdit,
  RzRadChk, cxMaskEdit, cxButtonEdit,

  U_BaseCommon, U_BaseConstants, U_Common, U_SCSLists, U_SCSComponent, RzSpnEdt, ImgList,
  Buttons, siComp, siLngLnk, exgrid, RapTree, FlytreePro, Treecoll,
  ActnList, Menus, XPMenu, RzSplit;

const
  // Column Indexes
  ciTraces = 0;
  ciKolvo = 1;
  ciComponent = 2;
  ciCablesTotalSection = 3;
  ciChannelSection = 4;

  // TreeViewColors
  tvclSelBackColorFocused = clHighlight;
  tvclSelTextColorFocused = clWhite;

  tvclSelBackColorHalfUnFocused = clSkyBlue; //clLime;
  tvclSelTextColorHalfUnFocused = clBlack;

  tvclSelBackColorUnFocused = clSilver;
  tvclSelTextColorUnFocused = clBlack;

type

  TNodeType = (ntNone,
               ntTypeVerticalTraces,    // вертикальные трассы
               ntTypeHorizontalTraces,  // горизонтальные трассы
               ntTypeHeightTracing,     // трассы на высоте размещения трасс
               ntTypeHeightSocket,      // трассы на высоте размещения точечных объектов
               ntTypeHeightFloor,       // трассы в полу(высота размещения = 0)
               ntTypeHeightBetweenSocketFloor, // Трасса между полом и розетками
               ntTypeHeightCeiling,     // под потолком (высота размещения = высота потолка)
               ntTypeHeightFalseCeiling,// трассы над фальш-потолком
               ntTypeNoCategory,        // трассы не попавшие в категории
               ntTrace
               );

  TNodeInfo = record
    NodeType: TNodeType;
    IDComponent: Integer;
    NameComponent: string[255];
    CableCountToTrace: Integer;              
    IDTrace: Integer;
    CablesTotalSection: Double;
    ChannelSection: Double;
    TraceObject: TSCSCatalog;
  end;
  PNodeInfo = ^TNodeInfo;

  TF_MasterCableCanalTracing = class(TForm)
    pnOkCancel: TRzGroupBox;
    btOk: TRzBitBtn;
    btCancel: TRzBitBtn;
    pcMain: TRzPageControl;
    tsStep0: TRzTabSheet;
    tsStep1: TRzTabSheet;
    RzGroupBox1: TRzGroupBox;
    Splitter1: TSplitter;
    RzPanel3: TRzPanel;
    gbTracingType: TRzGroupBox;
    rbAllTraces: TRzRadioButton;
    rbSelectedTraces: TRzRadioButton;
    rbDefineTrace: TRzRadioButton;
    cbSelectInPM: TRzCheckBox;
    RzPanel1: TRzPanel;
    RzPanel2: TRzPanel;
    lbDestTraces: TLabel;
    pcTrees: TRzPageControl;
    tsAllTraces: TRzTabSheet;
    tsSelectedTraces: TRzTabSheet;
    tsDefineTrace: TRzTabSheet;
    pnCableCanals: TRzPanel;
    gbComponentsFromNB: TRzGroupBox;
    lvComponents: TListView;
    btBack: TRzBitBtn;
    pnUseComponentAsDefault: TRzPanel;
    cbUseComponentAsDefault: TRzCheckBox;
    gbChoiceNBComponent: TRzGroupBox;
    RzGroupBox2: TRzGroupBox;
    pnNBComponents: TRzPanel;
    ImageList_Glyphs: TImageList;
    RzPanel4: TRzPanel;
    cbAddComponentToChildNodes: TRzCheckBox;
    btSetNBComponentToNodeInfo: TRzBitBtn;
    pnComponCountToTrace: TRzPanel;
    cbTraceOnlyForEmptyObjects: TRzCheckBox;
    lng_Forms: TsiLangLinked;
    gbTraceScaleGrops: TRzGroupBox;
    RzPanel5: TRzPanel;
    Label2: TLabel;
    seScaleStep: TRzSpinEdit;
    spTraceScaleGrops: TSplitter;
    tvAllTraces: TFlyTreeViewPro;
    tvSelectedTraces: TFlyTreeViewPro;
    tvDefineTrace: TFlyTreeViewPro;
    tvTraceScaleGrops: TFlyTreeViewPro;
    Button1: TButton;
    ActionList1: TActionList;
    Act_DropComponFromMainTree: TAction;
    Act_DropComponFromScaleTree: TAction;
    Act_SelectTraceFromMainToScaleTree: TAction;
    Act_SelectTraceFromScaleToMainTree: TAction;
    pmTreeMain: TPopupMenu;
    pmTreeScale: TPopupMenu;
    ImageList_Actions: TImageList;
    N1: TMenuItem;
    N2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    pnszCableCanals: TRzSizePanel;
    ImageList_FlyTree: TImageList;
    pcComponInfo: TRzPageControl;
    tsCable: TRzTabSheet;
    Label1: TLabel;
    seComponCountToTrace: TRzSpinEdit;
    tsCableChannel: TRzTabSheet;
    pnCableChannelInfo: TRzPanel;
    lbComponVolume: TLabel;
    Label3: TLabel;
    Timer_SelectTracesInCAD: TTimer;
    XP_Menu1: TXPMenu;
    procedure rbAllTracesClick(Sender: TObject);
    procedure rbSelectedTracesClick(Sender: TObject);
    procedure rbDefineTraceClick(Sender: TObject);
    procedure cbUseOneCanalForAllClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btSetNBComponentToNodeInfoClick(Sender: TObject);
    procedure cbAddComponentToChildNodesClick(Sender: TObject);
    procedure btBackClick(Sender: TObject);
    procedure btOkClick(Sender: TObject);
    procedure pnOkCancelResize(Sender: TObject);
    procedure lvComponentsSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure cbSelectInPMClick(Sender: TObject);
    procedure seComponCountToTraceKeyPress(Sender: TObject; var Key: Char);
    procedure seScaleStepChange(Sender: TObject);
    procedure tvDefineTraceChange(Sender: TObject; Node: TFlyNode);
    procedure Button1Click(Sender: TObject);
    procedure tvDefineTraceGetNodeAttributes(Node: TFlyNode;
      Column: Integer; aFont: TFont; var BackColor: TColor;
      var Alignment: TAlignment);
    procedure tvDefineTraceStateChange(Node: TFlyNode; Oldindex: Integer);
    procedure tvTraceScaleGropsStateChange(Node: TFlyNode;
      Oldindex: Integer);
    procedure Act_DropComponFromMainTreeExecute(Sender: TObject);
    procedure Act_DropComponFromScaleTreeExecute(Sender: TObject);
    procedure tvTraceScaleGropsChange(Sender: TObject; Node: TFlyNode);
    procedure Act_SelectTraceFromMainToScaleTreeExecute(Sender: TObject);
    procedure Act_SelectTraceFromScaleToMainTreeExecute(Sender: TObject);
    procedure tvDefineTraceEnter(Sender: TObject);
    procedure tvDefineTraceExit(Sender: TObject);
    procedure tvTraceScaleGropsMouseUp(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure pmTreeMainPopup(Sender: TObject);
    procedure pmTreeScalePopup(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Timer_SelectTracesInCADTimer(Sender: TObject);
    procedure btCancelClick(Sender: TObject);
  private
    GForm: TForm;

    FtiiSCSLineGroup: Integer;
    FtiiSCSLineNormal: Integer;

    FAllTracesInfo: TList;
    FSelectedTracesInfo: TList;

    FActiveTreeView: TFlyTreeViewPro;
    FFocusedTreeView: TFlyTreeViewPro;
    FNormBase: TForm;
    FSavedNBTreeCatalogChange: TTVChangedEvent;
    FSavedNBlvTemplatesSelectItem: TLVSelectItemEvent;
    FSavedNBpcObjectsChange: TNotifyEvent;
    FSavedNBtvComponGroupsChange: TFTVChangedEvent;

    FComponentsIDs: TIDStringList;
    FLookedindexes: TIntList;
    FComponentTypeSysName: String;
    FComponentTypeSysNames: TStringList;
    FComponCountToTraceForAll: Integer;
    FIDComponentForAll: Integer;
    FNameComponentForAll: string;
    FVolumeComponentForAll: Double;
    FSCSList: TSCSList;
    FStepIndex: Integer;

    FLastGroupNode: TFlyNode;
    FNodeToSelInCAD: TFlyNode;
    FtvList: TObjectList;
    FUOMMin: Integer;

    procedure AddComponentsToListView(AComponentsIDs: TIDStringList);
    function AddGroupNodeToTree(ATreeView: TFlyTreeViewPro; AParentNode: TFLyNode; AGroupCaption: String; AGroupNodeType: TNodeType): TFLyNode;
    procedure AddIDComponentAndCountToTreeNodes(AIDComponent, ACount: Integer;
                ANameCompon: string; AChannelSection: Double; ANode: TFlyNode; ATakeChilds: Boolean);
    function AddNodeToTreeView(ATreeView: TFlyTreeViewPro; AParentNode: TFlyNode; ACaption: String; ANodeInfo: TNodeInfo): TFlyNode;
    procedure AddTraceInfoToTreeView(ATreeView: TFlyTreeViewPro; AParentNode: TFlyNode; ATraceInfo: TList);
    function AddTraceInfoAsGroupToTreeView(ATreeView: TFlyTreeViewPro; AParentNode: TFlyNode;
                AGroupCaption: String; AGroupNodeType: TNodeType; ATraceInfo: TList; AExpandGrp: Boolean): TFlyNode;
    procedure AfterChangeActiveTreeView;
    procedure ApplyNodeSelection(ANode: TFlyNode);
    procedure DefineComponVolumeForAll;
    //procedure ClearCheckTreeView(ATreeView: TRzCheckTree);
    procedure DropComponFromTraceNode(ATraceNode: TFlyNode; AParalellTree: TFlyTreeViewPro);
    procedure EnableDisableActions;
    function GetNameUOMMin2: String;
    function GetGroupNodeByNode(ANode: TFlyNode): TFlyNode;
    function GetTraceNodeByTraceID(ATreeView: TFlyTreeViewPro; ATraceID: Integer): TFlyNode;
    function GetTreeViewFirstNode(ATreeView: TFlyTreeViewPro): TFlyNode;
    function HaveNodeChildByNodeType(ANode: TFlyNode; ANodeType: TNodeType): Boolean;
    procedure LoadTraceScaleGropsToTreeFromNode(ANode: TFlyNode);
    procedure ReChangeRadioButton(ARadioButton: TRzRadioButton);
    procedure RefreshNodesData(ATreeViewToRefresh: TFlyTreeViewPro; ASrcNodeFromOtherTV: TFlyNode);
    procedure RefreshSelectedInNB;
    procedure ShowNodeData(ANode: TFlyNode);
    procedure SelectComponentFromNode(ATreeNode: TFlyNode);
    procedure SelectComponentInListView(AIDComponent: Integer);
    function SelectTraceNodeByNodeFromOtherTree(ANodeFromOtherTree: TFlyNode; ATreeView: TFlyTreeViewPro): Boolean;
    procedure SelectTracesInCADFromNode(ANode: TFlyNode);
    procedure SetComponentToTrace(ANBComponent: TSCSComponent; APMTrace: TSCSCatalog; ACableCount: Integer);
    procedure SetControls;
    procedure SetNBToForm;
    procedure StepIndex(AIsInc: Boolean);
    function TraceComponentsFromTree(ATreeView: TFlyTreeViewPro): Boolean;

    // Events
    procedure NBTree_CatalogChange(Sender: TObject; Node: TTreeNode);
    procedure NBlvTemplatesSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
    procedure NBpcObjectsChange(Sender: TObject);
    procedure NBtvComponGroupsChange(Sender: TObject; Node: TFlyNode);
    procedure AfterChangeNBCompon;
  public
    constructor Create(AOwner: TComponent; AForm: TForm);
    destructor Destroy; override;

    function Execute(AIDNBComponent: Integer; const ANameNBComponent, ACompTypeSysName: String; ACompTypeSysNames: TStringList): Boolean;
  end;

//var
//  F_MasterCableCanalTracing: TF_MasterCableCanalTracing;

implementation
Uses Unit_DM_SCS, U_Main, U_Constants, U_FilterConfigurator, U_Progress;
{$R *.dfm}

{ TF_MasterCableCanalTracing }

procedure TF_MasterCableCanalTracing.AddComponentsToListView(AComponentsIDs: TIDStringList);
var
  ListItem: TListItem;
  i: Integer;
begin
  lvComponents.SortType := stText;
  try
    for i := 0 to AComponentsIDs.Count - 1 do
    begin
      ListItem := lvComponents.Items.Add;

      ListItem.Caption := AComponentsIDs.GetStringByIndex(i);
      ListItem.Data := Pointer(AComponentsIDs.GetIDByIndex(i));
    end;
  finally
    lvComponents.SortType := stText;
  end;
end;


procedure TF_MasterCableCanalTracing.AddIDComponentAndCountToTreeNodes(AIDComponent, ACount: Integer;
  ANameCompon: string; AChannelSection: Double; ANode: TFlyNode; ATakeChilds: Boolean);

  procedure AddComponentToNode(AParentNode: TFlyNode; ATakeChilds: Boolean);
  var
    Nodeinfo: PNodeinfo;
    CurrChild: TFlyNode;
  begin
    Nodeinfo := AParentNode.Data;
    if Nodeinfo <> nil then
    begin
      Nodeinfo.IDComponent := AIDComponent;
      Nodeinfo.NameComponent := ANameCompon;
      if (ACount > 0) and (AIDComponent <> 0) then
        Nodeinfo.CableCountToTrace := ACount;
      Nodeinfo.ChannelSection := RoundCP(FloatInUOM(AChannelSection, umSM, FUOMMin, 2));
      
      ShowNodeData(AParentNode);
    end;

    if ATakeChilds then
    begin
      CurrChild := AParentNode.getFirstChild;
      while CurrChild <> nil do
      begin
        AddComponentToNode(CurrChild, ATakeChilds);
        CurrChild := CurrChild.getNextSibling;
      end;
    end;
  end;

begin
  AddComponentToNode(ANode, ATakeChilds);
end;

function TF_MasterCableCanalTracing.AddGroupNodeToTree(ATreeView: TFlyTreeViewPro; AParentNode: TFLyNode; AGroupCaption: String; AGroupNodeType: TNodeType): TFLyNode;
var
  NodeInfo: TNodeInfo;
begin
  Result := nil;
  ZeroMemory(@NodeInfo, SizeOf(TNodeInfo));
  NodeInfo.NodeType := AGroupNodeType;
  Result := AddNodeToTreeView(ATreeView, AParentNode, AGroupCaption, NodeInfo);
end;

function TF_MasterCableCanalTracing.AddNodeToTreeView(
  ATreeView: TFlyTreeViewPro; AParentNode: TFlyNode;
  ACaption: String; ANodeInfo: TNodeInfo): TFlyNode;
var
  NewNode: TFlyNode;
  ptrNodeInfo: PNodeInfo;
begin
  Result := nil;
  if AParentNode = nil then
    Result := ATreeView.Items.Add(nil, ACaption)
  else
    Result := ATreeView.Items.AddChild(AParentNode, ACaption);

  GetZeroMem(ptrNodeInfo, SizeOf(TNodeInfo));
  ptrNodeInfo^ := ANodeInfo;
  //ptrNodeInfo.IDComponent := FIDComponentForAll;
  //ptrNodeInfo.NameComponent := FNameComponentForAll;
  //ptrNodeInfo.CableCountToTrace := FComponCountToTraceForAll;
  Result.Data := ptrNodeInfo;
  if ANodeInfo.NodeType = ntTrace then
    Result.ImageIndex := FtiiSCSLineNormal
  else
    Result.ImageIndex := FtiiSCSLineGroup;
  Result.SelectedIndex := Result.ImageIndex;

  //Result.StateIndex := Ord(csChecked);
  Result.StateIndex := STATE_CHECKED;
  ShowNodeData(Result);
end;

constructor TF_MasterCableCanalTracing.Create(AOwner: TComponent;
  AForm: TForm);
begin
  GForm := AForm;
  inherited Create(AOwner);
end;

destructor TF_MasterCableCanalTracing.Destroy;
begin
  inherited;
end;

function TF_MasterCableCanalTracing.Execute(
  AIDNBComponent: Integer; const ANameNBComponent, ACompTypeSysName: String; ACompTypeSysNames: TStringList): Boolean;
var
  i: integer;
  CurrTree: TFlyTreeViewPro;
begin
  Result := false;
  FNodeToSelInCAD := nil;
  try
    BeginProgress;
    try
      FUOMMin := ConvertUOMToMin(TF_Main(GForm).FUOM);

      Caption := GetMasterTracingCaption(ACompTypeSysName); //04.01.2011 GetCaptionByComponentType(ACompTypeSysName);
      //pnComponCountToTrace.Visible := false;
      gbTraceScaleGrops.Visible := false;
      spTraceScaleGrops.Visible := false;
      if ACompTypeSysName = ctsnCableChannel then
      begin
        cbUseComponentAsDefault.Caption := cMasterCableCanalTracing_Msg1;
        gbComponentsFromNB.Caption := cMasterCableCanalTracing_Msg2;
        gbTracingType.Caption := cMasterCableCanalTracing_Msg3;
        lbDestTraces.Caption := cMasterCableCanalTracing_Msg4;
        gbChoiceNBComponent.Caption := cMasterCableCanalTracing_Msg5;
        btSetNBComponentToNodeInfo.Hint := cMasterCableCanalTracing_Msg6;

        gbTraceScaleGrops.Visible := true;
        spTraceScaleGrops.Visible := true;

        pcComponInfo.ActivePage := tsCableChannel;
        lbComponVolume.Caption := '';
      end
      else
      begin
        cbUseComponentAsDefault.Caption := cMasterCableCanalTracing_Msg7;
        gbComponentsFromNB.Caption := cMasterCableCanalTracing_Msg8;
        gbTracingType.Caption := cMasterCableCanalTracing_Msg9;
        lbDestTraces.Caption := cMasterCableCanalTracing_Msg10;
        gbChoiceNBComponent.Caption := cMasterCableCanalTracing_Msg11;
        btSetNBComponentToNodeInfo.Hint := cMasterCableCanalTracing_Msg12;

        //pnComponCountToTrace.Visible := true;
        pcComponInfo.ActivePage := tsCable;
      end;
      for i := 0 to FtvList.Count - 1 do
      begin
        CurrTree := TFlyTreeViewPro(FtvList[i]);
        CurrTree.Columns[ciKolvo].Visible := ACompTypeSysName = ctsnCable;
        CurrTree.Columns[ciCablesTotalSection].Visible := ACompTypeSysName = ctsnCableChannel;
        CurrTree.Columns[ciChannelSection].Visible := ACompTypeSysName = ctsnCableChannel;

        CurrTree.Columns[ciCablesTotalSection].Caption := cMasterCableCanalTracing_Msg22_6+', '+GetNameUOMMin2;
        CurrTree.Columns[ciChannelSection].Caption := cMasterCableCanalTracing_Msg22_7+', '+GetNameUOMMin2;
      end;

      FNormBase := nil;
      FActiveTreeView := nil;
      FFocusedTreeView := nil;

      FIDComponentForAll := AIDNBComponent;
      FNameComponentForAll := ANameNBComponent;
      FComponCountToTraceForAll := 1;
      FComponentTypeSysName := ACompTypeSysName;
      FComponentTypeSysNames := ACompTypeSysNames;
      DefineComponVolumeForAll;

      FSCSList := nil;
      if TF_Main(GForm).GSCSBase.Active then
        if (TF_Main(GForm).GSCSBase.CurrProject <> nil) and TF_Main(GForm).GSCSBase.CurrProject.Active then
          if TF_Main(GForm).GSCSBase.CurrProject.CurrList <> nil then
            FSCSList := TF_Main(GForm).GSCSBase.CurrProject.CurrList;
      if FSCSList = nil then
      begin
        MessageModal(CActiveListNotExistMessage, ApplicationName, MB_ICONINFORMATION or MB_OK);
        Exit; ///// EXIT /////
      end;
      OpenNoExistsListInCAD(FSCSList);
      FLastGroupNode := nil;

      SetNBToForm;

      FComponentsIDs := nil;
      FAllTracesInfo := nil;
      FSelectedTracesInfo := nil;

      FLookedindexes := TIntList.Create;
      FStepIndex := -1;
      StepIndex(True);
      //if AIDNBComponent > 0 then
      //begin
      //  SelectComponentInListView(AIDNBComponent);
      //  StepIndex(True);
      //end;
      if AIDNBComponent > 0 then
        SelectComponentInListView(AIDNBComponent);
      StepIndex(True);
    finally
      EndProgress;
    end;

    try
      if ShowModal = mrOk then
      begin

      end;
    finally
      FLookedindexes.Free;
      if FComponentsIDs <> nil then
        FComponentsIDs.Free;
      lvComponents.Items.Clear;

      ClearTreeViewFly(tvAllTraces);
      ClearTreeViewFly(tvSelectedTraces);
      ClearTreeViewFly(tvDefineTrace);
      // Tolik 21/12/2019 --
      //FreeList(FAllTracesInfo);
      //FreeList(FSelectedTracesInfo);
      FreeAndDisposeList(FAllTracesInfo);
      FreeAndDisposeList(FSelectedTracesInfo);
      //
      if FNormBase <> nil then
        FreeAndNil(FNormBase);
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_MasterCableCanalTracing.Execute', E.Message);
  end;
end;

procedure TF_MasterCableCanalTracing.RefreshNodesData(ATreeViewToRefresh: TFlyTreeViewPro; ASrcNodeFromOtherTV: TFlyNode);
var
  SavedOnStateChange: TStateChangedEvent;

  procedure RefreshNodeData(ASrcStepNodeFromOtherTV: TFlyNode);
  var
    SrcNodeInfo: PNodeInfo;
    NodeToRefresh: TFlyNode;
    VariousStateIndex: Boolean;
  begin
    SrcNodeInfo := ASrcStepNodeFromOtherTV.Data;
    if SrcNodeInfo.NodeType = ntTrace then
    begin
      //*** Найти ветку трассы в обновляемом дереве
      NodeToRefresh := GetTraceNodeByTraceID(ATreeViewToRefresh, SrcNodeInfo.IDTrace);
      if NodeToRefresh <> nil then
      begin
        VariousStateIndex := NodeToRefresh.StateIndex <> ASrcStepNodeFromOtherTV.StateIndex;

        PNodeInfo(NodeToRefresh.Data)^ := SrcNodeInfo^;
        NodeToRefresh.StateIndex := ASrcStepNodeFromOtherTV.StateIndex;
        if VariousStateIndex then
        begin
          if totRefreshChilds in ATreeViewToRefresh.TreeOptions then
            ATreeViewToRefresh.NodeStateRefreshChildren(NodeToRefresh, false);
          if totrefreshParents in ATreeViewToRefresh.TreeOptions then
            ATreeViewToRefresh.NodeStateRefreshParent(NodeToRefresh, false);
        end;
        ShowNodeData(NodeToRefresh);
      end;
    end;
  end;

  procedure StepRefrech(ANode: TFlyNode);
  var
    ChildNode: TFlyNode;
  begin
    RefreshNodeData(ANode);
    ChildNode := ANode.getFirstChild;
    while ChildNode <> nil do
    begin
      StepRefrech(ChildNode);
      ChildNode := ChildNode.GetNextSibling;
    end;
  end;

begin
  SavedOnStateChange := ATreeViewToRefresh.OnStateChanged;
  ATreeViewToRefresh.OnStateChanged := nil;
  try
    StepRefrech(ASrcNodeFromOtherTV);
  finally
    ATreeViewToRefresh.OnStateChanged := SavedOnStateChange;
  end;
end;

procedure TF_MasterCableCanalTracing.RefreshSelectedInNB;
begin
  if TF_Main(FNormBase).pcObjects.ActivePage = TF_Main(FNormBase).tsComponents then
    NBTree_CatalogChange(TF_Main(FNormBase).Tree_Catalog, TF_Main(FNormBase).Tree_Catalog.Selected)
  else
  if TF_Main(FNormBase).pcObjects.ActivePage = TF_Main(FNormBase).tsTemplates then
    NBlvTemplatesSelectItem(TF_Main(FNormBase).FlvTemplate, TF_Main(FNormBase).FlvTemplate.Selected, true);
end;

procedure TF_MasterCableCanalTracing.ShowNodeData(ANode: TFlyNode);
var
  NodeInfo: PNodeInfo;
  aciComponent: Integer;
  aciKolvo: integer;
  aciCablesTotalSection: Integer;
  aciChannelSection: Integer;
begin
  NodeInfo := ANode.Data;

  //aciComponent := tvTraceScaleGrops.GetColumnOrder(ciComponent);
  //aciKolvo := tvTraceScaleGrops.GetColumnOrder(ciKolvo);
  //aciCablesTotalSection := tvTraceScaleGrops.GetColumnOrder(ciCablesTotalSection);

  aciComponent := ciComponent;
  aciKolvo := ciKolvo;
  aciCablesTotalSection := ciCablesTotalSection;
  aciChannelSection := ciChannelSection;

  if NodeInfo.NodeType = ntTrace then
  begin
    if NodeInfo.NameComponent <> '' then
      ANode.Cells[aciComponent] := NodeInfo.NameComponent
    else
      ANode.Cells[aciComponent] := '';

    if aciKolvo <> -1 then
      if NodeInfo.CableCountToTrace <> 0 then
        ANode.Cells[aciKolvo] := IntToStr(NodeInfo.CableCountToTrace)
      else
        ANode.Cells[aciKolvo] := '';

    if aciCablesTotalSection <> -1 then
      if NodeInfo.CablesTotalSection <> 0 then
        ANode.Cells[aciCablesTotalSection] := FloatToStr(RoundCP(NodeInfo.CablesTotalSection))
      else
        ANode.Cells[aciCablesTotalSection] := '';

    if aciChannelSection <> -1 then
      if NodeInfo.ChannelSection <> 0 then
        ANode.Cells[ciChannelSection] := FloatToStr(RoundCP(NodeInfo.ChannelSection))
      else
        ANode.Cells[ciChannelSection] := '';
  end
  else
  begin
    ANode.Cells[aciComponent] := '';
    ANode.Cells[aciKolvo] := '';
    ANode.Cells[aciCablesTotalSection] := '';
    ANode.Cells[ciChannelSection] := '';
  end;
end;

procedure TF_MasterCableCanalTracing.SelectComponentFromNode(ATreeNode: TFlyNode);
var
  NodeInfo: PNodeInfo;
begin
  Nodeinfo := ATreeNode.Data;
  if Nodeinfo <> nil then
    if NodeInfo.IDComponent > 0 then
    begin
      TF_Main(FNormBase).SelectComponInPCObjects(NodeInfo.IDComponent); //TF_Main(FNormBase).SelectComponByIDInTree(NodeInfo.IDComponent);
      seComponCountToTrace.Value := NodeInfo.CableCountToTrace; 
    end;
end;

procedure TF_MasterCableCanalTracing.SelectComponentInListView(AIDComponent: Integer);
var
  ListItem: TListItem;
  i: Integer;
begin
  for i := 0 to lvComponents.Items.Count - 1 do
  begin
    ListItem := lvComponents.Items[i];
    if Integer(ListItem.Data) = AIDComponent then
    begin
      lvComponents.Selected := ListItem;
      Break; ///// BREAK /////
    end;
  end;
end;

function TF_MasterCableCanalTracing.SelectTraceNodeByNodeFromOtherTree(ANodeFromOtherTree: TFlyNode; ATreeView: TFlyTreeViewPro): Boolean;
var
  TraceNode: TFlyNode;
begin
  Result := false;

  TraceNode := nil;
  if ANodeFromOtherTree <> nil then
    if ANodeFromOtherTree.Data <> nil then
      if (PNodeInfo(ANodeFromOtherTree.Data).NodeType = ntTrace) and
         (PNodeInfo(ANodeFromOtherTree.Data).IDTrace <> 0) then
      begin
        TraceNode := GetTraceNodeByTraceID(ATreeView, PNodeInfo(ANodeFromOtherTree.Data).IDTrace);
        if TraceNode <> nil then
          ATreeView.Selected := TraceNode;
      end;
end;

procedure TF_MasterCableCanalTracing.SelectTracesInCADFromNode(ANode: TFlyNode);
var
  LinesList: TList;
  Deselected: Boolean;

  procedure Step(AStepNode: TFlyNode; AStepIndex: Integer);
  var
    CurrChild: TFlyNode;
    NodeInfo: PNodeInfo;
    SCSCatalog: TSCSCatalog;
    ptrID: ^Integer;
  begin
    if (AStepNode.Data <> nil) and
       ((AStepNode.StateIndex = STATE_CHECKED) or (AStepNode = ANode)) //17.01.2011 Подсвечиваем трассу если она отмечена, или ее выделили в дереве
    then
    begin
      NodeInfo := AStepNode.Data;
      if NodeInfo.NodeType = ntTrace then
      begin
        SCSCatalog := TF_Main(GForm).GSCSBase.CurrProject.CurrList.GetCatalogFromReferences(NodeInfo.IDTrace);
        if SCSCatalog <> nil then
        begin
          GetZeroMem(ptrID, SizeOf(Integer));
          ptrID^ := SCSCatalog.SCSID;
          LinesList.Add(ptrID);

          if AStepIndex = 0 then
            SelectObjectInCAD(SCSCatalog.ListID, SCSCatalog.SCSID, '');
        end;
      end;
    end;

    CurrChild := AStepNode.GetFirstChild;
    while CurrChild <> nil do
    begin
      Step(CurrChild, AStepIndex + 1);
      CurrChild := CurrChild.getNextSibling;
    end;
  end;
begin
  LinesList := nil;

  Deselected := DeselectTraceInCAD;
  if cbSelectInPM.Checked and Assigned(ANode) then //17.01.2011
  begin
    LinesList := TList.Create;
    //DeselectAllSCSObjectsInCAD(FSCSList.CurrID);
    Step(ANode, 0);
    if LinesList.Count > 0 then
      SelectTraceInCAD(LinesList);
  end;

  if Deselected or (Assigned(LinesList) and (LinesList.Count > 0)) then
    RefreshCAD(GCadForm.PCad);

  if Assigned(LinesList) then
    FreeList(LinesList);
end;

procedure TF_MasterCableCanalTracing.SetComponentToTrace(ANBComponent: TSCSComponent; APMTrace: TSCSCatalog; ACableCount: Integer);
var
  RootHaveCables: Boolean;
  ComponFromTrace: TSCSComponent;
  i: Integer;

  CanFemaleHaveMaleRes: TCanFemaleHaveMaleRes;
  FemaleInterface: TSCSInterface;
  MaleValue: Double;

  DefMaleInterface: TSCSInterface;
  DefFemaleInterface: TSCSInterface;

  NewIDComponent: Integer;
  SendedComponToTrace: Boolean;

  PrevCableCount: Integer;
  PrevComponCount: Integer;
  CurrCableCount: Integer;
  CurrComponCount: Integer;
begin
  //*** Проверить флажок "Прокладывать только на пустых трассах"
  if cbTraceOnlyForEmptyObjects.Checked and
    (APMTrace.ComponentReferences.GetComponentByType(ANBComponent.ComponentType.SysName) <> nil) then
    Exit; ///// EXIT /////

  SendedComponToTrace := false;
  if CheckSysNameIsCableChannel(FComponentTypeSysName) then
  begin
    FemaleInterface := ANBComponent.GetInterfaceByTypeAndGender([itConstructive], [gtFemale], biTrue);
    if FemaleInterface = nil then
      Exit; ///// EXIT /////

    //CopyComponentToSCSObject(APMTrace.SCSID, ANBComponent.ID, true);
    //SendedComponToTrace := true;

    RootHaveCables := true;
    while RootHaveCables do
    begin
      RootHaveCables := false;
      //*** Пролверить, есть ли в тассе хотябы один компонет, кот мог бы поместиться в каб. канал
      for i := 0 to APMTrace.SCSComponents.Count - 1 do
      begin
        ComponFromTrace := APMTrace.SCSComponents[i];
        if ANBComponent.CheckCanalHaveCable(ComponFromTrace, DefFemaleInterface, DefMaleInterface).CanHave then
          if TF_Main(GForm).CanConnCompon(ANBComponent, ComponFromTrace, cntComplect, smtNone) then
          begin
            RootHaveCables := true;
            Break; ///// BREAK /////
          end;

        {MaleValue := ComponFromTrace.GetVolume(gtMale);
        if MaleValue > 0 then
        begin
          CanFemaleHaveMaleRes := TF_Main(GForm).CanFemaleHaveMale(FemaleInterface, MaleValue, TF_Main(GForm).GSCSBase.CurrProject.CurrList.Setting.CableCanalFullnessKoef);
          if CanFemaleHaveMaleRes.CanHave then
            if TF_Main(GForm).CanConnCompon(ANBComponent, ComponFromTrace, cntComplect, smtNone) then
            begin
              RootHaveCables := true;
              Break; ///// BREAK /////
            end;
        end;}
      end;
      if APMTrace.SCSComponents.Count = 0 then
        RootHaveCables := true;

      if RootHaveCables then
      begin
        PrevCableCount := GetCatalogTopComponCountByWithoutType(APMTrace, ctsnCableChannel);
        PrevComponCount := APMTrace.SCSComponents.Count;

        NewIDComponent := CopyComponentToSCSObject(APMTrace.SCSID, ANBComponent.ID, true);

        if (TF_Main(GForm).FProjectMan.FQuastLastResPlaceToConduitMaxCompons = mrCancel) and
           CheckSysNameIsCableChannel(FComponentTypeSysName) then
        begin
          //TF_Main(GForm).FProjectMan.DelCompon(NewIDComponent, nil, false, true, true, false);
          Break; //// BREAK ////
        end;

        CurrCableCount := GetCatalogTopComponCountByWithoutType(APMTrace, ctsnCableChannel);
        CurrComponCount := APMTrace.SCSComponents.Count;

        if PrevComponCount <> CurrComponCount then
          SendedComponToTrace := true;

        //*** Если каб. канал не смог вместить в себя кабели, то идти альше
        if PrevCableCount = CurrCableCount then
          RootHaveCables := false;
      end;
    end;
  end
  else
    for i := 0 to ACableCount - 1 do
    begin
      NewIDComponent := CopyComponentToSCSObject(APMTrace.SCSID, ANBComponent.ID, false);
      SendedComponToTrace := true;
      //if NewIDComponent > 0 then
      //  AutoConnectOnAppendCable(APMTrace.SCSID);
    end;
  if SendedComponToTrace then
    AutoConnectOnAppendCable(APMTrace.ListID, APMTrace.SCSID);
end;

procedure TF_MasterCableCanalTracing.SetControls;
begin
  if FSelectedTracesInfo <> nil then
  begin
    rbSelectedTraces.Enabled := FSelectedTracesInfo.Count > 0;
    if Not rbSelectedTraces.Enabled and rbSelectedTraces.Checked then
      rbAllTraces.Checked := true;
  end;

  //cbUseOneCanalForAll.Visible := rbDefineTrace.Checked;
  //lbUseOneCanalForAll.Visible := rbDefineTrace.Checked;
  //pnCanalForType.Visible := rbDefineTrace.Checked;

  //pnCanalForAll.Enabled := (rbDefineTrace.Checked and cbUseOneCanalForAll.Checked) or
                           //(Not rbDefineTrace.Checked);

  //pnCanalForType.Enabled := (rbDefineTrace.Checked and Not pnCanalForAll.Enabled);
  EnableDisableActions; 
end;


procedure TF_MasterCableCanalTracing.SetNBToForm;
begin
  try
    GGDBMode := bkNormBase;
    FNormBase := TF_Main.Create(Self, bkNormBase, fmConnections, pnNBComponents);
    if TF_Main(FNormBase).gbTemplateGroups.GroupCount = 0 then
      TF_Main(FNormBase).LoadTemplateGroups;
    FSavedNBTreeCatalogChange := TF_Main(FNormBase).Tree_Catalog.OnChange;
    FSavedNBlvTemplatesSelectItem := TF_Main(FNormBase).lvTemplatesSelectItem; //TF_Main(FNormBase).lvTemplates.OnSelectItem;
    FSavedNBpcObjectsChange := TF_Main(FNormBase).pcObjects.OnChange;
    FSavedNBtvComponGroupsChange := TF_Main(FNormBase).tvComponGroups.OnChange;

    TF_Main(FNormBase).FNormBase := F_NormBase;
    TF_Main(FNormBase).FProjectMan := F_ProjMan;

    TF_Main(FNormBase).Visible := false;
    TF_Main(FNormBase).GSCSBase.NBSpravochnik.Assign(F_NormBase.GSCSBase.NBSpravochnik);

    TF_Main(FNormBase).Constraints.MinWidth := 0;
    TF_Main(FNormBase).ToolBar_Tree.Visible := false;
    TF_Main(FNormBase).HideTemplateItems(FComponentTypeSysNames, false);
    TF_Main(FNormBase).HideTemplateEditingControls;
    TF_Main(FNormBase).Panel_Addition.Visible := false;
    TF_Main(FNormBase).Panel_OKCancel.Visible := false;
    //TF_Main(FNormBase).Parent := pnNBComponents;
    TF_Main(FNormBase).Align := alClient;
    TF_Main(FNormBase).EnableDisableEdit(false);
    TF_Main(FNormBase).Tree_Catalog.PopupMenu := nil;
    TF_Main(FNormBase).Tree_Catalog.OnChange := NBTree_CatalogChange;
    TF_Main(FNormBase).lvTemplates.OnSelectItem := NBlvTemplatesSelectItem;
    TF_Main(FNormBase).SetEventsToLVTemplate(NBlvTemplatesSelectItem, nil);
    TF_Main(FNormBase).tvComponGroups.OnChange := NBtvComponGroupsChange;
    TF_Main(FNormBase).pcObjects.OnChange := NBpcObjectsChange;

    FreeAndNil(TF_Main(FNormBase).PopupMenu_Catalog);
    if FComponentTypeSysNames <> nil then
      TF_Main(FNormBase).SetFilterBlockForCompType(FComponentTypeSysNames);

    TF_Main(FNormBase).InitComponGroup(FComponentTypeSysName);
    if GetGUIDFromComboBoxRz(TF_Main(FNormBase).cbGroupCompType) <> FComponentTypeSysName then
      TF_Main(FNormBase).tsComponGroups.TabVisible := false;

    TF_Main(FNormBase).Visible := true;
  except
    on E: Exception do AddExceptionToLogEx('TF_MasterCableCanalTracing.SetNBToForm', E.Message);
  end;
end;

procedure TF_MasterCableCanalTracing.StepIndex(AIsInc: Boolean);
begin
  try
    case AIsInc of
      True:
        Inc(FStepIndex);
      False:
        Dec(FStepIndex);
    end;
    case FStepIndex of
      0:
        begin
          pcMain.ActivePage := tsStep0;
          btBack.Enabled := false;
          btOk.Caption := cMasterCableCanalTracing_Msg14;

          if FComponentsIDs = nil then
          begin
            FComponentsIDs := TF_Main(GForm).FNormBase.DM.GetComponsIDNameByType(FComponentTypeSysName);
            lvComponents.Items.Clear;
            AddComponentsToListView(FComponentsIDs);
          end;

          cbUseComponentAsDefault.Checked := true;
          pnUseComponentAsDefault.Visible := (FLookedindexes.IndexOf(FStepIndex) <> -1) and
                                         (FLookedindexes.IndexOf(FStepIndex + 1) <> -1);
        end;
      1:
        begin
          pcMain.ActivePage := tsStep1;
          btBack.Enabled := true;
          btOk.Caption := cMasterCableCanalTracing_Msg15;

          if FAllTracesInfo = nil then
            FAllTracesInfo := GetTraceInfo(FSCSList.CurrID);
          if FSelectedTracesInfo = nil then
            FSelectedTracesInfo := GetTraceInfoFromListBySelected(FAllTracesInfo, true);

          if FLookedindexes.IndexOf(FStepIndex) = -1 then
          begin
            if rbAllTraces.Checked then
              ReChangeRadioButton(rbAllTraces);
            if rbSelectedTraces.Checked then
              ReChangeRadioButton(rbSelectedTraces);
            if rbDefineTrace.Checked then
              ReChangeRadioButton(rbDefineTrace);
          end
          else
            AfterChangeActiveTreeView;
        end;
    end;
    if FLookedindexes.IndexOf(FStepIndex) = -1 then
      FLookedindexes.Add(FStepIndex);
    SetControls;
  except
    on E: Exception do AddExceptionToLogEx('TF_MasterCableCanalTracing.StepIndex', E.Message);
  end;
end;

function TF_MasterCableCanalTracing.TraceComponentsFromTree(ATreeView: TFlyTreeViewPro): Boolean;
var
  Node: TFlyNode;
  NodeInfo: PNodeInfo;
  NodesInfoToTrace: TList;
  TraceObject: TSCSCatalog;
  NBComponents: TSCSComponents;
  NBComponent: TSCSComponent;
  i: Integer;
  ProgressCaption: String;
  IsSetComponToTrace: Boolean;
  SCSListIDs: TIntList;
begin
  Result := false;
  NodesInfoToTrace := TList.Create;
  NBComponents := TSCSComponents.Create(true);
  SCSListIDs := TIntList.Create;
  try
    //*** Отобрать трассы с инфой для для прокладки каб каналов
    Node := ATreeView.Items[0];
    while Node <> nil do
    begin
      NodeInfo := Node.Data;
      if NodeInfo.NodeType = ntTrace then
        //if TRzCheckState(Node.StateIndex) = csChecked then
        if Node.StateIndex = STATE_CHECKED then
          NodesInfoToTrace.Add(NodeInfo);
      Node := Node.GetNext;
    end;
    //for i := 0 to ATreeView.Items.Count - 1 do
    //begin
    //  Node := ATreeView.Items[i];
    //  NodeInfo := Node.Data;
    //  if NodeInfo.NodeType = ntTrace then
    //    //if TRzCheckState(Node.StateIndex) = csChecked then
    //    if Node.StateIndex = STATE_CHECKED then
    //      NodesInfoToTrace.Add(NodeInfo);
    //end;

    //TF_Main(GForm).F_Animate.GMaxProgressPos := NodesInfoToTrace.Count * 2;
    //TF_Main(GForm).F_Animate.StartAnimate('Прокладка кабельных каналов', aviCopyFiles, aiProgressBar);

    ProgressCaption := '';
    if CheckSysNameIsCableChannel(FComponentTypeSysName) then
      ProgressCaption := cMasterCableCanalTracing_Msg16_1
    else
      ProgressCaption := cMasterCableCanalTracing_Msg16_2;

    IsSetComponToTrace := false;
    for i := 0 to NodesInfoToTrace.Count - 1 do
    begin
      NodeInfo := NodesInfoToTrace[i]; 
      //*** Проверить, есть ли хоть один установленный компонент
      if NodeInfo.IDComponent <> 0 then
        IsSetComponToTrace := true;
      //*** Внести ID листа в список
      if NodeInfo.TraceObject <> nil then
        if SCSListIDs.IndexOf(NodeInfo.TraceObject.ListID) = -1 then
          SCSListIDs.Add(NodeInfo.TraceObject.ListID);
    end;

    if IsSetComponToTrace then
    begin
      Result := true;

      TF_Main(GForm).FProjectMan.FQuastAdditButtonsPlaceToConduitMaxCompons := [mbYesToAll, mbNoToAll];
      BeginProgress(ProgressCaption, NodesInfoToTrace.Count * 2 + 1);
      try
        SaveListsToUndoStack(SCSListIDs);
        StepProgress;

        //*** Загрузить объекты кабельных каналов
        for i := 0 to NodesInfoToTrace.Count - 1 do
        begin
          NodeInfo := NodesInfoToTrace[i];
          if NodeInfo.IDComponent <> 0 then
            if NBComponents.GetComponenByID(NodeInfo.IDComponent) = nil then
            begin
              NBComponent := TSCSComponent.Create(TF_Main(GForm).FNormBase);
              NBComponent.LoadComponentByID(NodeInfo.IDComponent);
              NBComponents.Add(NBComponent);

              TF_Main(GForm).FNormBase.DM.AddComponGUIDToFreqUseObj(NBComponent.GuidNB);
            end;
          StepProgress;
        end;

        //*** Проложить каб-е каналы на трассы
        for i := 0 to NodesInfoToTrace.Count - 1 do
        begin
          NodeInfo := NodesInfoToTrace[i];
          NBComponent := NBComponents.GetComponenByID(NodeInfo.IDComponent);
          TraceObject := NodeInfo.TraceObject; //TF_Main(GForm).GSCSBase.CurrProject.CurrList.GetCatalogFromReferences(NodeInfo.IDTrace);
          if (NBComponent <> nil) and (TraceObject <> nil) then
          begin
            SetComponentToTrace(NBComponent, TraceObject, NodeInfo.CableCountToTrace);
            // Если была нажата отмена, то выходим из цикла
            if (TF_Main(GForm).FProjectMan.FQuastLastResPlaceToConduitMaxCompons = mrCancel) and
               CheckSysNameIsCableChannel(FComponentTypeSysName) then
              Break; //// BREAK ////
          end;
          StepProgress;
        end;
      finally
        EndProgress;
      end;
      TF_Main(GForm).FProjectMan.FQuastAdditButtonsPlaceToConduitMaxCompons := [];
      TF_Main(GForm).FProjectMan.FQuastLastResPlaceToConduitMaxCompons := -1;
    end
    else
      MessageModal(cMasterCableCanalTracing_Msg26, ApplicationName, MB_OK or MB_ICONINFORMATION);
  finally
    NBComponents.Free;
    NodesInfoToTrace.Free;
    SCSListIDs.Free;
  end;
end;

procedure TF_MasterCableCanalTracing.AddTraceInfoToTreeView(ATreeView: TFlyTreeViewPro; AParentNode: TFlyNode; ATraceInfo: TList);
var
  TraceObject: TSCSCatalog;
  ptrTraceInfo: PTraceInfo;
  TraceNodeInfo: TNodeInfo;
  i: Integer;
begin
  for i := 0 to ATraceInfo.Count - 1 do
  begin
    ptrTraceInfo := ATraceInfo[i];
    TraceObject := TF_Main(GForm).GSCSBase.CurrProject.CurrList.GetCatalogFromReferencesBySCSID(ptrTraceInfo.FigureID);
    if TraceObject <> nil then
    begin
      ZeroMemory(@TraceNodeInfo, SizeOf(TNodeInfo));
      TraceNodeInfo.IDTrace := TraceObject.ID;
      TraceNodeInfo.NodeType := ntTrace;
      TraceNodeInfo.CablesTotalSection := RoundCP(FloatInUOM(GetTotalSectionFromTopCables(TraceObject), umSM, FUOMMin, 2));
      TraceNodeInfo.ChannelSection := 0;
      TraceNodeInfo.TraceObject := TraceObject;

      AddNodeToTreeView(ATreeView, AParentNode, TraceObject.GetNameForVisible, TraceNodeInfo);
    end;
  end;
end;

function TF_MasterCableCanalTracing.AddTraceInfoAsGroupToTreeView(ATreeView: TFlyTreeViewPro;
  AParentNode: TFlyNode; AGroupCaption: String; AGroupNodeType: TNodeType;
  ATraceInfo: TList; AExpandGrp: Boolean): TFlyNode;
//var
//  NodeInfo: TNodeInfo;
begin
  Result := AddGroupNodeToTree(ATreeView, AParentNode, AGroupCaption, AGroupNodeType);
  //ZeroMemory(@NodeInfo, SizeOf(TNodeInfo));
  //NodeInfo.NodeType := AGroupNodeType;
  //Result := AddNodeToTreeView(ATreeView, AParentNode, AGroupCaption, NodeInfo);

  AddTraceInfoToTreeView(ATreeView, Result, ATraceInfo);
  if AExpandGrp then
    Result.Expanded := true;

  //*** Установить параметры по умолчанию
  AddIDComponentAndCountToTreeNodes(FIDComponentForAll, 1, FNameComponentForAll, FVolumeComponentForAll, Result, true);
end;

procedure TF_MasterCableCanalTracing.AfterChangeActiveTreeView;
begin
  RefreshSelectedInNB; //22.05.2009 NBTree_CatalogChange(TF_Main(FNormBase).Tree_Catalog, TF_Main(FNormBase).Tree_Catalog.Selected);
  tvDefineTraceChange(FActiveTreeView, FActiveTreeView.Selected);
  SelectComponentFromNode(FActiveTreeView.Selected);

  try
    if FActiveTreeView <> nil then
      if Self.Active then // Tolik 27/12/2019--
        FActiveTreeView.SetFocus;
  except
  end;

  SetControls;
end;

procedure TF_MasterCableCanalTracing.ApplyNodeSelection(ANode: TFlyNode);
var
  NodeInfo: PNodeinfo;
  PMTraceNode: TTreeNode;
begin
  NodeInfo := ANode.Data;

  EnableDisableActions;

  if NodeInfo <> nil then
  begin
    SelectComponentFromNode(ANode);

    if NodeInfo.NodeType = ntTrace then
    begin
      if cbSelectInPM.Checked then
      begin
        PMTraceNode := TF_Main(GForm).FindComponOrDirInTree(NodeInfo.IDTrace, false);
        if PMTraceNode <> nil then
        begin
          TF_Main(GForm).SelectNodeDirect(PMTraceNode); //TF_Main(GForm).Tree_Catalog.Selected := PMTraceNode;
        end;
      end;
    end;

    //17.01.2011 if cbSelectInPM.Checked then
      SelectTracesInCADFromNode(ANode);

    RefreshSelectedInNB; //22.05.2009 NBTree_CatalogChange(TF_Main(FNormBase).Tree_Catalog, TF_Main(FNormBase).Tree_Catalog.Selected);
  end;
end;

procedure TF_MasterCableCanalTracing.DefineComponVolumeForAll;
begin
  try
    FVolumeComponentForAll := 0;
    if GCompTypeSysNameCableChannels.IndexOf(FComponentTypeSysName) <> -1 then
      FVolumeComponentForAll := TF_Main(GForm).FNormBase.DM.GetComponVolume(FIDComponentForAll, gtFemale);
  except
    on E: Exception do AddExceptionToLogEx('TF_MasterCableCanalTracing.DefineComponVolumeForAll', E.Message);
  end;
end;

{
procedure TF_MasterCableCanalTracing.ClearCheckTreeView(ATreeView: TRzCheckTree);
var
  i: Integer;
  Node: TTreeNode;
begin
  for i := 0 to ATreeView.Items.Count - 1 do
  begin
    Node := ATreeView.Items[i];
    if Node.Data <> nil then
      FreeMem(Node.Data);
  end;
  ATreeView.Items.Clear;
end;}

procedure TF_MasterCableCanalTracing.DropComponFromTraceNode(ATraceNode: TFlyNode; AParalellTree: TFlyTreeViewPro);
var
  NodeInfo: PNodeInfo;
begin
  if (ATraceNode <> nil) and (ATraceNode.Data <> nil) then
  begin
    NodeInfo := ATraceNode.Data;
    if (NodeInfo.NodeType = ntTrace) and
       (NodeInfo.IDComponent <> 0) then
      if MessageModal(cMasterCableCanalTracing_Msg25, ApplicationName, MB_ICONQUESTION or MB_YESNO) = IDYES then
      begin
        NodeInfo.IDComponent := 0;
        NodeInfo.NameComponent := '';
        NodeInfo.CableCountToTrace := 0;
        NodeInfo.CablesTotalSection := 0;
        ShowNodeData(ATraceNode);

        RefreshNodesData(AParalellTree, ATraceNode);
      end;
  end;
end;

procedure TF_MasterCableCanalTracing.EnableDisableActions;
var
  MainNodeInfo: PNodeinfo;
  ScaleNodeInfo: PNodeinfo;
begin
  Act_SelectTraceFromMainToScaleTree.Visible := CheckSysNameIsCableChannel(FComponentTypeSysName);
  Act_SelectTraceFromScaleToMainTree.Visible := CheckSysNameIsCableChannel(FComponentTypeSysName);

  Act_DropComponFromMainTree.Enabled := false;
  Act_DropComponFromScaleTree.Enabled := false;
  Act_SelectTraceFromMainToScaleTree.Enabled := false;
  Act_SelectTraceFromScaleToMainTree.Enabled := false;

  if FActiveTreeView <> nil then
    if FActiveTreeView.Selected <> nil then
    begin
      MainNodeInfo := FActiveTreeView.Selected.Data;
      if MainNodeInfo.NodeType = ntTrace then
      begin
        Act_SelectTraceFromMainToScaleTree.Enabled := true;
        if MainNodeInfo.IDComponent <> 0 then
          Act_DropComponFromMainTree.Enabled := true;
      end;
    end;

  if tvTraceScaleGrops.Selected <> nil then
  begin
    ScaleNodeInfo := tvTraceScaleGrops.Selected.Data;
    if ScaleNodeInfo.NodeType = ntTrace then
    begin
      Act_SelectTraceFromScaleToMainTree.Enabled := true;
      if ScaleNodeInfo.IDComponent <> 0 then
        Act_DropComponFromScaleTree.Enabled := true;
    end;
  end;
end;

function TF_MasterCableCanalTracing.GetNameUOMMin2: String;
begin
  Result := GetNameUOM2(FUOMMin);
end;

function TF_MasterCableCanalTracing.GetGroupNodeByNode(ANode: TFlyNode): TFlyNode;
var
  CurrNode: TFlyNode;
begin
  Result := nil;
  CurrNode := ANode;
  while CurrNode <> nil do
  begin
    if PNodeInfo(CurrNode.Data).NodeType <> ntTrace then
    begin
      Result := CurrNode;
      Break; //// BREAK ////
    end;
    CurrNode := CurrNode.Parent;
  end;
end;

function TF_MasterCableCanalTracing.GetTraceNodeByTraceID(ATreeView: TFlyTreeViewPro; ATraceID: Integer): TFlyNode;
var
  CurrNode: TFlyNode;
begin
  Result := nil;
  CurrNode := nil;
  if ATreeView.Items.Count > 0 then
    CurrNode := ATreeView.Items[0];
  while CurrNode <> nil do
  begin
    if (PNodeInfo(CurrNode.Data).NodeType = ntTrace) and
       (PNodeInfo(CurrNode.Data).IDTrace = ATraceID) then
    begin
      Result := CurrNode;
      Break; //// BREAK ////
    end;
    CurrNode := CurrNode.GetNext;
  end;
end;

function TF_MasterCableCanalTracing.GetTreeViewFirstNode(ATreeView: TFlyTreeViewPro): TFlyNode;
begin
  Result := nil;
  if ATreeView.Items.Count > 0 then
    Result := ATreeView.Items[0];
end;

function TF_MasterCableCanalTracing.HaveNodeChildByNodeType(ANode: TFlyNode; ANodeType: TNodeType): Boolean;

  procedure Step(AParentNode: TFlyNode);
  var
    CurrChild: TFlyNode;
    NodeInfo: PNodeInfo;
  begin
    CurrChild := AParentNode.getFirstChild;
    while CurrChild <> nil do
    begin
      NodeInfo := CurrChild.Data;
      if NodeInfo <> nil then
        if NodeInfo.NodeType = ANodeType then
        begin
          Result := true;
          Break; ///// BREAK /////
        end;
      Step(CurrChild);
      CurrChild := CurrChild.getNextSibling;
    end;
  end;

begin
  Result := false;
  Step(ANode);
end;

procedure TF_MasterCableCanalTracing.LoadTraceScaleGropsToTreeFromNode(ANode: TFlyNode);
var
  GroupNode: TFlyNode;
  GroupNodeInfo: TNodeInfo;
  ChildNodeList: TObjectList;
  NodeInfo: PNodeInfo;
  i, j: Integer;
  TraceNode: TFlyNode;
  NewTraceNode: TFlyNode;
  NewTraceNodeInfo: PNodeInfo;
  NodeI: TFlyNode;
  NodeJ: TFlyNode;

  ScaleStep: Integer;
  ScaleGrpNodeList: TObjectList;
  //ScaleGrpNode: TTreeNode;
  //ScaleFrom: Integer;
  //ScaleTo: Integer;
  LastScaleFromValue: Integer;
  LastScaleGrpNode: TFlyNode;
  TraceScaleFromValue: Integer;
  TraceScaleToValue: Integer;

  SavedOnStateChange: TStateChangedEvent;
begin
  ClearTreeViewFly(tvTraceScaleGrops);

  if CheckSysNameIsCableChannel(FComponentTypeSysName) then
  begin
    GroupNode := GetGroupNodeByNode(ANode);
    if GroupNode <> nil then
    begin
      SavedOnStateChange := tvTraceScaleGrops.OnStateChanged;
      tvTraceScaleGrops.OnStateChanged := nil;
      try
        //*** Определить все Чилды
        ChildNodeList := GetAllChildNodesFly(GroupNode);
        //*** Оставить только трассы, с сечением больше 1-го
        i := 0;
        // Tolik -- 11/05/2017 --
        {
        while i <= ChildNodeList.Count - 1 do
        begin
          NodeInfo := TFlyNode(ChildNodeList[i]).Data;
          if (NodeInfo.NodeType <> ntTrace) or (NodeInfo.CablesTotalSection = 0) then
            ChildNodeList.Delete(i)
          else
            Inc(i);
        end;
        }
        //
        //*** Сортировать список трасс по сечению кабелей
        for i := 0 to ChildNodeList.Count - 1 do
        begin
          NodeI := TFlyNode(ChildNodeList[i]);
          for j := i to ChildNodeList.Count - 1 do
          begin
            NodeJ := TFlyNode(ChildNodeList[j]);
            if PNodeInfo(NodeJ.Data).CablesTotalSection < PNodeInfo(NodeI.Data).CablesTotalSection then
            begin
              ExchangeObjects(NodeI, NodeJ);
              ChildNodeList[i] := NodeI;
              ChildNodeList[j] := NodeJ;
            end;
          end;
        end;
        //*** Разгруппировать трассы по группам
        ScaleStep := Trunc(seScaleStep.Value);
        ScaleGrpNodeList := TObjectList.Create(false);
        LastScaleFromValue := 0;
        LastScaleGrpNode := nil;
        for i := 0 to ChildNodeList.Count - 1 do
        begin
          TraceNode := TFlyNode(ChildNodeList[i]);
          NodeInfo := TraceNode.Data;
          // Tolik -- 05/12017 --
          if NodeInfo.NodeType = ntTrace then
          begin
            //*** Сечение кабелей меньше одного
            if NodeInfo.CablesTotalSection < 1 then
            begin
              // Tolik -- 11/05/2017 -- чтобы добавить пустые трассы
              {if LastScaleGrpNode = nil then
                LastScaleGrpNode := AddGroupNodeToTree(tvTraceScaleGrops, nil, cMasterCableCanalTracing_Msg23+cMasterCableCanalTracing_Msg27+GetNameUOMMin2, ntNone);}
              if LastScaleGrpNode = nil then
              begin
                if NodeInfo.CablesTotalSection <> 0  then
                  LastScaleGrpNode := AddGroupNodeToTree(tvTraceScaleGrops, nil, cMasterCableCanalTracing_Msg23+cMasterCableCanalTracing_Msg27+GetNameUOMMin2, ntNone)
                else
                  LastScaleGrpNode := AddGroupNodeToTree(tvTraceScaleGrops, nil, cMasterCableCanalTracing_Msg28, ntNone);
              end;
            end
            else
            //*** Сечение кабелей больше одного
            begin
              //*** Определить начальное значение градации для трассы TraceNode
              if NodeInfo.CablesTotalSection <= ScaleStep then
              begin
                TraceScaleFromValue := Trunc(NodeInfo.CablesTotalSection) - (Trunc(NodeInfo.CablesTotalSection) mod ScaleStep) + 1;
                TraceScaleToValue := TraceScaleFromValue + ScaleStep - 1;
              end
              else
              begin
                TraceScaleFromValue := Trunc(NodeInfo.CablesTotalSection) - (Trunc(NodeInfo.CablesTotalSection) mod ScaleStep);
                TraceScaleToValue := TraceScaleFromValue + ScaleStep;
              end;

              //*** Определить групповую ветвь
              if (LastScaleFromValue <> TraceScaleFromValue) or (LastScaleGrpNode = nil) then
              begin
                ZeroMemory(@GroupNodeInfo, SizeOf(TNodeInfo));
                GroupNodeInfo.CableCountToTrace := 1;
                GroupNodeInfo.NodeType := ntNone;
                //LastScaleGrpNode := AddNodeToTreeView(tvTraceScaleGrops, nil,
                //                cMasterCableCanalTracing_Msg23+ IntToStr(TraceScaleFromValue)+'-'+IntToStr(TraceScaleToValue)+cNameSantim2, GroupNodeInfo);
                LastScaleGrpNode := AddGroupNodeToTree(tvTraceScaleGrops, nil,
                                cMasterCableCanalTracing_Msg23+IntToStr(TraceScaleFromValue)+'-'+IntToStr(TraceScaleToValue)+' '+GetNameUOMMin2, ntNone);

                LastScaleFromValue := TraceScaleFromValue;
              end;
            end;
          end;

          if LastScaleGrpNode <> nil then
          begin
            NewTraceNode := AddNodeToTreeView(tvTraceScaleGrops, LastScaleGrpNode, TraceNode.Text, NodeInfo^);
            PNodeinfo(NewTraceNode.Data)^ := NodeInfo^;
            NewTraceNode.StateIndex := TraceNode.StateIndex;
            ShowNodeData(NewTraceNode);
          end;
        end;

        FreeAndNil(ScaleGrpNodeList);
        FreeAndNil(ChildNodeList);
      finally
        tvTraceScaleGrops.OnStateChanged := SavedOnStateChange;
      end;
    end;
  end;
end;

procedure TF_MasterCableCanalTracing.ReChangeRadioButton(ARadioButton: TRzRadioButton);
begin
  ARadioButton.Checked := Not ARadioButton.Checked;
  ARadioButton.Checked := Not ARadioButton.Checked;
end;

procedure TF_MasterCableCanalTracing.rbAllTracesClick(Sender: TObject);
var
  GroupNode: TFlyNode;
  SavedOnStateChange: TStateChangedEvent;
begin
  if tvAllTraces.Items.Count = 0 then
  begin
    SavedOnStateChange := tvAllTraces.OnStateChanged;
    tvAllTraces.OnStateChanged := nil;
    try
      GroupNode := AddTraceInfoAsGroupToTreeView(tvAllTraces, nil, cMasterCableCanalTracing_Msg17, ntNone, FAllTracesInfo, true);
    finally
      tvAllTraces.OnStateChanged := SavedOnStateChange;
    end;
    tvAllTraces.selected := GroupNode;
  end;

  FActiveTreeView := tvAllTraces;
  pcTrees.ActivePage := tsAllTraces;
  AfterChangeActiveTreeView;

  //SetControls;
end;

procedure TF_MasterCableCanalTracing.rbSelectedTracesClick(
  Sender: TObject);
var
  GroupNode: TFlyNode;
  SavedOnStateChange: TStateChangedEvent;
begin
  if tvSelectedTraces.Items.Count = 0 then
  begin
    SavedOnStateChange := tvSelectedTraces.OnStateChanged;
    tvSelectedTraces.OnStateChanged := nil;
    try
      GroupNode := AddTraceInfoAsGroupToTreeView(tvSelectedTraces, nil, cMasterCableCanalTracing_Msg18, ntNone, FSelectedTracesInfo, true);
    finally
      tvSelectedTraces.OnStateChanged := SavedOnStateChange;
    end;
    tvSelectedTraces.selected := GroupNode;
  end;

  FActiveTreeView := tvSelectedTraces;
  pcTrees.ActivePage := tsSelectedTraces;
  AfterChangeActiveTreeView;

  //SetControls;
end;

procedure TF_MasterCableCanalTracing.rbDefineTraceClick(Sender: TObject);
var
  NodeInfo: TNodeinfo;

  VerticalTraces: TList;            // вертикальные трассы
  //ntTypeHorizontalTraces,  // горизонтальные трассы
  TracesInHeightTracing: TList;     // трассы на высоте размещения трасс
  TracesInHeightSocket: TList;      // трассы на высоте размещения точечных объектов
  TracesInHeightFloor: TList;       // трассы в полу(высота размещения = 0)
  TracesInHeightBetweenSocketFloor: TList; // Трасса между полом и розетками
  TracesInHeightCeiling: TList;     // под потолком (высота размещения трасс = высота потолка)
  TracesInHeightFalseCeiling: TList;// трассы над фальш-потолком
  TracesInHeightNoCategory: TList;  // трассы не попавшие в категории выше

  LooadedTracesInfos: TList; // Список загруженных трасс 

  TracesInCategories: TList;

  TraceTypes: TFlyNode;
  GrpHorzNode: TFlyNode;
  SavedOnStateChange: TStateChangedEvent;
begin
  if tvDefineTrace.Items.Count = 0 then
  begin
    VerticalTraces := nil;
    TracesInHeightTracing := nil;
    TracesInHeightSocket := nil;
    TracesInHeightFloor := nil;
    TracesInHeightBetweenSocketFloor := nil;
    TracesInHeightCeiling := nil;
    TracesInHeightFalseCeiling := nil;
    TracesInHeightNoCategory := nil;

    TracesInCategories := nil;
    LooadedTracesInfos := TList.Create;
    SavedOnStateChange := tvDefineTrace.OnStateChanged;
    tvDefineTrace.OnStateChanged := nil;
    try
      //*** Типы трасс
      ZeroMemory(@NodeInfo, SizeOf(TNodeInfo));
      NodeInfo.NodeType := ntNone;
      TraceTypes := AddNodeToTreeView(tvDefineTrace, nil, cMasterCableCanalTracing_Msg19_1, NodeInfo);
      tvDefineTrace.Selected := TraceTypes;

      //*** вертикальные трассы
      VerticalTraces := GetTraceInfoFromListByPosition(FAllTracesInfo, tpVertical);
      if VerticalTraces.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, TraceTypes, cMasterCableCanalTracing_Msg19_2, ntTypeVerticalTraces, VerticalTraces, false);


      //*** Горизонтальные трассы
      //
      ZeroMemory(@NodeInfo, SizeOf(TNodeInfo));
      NodeInfo.NodeType := ntTypeHorizontalTraces;
      GrpHorzNode := AddNodeToTreeView(tvDefineTrace, TraceTypes, cMasterCableCanalTracing_Msg19_3, NodeInfo);

      //*** трассы на высоте размещения трасс
      TracesInHeightTracing := GetTraceInfoFromListByHorzHeight(FAllTracesInfo, FSCSList.Setting.HeightCorob, -1, false, false, LooadedTracesInfos);
      if TracesInHeightTracing.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_4, ntTypeHeightTracing, TracesInHeightTracing, false);

      //*** трассы на высоте размещения точечных объектов
      TracesInHeightSocket := GetTraceInfoFromListByHorzHeight(FAllTracesInfo, FSCSList.Setting.HeightSocket, -1, false, false, LooadedTracesInfos);
      if TracesInHeightSocket.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_5, ntTypeHeightSocket, TracesInHeightSocket, false);

      //*** трассы в полу(высота размещения = 0)
      TracesInHeightFloor := GetTraceInfoFromListByHorzHeight(FAllTracesInfo, 0, -1, false, false, LooadedTracesInfos);
      if TracesInHeightFloor.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_6, ntTypeHeightFloor, TracesInHeightFloor, false);

      //*** Трасса между полом и розетками
      TracesInHeightBetweenSocketFloor := GetTraceInfoFromListByHorzHeight(FAllTracesInfo, 0, FSCSList.Setting.HeightSocket, false, false, LooadedTracesInfos);
      if TracesInHeightBetweenSocketFloor.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_7, ntTypeHeightBetweenSocketFloor, TracesInHeightBetweenSocketFloor, false);

      //*** Под потолком (высота размещения трасс = высота потолка)
      TracesInHeightCeiling := GetTraceInfoFromListByHorzHeight(FAllTracesInfo, FSCSList.Setting.HeightRoom, -1, false, false, LooadedTracesInfos);
      if TracesInHeightCeiling.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_8, ntTypeHeightCeiling, TracesInHeightCeiling, false);

      //*** трассы над фальш-потолком
      TracesInHeightFalseCeiling := GetTraceInfoFromListByHorzHeight(FAllTracesInfo,
                                            FSCSList.Setting.HeightRoom - FSCSList.Setting.HeightCeiling, FSCSList.Setting.HeightRoom, true, false, LooadedTracesInfos);
      if TracesInHeightFalseCeiling.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_9, ntTypeHeightFalseCeiling, TracesInHeightFalseCeiling, false);

      //*** трассы не попавшие в категории выше
      TracesInCategories := TList.Create;
      TracesInCategories.Assign(VerticalTraces, laOr);
      TracesInCategories.Assign(TracesInHeightTracing, laOr);
      TracesInCategories.Assign(TracesInHeightSocket, laOr);
      TracesInCategories.Assign(TracesInHeightFloor, laOr);
      TracesInCategories.Assign(TracesInHeightBetweenSocketFloor, laOr);
      TracesInCategories.Assign(TracesInHeightCeiling, laOr);
      TracesInCategories.Assign(TracesInHeightFalseCeiling, laOr);

      TracesInHeightNoCategory := GetTraceInfoNoHitToListByFigureID(FAllTracesInfo, TracesInCategories);
      if TracesInHeightNoCategory.Count > 0 then
        AddTraceInfoAsGroupToTreeView(tvDefineTrace, GrpHorzNode, cMasterCableCanalTracing_Msg19_10, ntTypeNoCategory, TracesInHeightNoCategory, false);

      TraceTypes.Expanded := true;
      GrpHorzNode.Expanded := true;
    finally
      tvDefineTrace.OnStateChanged := SavedOnStateChange;

      LooadedTracesInfos.Free;
      TracesInCategories.Free;

      FreeList(VerticalTraces);
      FreeList(TracesInHeightTracing);
      FreeList(TracesInHeightSocket);
      FreeList(TracesInHeightFloor);
      FreeList(TracesInHeightBetweenSocketFloor);
      FreeList(TracesInHeightCeiling);
      FreeList(TracesInHeightFalseCeiling);
      FreeList(TracesInHeightNoCategory);
    end;
  end;

  FActiveTreeView := tvDefineTrace;
  pcTrees.ActivePage := tsDefineTrace;
  AfterChangeActiveTreeView;

  //SetControls;
end;

procedure TF_MasterCableCanalTracing.cbUseOneCanalForAllClick(
  Sender: TObject);
begin
  SetControls;
end;

procedure TF_MasterCableCanalTracing.FormCreate(Sender: TObject);
var
  CurrTreeView: TFlyTreeViewPro;
  i: Integer;

  Icon: TIcon;

  TreeCollection: TTreeCollectionClass;
  TreeCollectionClassName: String;
  NewSectionNode: TFlyNode;
begin
  // Tolik 01/11/2019 --
  seComponCountToTrace.Max := 1000;
  seScaleStep.Max := 10000;
  //
  FLastGroupNode := nil;

  pnOkCancelResize(pnOkCancel);

  ImageList_FlyTree.AddImages(TF_Main(GForm).DM.ImageList_FlyTree);

  FtiiSCSLineGroup := 0;
  FtiiSCSLineNormal := 0;
  Icon := TIcon.Create;
  TF_Main(GForm).DM.ImageList_Dir.GetIcon(tciiSCSLineGroup, Icon);
  FtiiSCSLineGroup := ImageList_FlyTree.AddIcon(Icon);
  TF_Main(GForm).DM.ImageList_Dir.GetIcon(tciiSCSLineNorm, Icon);
  FtiiSCSLineNormal := ImageList_FlyTree.AddIcon(Icon);
  FreeAndNil(Icon);

  //tvAllTraces.Images := TF_Main(GForm).DM.ImageList_Dir;
  //tvSelectedTraces.Images := TF_Main(GForm).DM.ImageList_Dir;
  //tvDefineTrace.Images := TF_Main(GForm).DM.ImageList_Dir;

  FtvList := TObjectList.Create(false);
  FtvList.Add(tvAllTraces);
  FtvList.Add(tvSelectedTraces);
  FtvList.Add(tvDefineTrace);
  FtvList.Add(tvTraceScaleGrops);
  for i := 0 to FtvList.Count - 1 do
  begin
    CurrTreeView := TFlyTreeViewPro(FtvList[i]);

    CurrTreeView.Images.Clear;
    //CurrTreeView.Images.AddImages(TF_Main(GForm).DM.ImageList_FlyTree);
    CurrTreeView.Images.AddImages(ImageList_FlyTree);
    CurrTreeView.ButtonCollapsedIndex := tbiCollapsed;
    CurrTreeView.ButtonCheckedIndex := tbiChecked;
    CurrTreeView.ButtonExpandedIndex := tbiExpanded;
    CurrTreeView.ButtonGrayedIndex := tbiGrayed;
    CurrTreeView.ButtonUnCheckedIndex := tbiUnchecked;

    CurrTreeView.ClickableColumns := false;
    CurrTreeView.DefaultRowHeight := 17;
    CurrTreeView.FixedColAsButton := true;
    CurrTreeView.Indent := 17;
    CurrTreeView.Options := CurrTreeView.Options + [goColSizing] - [goHorzLine, goVertLine];
    CurrTreeView.RightClickSelect := true;
    CurrTreeView.SelectedBackgroundColor := tvclSelBackColorUnFocused;
    CurrTreeView.SelectedTextColor := tvclSelTextColorUnFocused;
    CurrTreeView.ShowHint := true;
    CurrTreeView.ShowImages := true;
    CurrTreeView.ShowLogic := true;
    CurrTreeView.StatesDrawed := false;
    //CurrTreeView.ToolTips := true;
    //CurrTreeView.TransparentMode := true;
    //CurrTreeView.Options := CurrTreeView.Options + [goRowSelect];
    CurrTreeView.ToolTips := true;

    CurrTreeView.Columns[ciTraces].Width := 270;
    CurrTreeView.Columns[ciTraces].Caption := cMasterCableCanalTracing_Msg22_5;

    // количество
    TreeCollection := CurrTreeView.Columns.Add(cMasterCableCanalTracing_Msg22_2, TreeCollectionClassName);
    // Прокладываемый компонент
    TreeCollection := CurrTreeView.Columns.Add(cMasterCableCanalTracing_Msg22_1, TreeCollectionClassName);
    // Толщина кабелей
    TreeCollection := CurrTreeView.Columns.Add(cMasterCableCanalTracing_Msg22_6, TreeCollectionClassName);
    // Сечение канала
    TreeCollection := CurrTreeView.Columns.Add(cMasterCableCanalTracing_Msg22_7, TreeCollectionClassName);

    CurrTreeView.Columns[ciComponent].Width := 150;
    CurrTreeView.Columns[ciKolvo].Width := 65;
    CurrTreeView.Columns[ciCablesTotalSection].Width := 65;
    CurrTreeView.Columns[ciChannelSection].Width := 95;
  end;
end;

procedure TF_MasterCableCanalTracing.NBTree_CatalogChange(Sender: TObject; Node: TTreeNode);
{var
  CanAddComponent: Boolean;
  NodeInfo: PNodeInfo;
  ComponVolume: Double;}
begin
  if Assigned(FSavedNBTreeCatalogChange) then
  begin
    TF_Main(FNormBase).Timer_TreeCatalogChangeTimer(TF_Main(FNormBase).Timer_TreeCatalogChange);
    //FSavedNBTreeCatalogChange(Sender, Node);
    //Sleep(TF_Main(FNormBase).Timer_TreeCatalogChange.Interval+1);
    //Application.ProcessMessages;
  end;

  AfterChangeNBCompon;
  {//22.05.2009
  pnCableChannelInfo.Visible := false;

  CanAddComponent := false;
  if TF_Main(FNormBase).GSCSBase.SCSComponent.ID <> 0 then
    if FComponentTypeSysNames.IndexOf(TF_Main(FNormBase).GSCSBase.SCSComponent.ComponentType.SysName) <> -1 then
      if FActiveTreeView <> nil then
        if FActiveTreeView.Selected <> nil then
        begin
          NodeInfo := FActiveTreeView.Selected.Data;
          if NodeInfo.NodeType = ntTrace then
            CanAddComponent := true
          else
            if HaveNodeChildByNodeType(FActiveTreeView.Selected, ntTrace) and cbAddComponentToChildNodes.Checked then
              CanAddComponent := true;

          if CheckSysNameIsCableChannel(FComponentTypeSysName) then
          begin
            pnCableChannelInfo.Visible := true;

            //lbComponVolume.Caption := FloatToStr(RoundCP(TF_Main(FNormBase).GSCSBase.SCSComponent.GetVolume(gtFemale)))+' '+cNameSantim2;
            ComponVolume := TF_Main(FNormBase).GSCSBase.SCSComponent.GetVolume(gtFemale);
            lbComponVolume.Caption := FloatToStr(RoundCP(FloatInUOM(ComponVolume, umSM, FUOMMin, 2)))+' '+GetNameUOMMin2;
          end;
        end;
  btSetNBComponentToNodeInfo.Enabled := CanAddComponent;}
end;

procedure TF_MasterCableCanalTracing.NBlvTemplatesSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
begin
  if Assigned(FSavedNBlvTemplatesSelectItem) then
    FSavedNBlvTemplatesSelectItem(Sender, Item, Selected);

  AfterChangeNBCompon;
end;

procedure TF_MasterCableCanalTracing.NBpcObjectsChange(Sender: TObject);
begin
  if Assigned(FSavedNBpcObjectsChange) then
  begin
    FSavedNBpcObjectsChange(Sender);
    //Application.ProcessMessages;
    if TF_Main(FNormBase).Timer_TreeCatalogChange.Enabled then
      TF_Main(FNormBase).Timer_TreeCatalogChangeTimer(TF_Main(FNormBase).Timer_TreeCatalogChange);
  end;

  AfterChangeNBCompon;
end;

procedure TF_MasterCableCanalTracing.NBtvComponGroupsChange(Sender: TObject; Node: TFlyNode);
begin
  if Assigned(FSavedNBtvComponGroupsChange) then
    FSavedNBtvComponGroupsChange(Sender, Node);
  AfterChangeNBCompon;
end;

procedure TF_MasterCableCanalTracing.AfterChangeNBCompon;
var
  CanAddComponent: Boolean;
  NodeInfo: PNodeInfo;
  ComponVolume: Double;
begin
  pnCableChannelInfo.Visible := false;

  CanAddComponent := false;
  if TF_Main(FNormBase).GSCSBase.SCSComponent.ID <> 0 then
    if FComponentTypeSysNames.IndexOf(TF_Main(FNormBase).GSCSBase.SCSComponent.ComponentType.SysName) <> -1 then
      if FActiveTreeView <> nil then
        if FActiveTreeView.Selected <> nil then
        begin
          NodeInfo := FActiveTreeView.Selected.Data;
          if NodeInfo.NodeType = ntTrace then
            CanAddComponent := true
          else
            if HaveNodeChildByNodeType(FActiveTreeView.Selected, ntTrace) and cbAddComponentToChildNodes.Checked then
              CanAddComponent := true;

          if CheckSysNameIsCableChannel(FComponentTypeSysName) then
          begin
            pnCableChannelInfo.Visible := true;

            //lbComponVolume.Caption := FloatToStr(RoundCP(TF_Main(FNormBase).GSCSBase.SCSComponent.GetVolume(gtFemale)))+' '+cNameSantim2;
            ComponVolume := TF_Main(FNormBase).GSCSBase.SCSComponent.GetVolume(gtFemale);
            lbComponVolume.Caption := FloatToStr(RoundCP(FloatInUOM(ComponVolume, umSM, FUOMMin, 2)))+' '+GetNameUOMMin2;
          end;
        end;
  btSetNBComponentToNodeInfo.Enabled := CanAddComponent;
end;

procedure TF_MasterCableCanalTracing.btSetNBComponentToNodeInfoClick(
  Sender: TObject);
var
  IDComponent: Integer;
  NameComponent: string;
  ComponCount: Integer;
  ChannelSection: Double;

  FocusedTreeView: TFlyTreeViewPro;
  ParallelTreeView: TFlyTreeViewPro;

  SelectedNode: TFlyNode;
begin
  IDComponent := 0;
  NameComponent := '';
  ChannelSection := 0;
  if TF_Main(FNormBase).GSCSBase.SCSComponent.ID > 0 then
    if FComponentTypeSysNames.IndexOf(TF_Main(FNormBase).GSCSBase.SCSComponent.ComponentType.SysName) <> -1 then
    begin
      IDComponent := TF_Main(FNormBase).GSCSBase.SCSComponent.ID;
      NameComponent := TF_Main(FNormBase).GSCSBase.SCSComponent.Name;
      if CheckSysNameIsCableChannel(FComponentTypeSysName) then
        ChannelSection := TF_Main(FNormBase).GSCSBase.SCSComponent.GetVolume(gtFemale);
    end;

  ComponCount := 1;
  if seComponCountToTrace.Value > 0 then
    ComponCount := Round(seComponCountToTrace.Value);

  //if IDComponent > 0 then
  //  if FActiveTreeView <> nil then
  //    if FActiveTreeView.Selected <> nil then
  //      AddIDComponentAndCountToTreeNodes(IDComponent, ComponCount, NameComponent, FActiveTreeView.Selected, cbAddComponentToChildNodes.Checked);

  if IDComponent > 0 then
  begin
    FocusedTreeView := FActiveTreeView;
    ParallelTreeView := nil;
    if CheckSysNameIsCableChannel(FComponentTypeSysName) then
    begin
      ParallelTreeView := tvTraceScaleGrops;
      if (tvTraceScaleGrops = FFocusedTreeView) and
         (tvTraceScaleGrops.Selected <> nil) then
      begin
        FocusedTreeView := tvTraceScaleGrops;
        ParallelTreeView := FActiveTreeView;
      end;
    end;

    if FocusedTreeView <> nil then
      if FocusedTreeView.Selected <> nil then
      begin
        SelectedNode := FocusedTreeView.Items.GetFirstSelectedNode;
        while SelectedNode <> nil do
        begin
          AddIDComponentAndCountToTreeNodes(IDComponent, ComponCount, NameComponent, ChannelSection, SelectedNode, cbAddComponentToChildNodes.Checked);
          SelectedNode := FocusedTreeView.Items.GetNextSelectedNode(SelectedNode);
        end;
        //AddIDComponentAndCountToTreeNodes(IDComponent, ComponCount, NameComponent, FocusedTreeView.Selected, cbAddComponentToChildNodes.Checked);
        if ParallelTreeView <> nil then
          RefreshNodesData(ParallelTreeView, FocusedTreeView.Selected);
      end;
  end;
end;


procedure TF_MasterCableCanalTracing.cbAddComponentToChildNodesClick(
  Sender: TObject);
begin
  NBTree_CatalogChange(TF_Main(FNormBase).Tree_Catalog, TF_Main(FNormBase).Tree_Catalog.Selected);
end;

procedure TF_MasterCableCanalTracing.btBackClick(Sender: TObject);
begin
  StepIndex(false);
end;

procedure TF_MasterCableCanalTracing.btOkClick(Sender: TObject);
var
  TopNode: TFlyNode;
begin
  ModalResult := mrNone;
  case FStepIndex of
    0:
      begin
        if cbUseComponentAsDefault.Checked then
          if lvComponents.Selected <> nil then
          begin
            FIDComponentForAll := Integer(lvComponents.Selected.Data);
            DefineComponVolumeForAll;
            FNameComponentForAll := lvComponents.Selected.Caption;

            TopNode := GetTreeViewFirstNode(tvAllTraces);
            if TopNode <> nil then
              AddIDComponentAndCountToTreeNodes(FIDComponentForAll, 0, FNameComponentForAll, FVolumeComponentForAll, TopNode, true);
            TopNode := GetTreeViewFirstNode(tvSelectedTraces);
            if TopNode <> nil then
              AddIDComponentAndCountToTreeNodes(FIDComponentForAll, 0, FNameComponentForAll, FVolumeComponentForAll, TopNode, true);
            TopNode := GetTreeViewFirstNode(tvDefineTrace);
            if TopNode <> nil then
              AddIDComponentAndCountToTreeNodes(FIDComponentForAll, 0, FNameComponentForAll, FVolumeComponentForAll, TopNode, true);
          end
          else
          begin
            if CheckSysNameIsCableChannel(FComponentTypeSysName) then
              MessageModal(cMasterCableCanalTracing_Msg20, ApplicationName, MB_ICONINFORMATION or MB_OK)
            else
              MessageModal(cMasterCableCanalTracing_Msg21, ApplicationName, MB_ICONINFORMATION or MB_OK);
            Exit; ///// EXIT /////
          end;
        StepIndex(True);
      end;
    1:
      begin
        if TraceComponentsFromTree(FActiveTreeView) then
          ModalResult := mrOk;
      end;
  end;
  // Tolik 13/06/2017 --
  if cbSelectInPM.Checked then
    SelectTracesInCADFromNode(nil); //17.01.2011 - снимаем выделение
  //
end;

procedure TF_MasterCableCanalTracing.pnOkCancelResize(Sender: TObject);
begin
  SetMiddleControlChilds(TControl(Sender), Self);
end;

procedure TF_MasterCableCanalTracing.lvComponentsSelectItem(
  Sender: TObject; Item: TListItem; Selected: Boolean);
var
  IDCanal: Integer;
begin
  if Selected then
  begin
    IDCanal := Integer(Item.Data);
    SelectComponentInNB(IDCanal);
  end;
end;

procedure TF_MasterCableCanalTracing.cbSelectInPMClick(Sender: TObject);
begin
  if cbSelectInPM.Checked then
    tvDefineTraceChange(FActiveTreeView, FActiveTreeView.Selected)
  else
  begin
    SelectTracesInCADFromNode(nil); //17.01.2011 - снимаем выделение
  end;
end;

procedure TF_MasterCableCanalTracing.seComponCountToTraceKeyPress(
  Sender: TObject; var Key: Char);
begin
  if Key = '-' then
    Key := #0;
end;

procedure TF_MasterCableCanalTracing.seScaleStepChange(Sender: TObject);
begin
  if FLastGroupNode <> nil then
    LoadTraceScaleGropsToTreeFromNode(FLastGroupNode);
end;

procedure TF_MasterCableCanalTracing.tvDefineTraceChange(Sender: TObject;
  Node: TFlyNode);
var
  //NodeInfo: PNodeInfo;
  //PMTraceNode: TTreeNode;
  GroupNode: TFlyNode;
begin
  if Node <> nil then
    if Node.Data <> nil then
    begin
      ApplyNodeSelection(Node);
      {
      NodeInfo := Node.Data;

      if Sender = FActiveTreeView then
        SelectComponentFromNode(Node);

      if NodeInfo.NodeType = ntTrace then
      begin
        if cbSelectInPM.Checked then
        begin
          PMTraceNode := TF_Main(GForm).FindComponOrDirInTree(NodeInfo.IDTrace, false);
          if PMTraceNode <> nil then
            TF_Main(GForm).Tree_Catalog.Selected := PMTraceNode;
        end;
      end;

      if cbSelectInPM.Checked then
        SelectTracesInCADFromNode(Node);
      RefreshSelectedInNB; //22.05.2009 NBTree_CatalogChange(TF_Main(FNormBase).Tree_Catalog, TF_Main(FNormBase).Tree_Catalog.Selected);}

      GroupNode := GetGroupNodeByNode(Node);
      if GroupNode <> nil then
        if GroupNode <> FLastGroupNode then
        begin
          FLastGroupNode := GroupNode;
          LoadTraceScaleGropsToTreeFromNode(GroupNode);
        end;
    end;
end;

procedure TF_MasterCableCanalTracing.Button1Click(Sender: TObject);
var
  rzTree: TRzCheckTree;
  //ImgList: TImageList;
  i: integer;
  Bitmap: TBitMap;
begin
  rzTree := TRzCheckTree.Create(Self);
  //ImgList := rzTree.StateImages;
  //ImgList.co
  if rzTree.StateImages <> nil then
    for i := 0 to rzTree.StateImages.Count - 1 do
    begin
      Bitmap := TBitMap.Create;
      if rzTree.StateImages.GetBitmap(i, Bitmap) then
      begin
        Bitmap.SaveToFile('c:\temp\raizebtn\img'+IntToStr(i)+'.bmp');
      end;
      FreeAndNil(Bitmap);
    end;
end;

procedure TF_MasterCableCanalTracing.tvDefineTraceGetNodeAttributes(
  Node: TFlyNode; Column: Integer; aFont: TFont; var BackColor: TColor;
  var Alignment: TAlignment);
var
  ActualColumn: integer;
begin
  if Node <> nil then
  begin
    ActualColumn := TFlyTreeViewPro(Node.Tree).GetColumnOrder(Column); //TFlyTreeViewPro(Node.Tree).Columns.VisibleColumn[Column].Index;
    if ActualColumn = ciKolvo then
      aFont.Color:=clblue;
  end;
end;

procedure TF_MasterCableCanalTracing.tvDefineTraceStateChange(
  Node: TFlyNode; Oldindex: Integer);
begin
  if CheckSysNameIsCableChannel(FComponentTypeSysName) then
    RefreshNodesData(tvTraceScaleGrops, Node);

  //SelectTracesInCADFromNode(TFlyTreeViewPro(Node.Tree).Selected); //17.01.2011 - обновить подсветку на листе
  FNodeToSelInCAD := TFlyTreeViewPro(Node.Tree).Selected;
  Timer_SelectTracesInCAD.Enabled := false;
  Timer_SelectTracesInCAD.Enabled := true;
end;

procedure TF_MasterCableCanalTracing.tvTraceScaleGropsStateChange(
  Node: TFlyNode; Oldindex: Integer);
begin
  if CheckSysNameIsCableChannel(FComponentTypeSysName) then
    RefreshNodesData(FActiveTreeView, Node);
end;

procedure TF_MasterCableCanalTracing.tvTraceScaleGropsChange(
  Sender: TObject; Node: TFlyNode);
begin
  if Node <> nil then
    ApplyNodeSelection(Node);
end;

procedure TF_MasterCableCanalTracing.Act_DropComponFromMainTreeExecute(
  Sender: TObject);
begin
  if FActiveTreeView <> nil then
    DropComponFromTraceNode(FActiveTreeView.Selected, tvTraceScaleGrops);
end;
                                            
procedure TF_MasterCableCanalTracing.Act_DropComponFromScaleTreeExecute(
  Sender: TObject);
begin
  if FActiveTreeView <> nil then
    DropComponFromTraceNode(tvTraceScaleGrops.Selected, FActiveTreeView);
end;


procedure TF_MasterCableCanalTracing.Act_SelectTraceFromMainToScaleTreeExecute(
  Sender: TObject);
begin
  if FActiveTreeView <> nil then
    SelectTraceNodeByNodeFromOtherTree(FActiveTreeView.Selected, tvTraceScaleGrops);
end;

procedure TF_MasterCableCanalTracing.Act_SelectTraceFromScaleToMainTreeExecute(
  Sender: TObject);
begin
  if FActiveTreeView <> nil then
    SelectTraceNodeByNodeFromOtherTree(tvTraceScaleGrops.Selected, FActiveTreeView);
end;

procedure TF_MasterCableCanalTracing.tvDefineTraceEnter(Sender: TObject);
begin
  if FFocusedTreeView <> nil then //25.03.2009
  begin
    FFocusedTreeView.SelectedBackgroundColor := tvclSelBackColorUnFocused;
    FFocusedTreeView.SelectedTextColor := tvclSelTextColorUnFocused;
  end; //25.03.2009

  FFocusedTreeView := TFlyTreeViewPro(Sender);
  TFlyTreeViewPro(Sender).SelectedBackgroundColor := tvclSelBackColorFocused;
  TFlyTreeViewPro(Sender).SelectedTextColor := tvclSelTextColorFocused;
end;

procedure TF_MasterCableCanalTracing.tvDefineTraceExit(Sender: TObject);
begin
  //25.03.2009 TFlyTreeViewPro(Sender).SelectedBackgroundColor := tvclSelBackColorUnFocused;
  //25.03.2009 TFlyTreeViewPro(Sender).SelectedTextColor := tvclSelTextColorUnFocused;

  if tvTraceScaleGrops.Showing then
  begin
    TFlyTreeViewPro(Sender).SelectedBackgroundColor := tvclSelBackColorHalfUnFocused;
    TFlyTreeViewPro(Sender).SelectedTextColor := tvclSelTextColorHalfUnFocused;
  end
  else
  begin
    TFlyTreeViewPro(Sender).SelectedBackgroundColor := tvclSelBackColorUnFocused;
    TFlyTreeViewPro(Sender).SelectedTextColor := tvclSelTextColorUnFocused;
  end;
end;

procedure TF_MasterCableCanalTracing.tvTraceScaleGropsMouseUp(
  Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  NodeAtCursor: TFlyNode;
  ClientPos: TPoint;
  ScrPos: TPoint;
begin
  if Button = mbRight then
  begin
    {NodeAtCursor := TFlyTreeViewPro(Sender).GetNodeAt(X, Y);
    if NodeAtCursor <> nil then
    begin
      TFlyTreeViewPro(Sender).Selected := NodeAtCursor;
      Application.ProcessMessages;
    end;

    //if TFlyTreeViewPro(Sender).PopupMenu <> nil then
    //  TFlyTreeViewPro(Sender).PopupMenu.Popup(X, Y);

    ClientPos.X := X;
    ClientPos.Y := Y;
    ScrPos := TFlyTreeViewPro(Sender).ClientToScreen(ClientPos);
    if TFlyTreeViewPro(Sender) = FActiveTreeView then
      pmTreeMain.Popup(ScrPos.X, ScrPos.Y)
    else
    if TFlyTreeViewPro(Sender) = tvTraceScaleGrops then
      pmTreeMain.Popup(ScrPos.X, ScrPos.Y);}
  end;
end;

procedure TF_MasterCableCanalTracing.pmTreeMainPopup(Sender: TObject);
begin
  EnableDisableActions;
end;

procedure TF_MasterCableCanalTracing.pmTreeScalePopup(Sender: TObject);
begin
  EnableDisableActions;
end;

procedure TF_MasterCableCanalTracing.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FtvList);
end;

procedure TF_MasterCableCanalTracing.FormActivate(Sender: TObject);
begin
  if F_Progress.Visible then
  begin
    EmptyProcedure;
  end;
end;

procedure TF_MasterCableCanalTracing.Timer_SelectTracesInCADTimer(
  Sender: TObject);
begin
  TTimer(Sender).Enabled := false;
  SelectTracesInCADFromNode(FNodeToSelInCAD); //17.01.2011 - обновить подсветку на листе
end;
//Tolik 13/06/2017 -- снимаем выделение в случае отмены мастера, а то трассы останутся подкрашенными
procedure TF_MasterCableCanalTracing.btCancelClick(Sender: TObject);
begin
  SelectTracesInCADFromNode(nil); //17.01.2011 - снимаем выделение
end;

end.

