unit U_CadNormsList;

interface

uses
  Windows, U_LNG, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, RzGrids, U_ESCadClasess, cxLookAndFeelPainters, StdCtrls,
  cxButtons, Contnrs, U_SCSComponent, Menus, siComp, siLngLnk, Buttons,
  U_Common_Classes, ComCtrls, ToolWin, cxGraphics, cxLookAndFeels;

type
  TSelectedRow = class(TObject)
  public
    FSelected: Boolean;
  end;


type
  TF_CadNormsList = class(TForm)
    slNorms: TRzStringGrid;
    bOK: TcxButton;
    bCancel: TcxButton;
    pmNorms: TPopupMenu;
    nAddRow: TMenuItem;
    nAddColumn: TMenuItem;
    nDeleteRow: TMenuItem;
    nDeleteColumn: TMenuItem;
    lng_Forms: TsiLangLinked;
    tbButtons: TToolBar;
    tbUp: TToolButton;
    tbDown: TToolButton;
    nMarkForJoin: TMenuItem;
    ToolButton1: TToolButton;
    tbJoin: TToolButton;
    tbLeft: TToolButton;
    tbRight: TToolButton;
    ToolButton4: TToolButton;
    procedure bCancelClick(Sender: TObject);
    procedure slNormsSetEditText(Sender: TObject; ACol, ARow: Integer;
      const Value: String);
    procedure nAddRowClick(Sender: TObject);
    procedure nAddColumnClick(Sender: TObject);
    procedure nDeleteRowClick(Sender: TObject);
    procedure nDeleteColumnClick(Sender: TObject);
    procedure pmNormsPopup(Sender: TObject);
    procedure slNormsMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure tbUpClick(Sender: TObject);
    procedure tbDownClick(Sender: TObject);
    procedure nMarkForJoinClick(Sender: TObject);
    procedure slNormsDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure tbJoinClick(Sender: TObject);
    procedure bOKClick(Sender: TObject);
    procedure tbLeftClick(Sender: TObject);
    procedure tbRightClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FEdited: Boolean;
    FEditedNormStruct: TCadNormStruct;
    Procedure LoadTable(aCadNormsObject: TCadNorms);
    Function SaveTable(aNormsList: TObjectList): TObjectList;
    Function Execute(aCadNormsObject: TCadNorms): Boolean;
    Procedure UnSelectAllRows;
    function CheckStrExist(aCol, aRow: Integer; aStr: string): Boolean; 
  end;

var
  F_CadNormsList: TF_CadNormsList;

implementation
uses U_BaseCommon, U_Common, USCS_Main, U_Constants;

{$R *.dfm}

{ TF_CadNormsList }

function TF_CadNormsList.Execute(aCadNormsObject: TCadNorms): Boolean;
var
  i, j: integer;
  SelRowObject: TSelectedRow;
begin
  try
    Result := False;
    FEdited := False;
    // почистить
    for i := 0 to slNorms.ColCount - 1 do
      for j := 0 to slNorms.RowCount - 1 do
        slNorms.Cells[i, j] := '';
    LoadTable(aCadNormsObject);
    // Selected
    for i := 0 to slNorms.RowCount - 1 do
    begin
      SelRowObject := TSelectedRow.Create;      
      SelRowObject.FSelected := False;
      slNorms.Objects[0, i] := SelRowObject;
    end;

    if ShowModal = mrOK then
    begin
      // было редактирование
      if FEdited then
      begin
        aCadNormsObject.FNormsList := SaveTable(aCadNormsObject.FNormsList);
        Result := True;        
      end;
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.Execute', E.Message);
  end;
end;

procedure TF_CadNormsList.LoadTable(aCadNormsObject: TCadNorms);
var
  i, j, k: Integer;
  Pos: Integer;
  Count: Integer;
  CadNormStruct: TCadNormStruct;
  CadNormColumn: TCadNormColumn;
  StrField: string;
begin
  try
    slNorms.RowHeights[0] := 10;
    slNorms.RowCount := aCadNormsObject.FNormsList.Count + 1;
    Count := 4;
    if aCadNormsObject.FNormsList.Count = 0 then
      Exit;
    CadNormStruct := TCadNormStruct(aCadNormsObject.FNormsList[0]);
    FEditedNormStruct := CadNormStruct;
    for i := 0 to CadNormStruct.NormColumns.Count - 1 do
    begin
      CadNormColumn := TCadNormColumn(CadNormStruct.NormColumns[i]);
      Count := Count + CadNormColumn.Columns.Count;
    end;
    slNorms.ColCount := Count;

    slNorms.ColWidths[0] := Round(aCadNormsObject.fNumberSize) * 5;
    slNorms.ColWidths[1] := Round(aCadNormsObject.fNameSize) * 5;
    slNorms.ColWidths[2] := Round(aCadNormsObject.fIzmSize) * 5;
    slNorms.ColWidths[3] := Round(aCadNormsObject.fCountSize) * 5;
    for i := 4 to slNorms.ColCount - 1 do
      slNorms.ColWidths[i] := Round(aCadNormsObject.fColumnSize) * 5;
    // основные поля
    StrField := CadNormStruct.Number;
    slNorms.Cells[0, 1] := StrField;
    StrField := CadNormStruct.Name;
    slNorms.Cells[1, 1] := StrField;
    StrField := CadNormStruct.Izm;
    slNorms.Cells[2, 1] := StrField;
    StrField := CadNormStruct.Count;
    slNorms.Cells[3, 1] := StrField;
    // поля колонок
    Pos := 4;
    for i := 0 to CadNormStruct.NormColumns.Count - 1 do
    begin
      CadNormColumn := TCadNormColumn(CadNormStruct.NormColumns[i]);
      for j := 0 to CadNormColumn.Columns.Count - 1 do
      begin
        StrField := CadNormColumn.Columns[j];
        slNorms.Cells[Pos, 1] := StrField;
        Pos := Pos + 1;
      end;
    end;

    // все остальные поля
    for i := 1 to aCadNormsObject.FNormsList.Count - 1 do
    begin
      CadNormStruct := TCadNormStruct(aCadNormsObject.FNormsList[i]);
      // основные поля
      StrField := CadNormStruct.Number;
      slNorms.Cells[0, i + 1] := StrField;
      StrField := CadNormStruct.Name;
      slNorms.Cells[1, i + 1] := StrField;
      StrField := CadNormStruct.Izm;
      slNorms.Cells[2, i + 1] := StrField;
      StrField := CadNormStruct.Count;
      slNorms.Cells[3, i + 1] := StrField;
      Pos := 4;
      for j := 0 to CadNormStruct.NormColumns.Count - 1 do
      begin
        CadNormColumn := TCadNormColumn(CadNormStruct.NormColumns[j]);
        for k := 0 to CadNormColumn.Columns.Count - 1 do
        begin
          StrField := CadNormColumn.Columns[k];
          slNorms.Cells[Pos, i + 1] := StrField;
          Pos := Pos + 1;
        end;
      end;
    end;

  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.LoadTable', E.Message);
  end;
end;

function TF_CadNormsList.SaveTable(aNormsList: TObjectList): TObjectList;
var
  i, j, k, ColPos: Integer;
  StrField: string;
  CadNormStruct: TCadNormStruct;
  CadNormColumn: TCadNormColumn;
  OldCadNormStruct: TCadNormStruct;
  OldCadNormColumn: TCadNormColumn;
begin
  try
    Result := TObjectList.Create;
    if FEditedNormStruct = nil then
      FEditedNormStruct := TCADNormStruct.Create;
    for i := 1 to slNorms.RowCount - 1 do
    begin
      OldCadNormStruct := FEditedNormStruct;
      CadNormStruct := TCADNormStruct.Create;
      CadNormStruct.Number := slNorms.Cells[0, i];
      CadNormStruct.Name := slNorms.Cells[1, i];
      CadNormStruct.Izm := slNorms.Cells[2, i];
      CadNormStruct.Count := slNorms.Cells[3, i];
      CadNormStruct.NormColumns := TObjectList.Create;

      ColPos := 4;

      for j := 0 to OldCadNormStruct.NormColumns.Count - 1 do
      begin
        OldCadNormColumn := TCadNormColumn(OldCadNormStruct.NormColumns[j]);
        CadNormColumn := TCADNormColumn.Create;
        CadNormColumn.CableName := OldCadNormColumn.CableName;
        CadNormColumn.Columns := TStringList.Create;
        for k := 0 to OldCadNormColumn.Columns.Count - 1 do
        begin
          CadNormColumn.Columns.Add(slNorms.Cells[ColPos, i]);
          ColPos := ColPos + 1;
        end;
        CadNormStruct.NormColumns.Add(CadNormColumn);
      end;
      // если были добавлены колонки - докинуть в структуру
      if ColPos < slNorms.ColCount then
      begin
        CadNormColumn := TCADNormColumn.Create;
        CadNormColumn.CableName := cCadNormsList_Mes1;
        CadNormColumn.Columns := TStringList.Create;
        for k := ColPos to slNorms.ColCount - 1 do
        begin
          CadNormColumn.Columns.Add(slNorms.Cells[k, i]);
        end;
        CadNormStruct.NormColumns.Add(CadNormColumn);
      end;

      Result.Add(CadNormStruct);
    end;
    aNormsList.Free;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.SaveTable', E.Message);
  end;
end;

procedure TF_CadNormsList.bCancelClick(Sender: TObject);
begin
  Close;
end;

procedure TF_CadNormsList.slNormsSetEditText(Sender: TObject; ACol,
  ARow: Integer; const Value: String);
begin
  FEdited := True;
end;

procedure TF_CadNormsList.nAddRowClick(Sender: TObject);
var
  i: integer;
  SelRowObject: TSelectedRow;
begin
  try
    slNorms.RowCount := slNorms.RowCount + 1;
    for i := 0 to slNorms.ColCount - 1 do
      slNorms.Cells[i, slNorms.RowCount - 1] := '';
    SelRowObject := TSelectedRow.Create;
    SelRowObject.FSelected := False;
    slNorms.Objects[0, slNorms.RowCount - 1] := SelRowObject;
    FEdited := True;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.nAddRowClick', E.Message);
  end;
end;

procedure TF_CadNormsList.nAddColumnClick(Sender: TObject);
var
  j: integer;
begin
  try
    slNorms.ColCount := slNorms.ColCount + 1;
    slNorms.Cells[slNorms.ColCount - 1, 0] := '';
    slNorms.Cells[slNorms.ColCount - 1, 1] := '';
    for j := 0 to slNorms.RowCount - 1 do
      slNorms.Cells[slNorms.ColCount - 1, j] := '';
    FEdited := True;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.nAddColumnClick', E.Message);
  end;
end;

procedure TF_CadNormsList.nDeleteRowClick(Sender: TObject);
var
  i: integer;
  vRow: Integer;
begin
  try
    vRow := slNorms.Row;
    for i := vRow to slNorms.RowCount - 2 do
    begin
      slNorms.Rows[i] := slNorms.Rows[i + 1];
    end;
    slNorms.RowCount := slNorms.RowCount - 1;
    FEdited := True;
    UnSelectAllRows;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.nDeleteRowClick', E.Message);
  end;
end;

procedure TF_CadNormsList.nDeleteColumnClick(Sender: TObject);
var
  i, j: integer;
  vCol: Integer;
  Pos: Integer;
  CadNormColumn: TCadNormColumn;
begin
  try
    vCol := slNorms.Col;
    for i := vCol to slNorms.ColCount - 2 do
    begin
      slNorms.Cols[i] := slNorms.Cols[i + 1];
    end;
    slNorms.ColCount := slNorms.ColCount - 1;
    FEdited := True;
    // убрать колонку с редактируемой структуры
    Pos := 4;
    for i := 0 to FEditedNormStruct.NormColumns.Count - 1 do
    begin
      CadNormColumn := TCadNormColumn(FEditedNormStruct.NormColumns[i]);
      for j := 0 to CadNormColumn.Columns.Count - 1 do
      begin
        if vCol = Pos then
        begin
          CadNormColumn.Columns.Delete(j);
          Pos := Pos + 1;
          Break;
        end
        else
          Pos := Pos + 1;
      end;
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.nDeleteColumnClick', E.Message);
  end;
end;

procedure TF_CadNormsList.pmNormsPopup(Sender: TObject);
begin
  try
    pmNorms.Items[0].Enabled := True;
    pmNorms.Items[1].Enabled := True;
    if (slNorms.Row >= 0) and (slNorms.Row <= 1) then
      pmNorms.Items[2].Enabled := False
    else
      pmNorms.Items[2].Enabled := True;
    if (slNorms.Col >= 0) and (slNorms.Col <= 3) then
      pmNorms.Items[3].Enabled := False
    else
      pmNorms.Items[3].Enabled := True;

    if slNorms.Row >= 2 then
    begin
      pmNorms.Items[4].Enabled := True;
      if TSelectedRow(slNorms.Objects[0, slNorms.Row]).FSelected then
        pmNorms.Items[4].Caption := cCadNormsList_Mes2
      else
        pmNorms.Items[4].Caption := cCadNormsList_Mes3;
    end
    else
      pmNorms.Items[4].Enabled := False;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.pmNormsPopup', E.Message);
  end;
end;

procedure TF_CadNormsList.slNormsMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  vCol, vRow: Integer;
begin
  try
    if Button = mbLeft then
    begin
      if ssShift in Shift then
      begin
        slNorms.MouseToCell(X, Y, vCol, vRow);
        if vRow >= 2 then
        begin
          TSelectedRow(slNorms.Objects[0, vRow]).FSelected := not TSelectedRow(slNorms.Objects[0, vRow]).FSelected;
          slNorms.Repaint;
        end;
      end;
    end
    else
    if Button = mbRight then
    begin
      slNorms.MouseToCell(X, Y, vCol, vRow);
      if vCol <> -1 then
        slNorms.Col := vCol;
      if vRow <> -1 then
        slNorms.Row := vRow;
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.slNormsMouseDown', E.Message);
  end;
end;

procedure TF_CadNormsList.tbUpClick(Sender: TObject);
var
  i, j: Integer;
  Row: Integer;
  PrevRow: Integer;
  RowList: TStringList;
  PrevRowList: TStringList;
  Str: string;
begin
  try
    Row := slNorms.Row;
    PrevRow := Row - 1;
    if Row >= 3 then
    begin
      RowList := TStringList.Create;
      PrevRowList := TStringList.Create;

      // Get
      for i := 0 to slNorms.ColCount - 1 do
      begin
        Str := slNorms.Cells[i, Row];
        RowList.Add(Str);
        Str := slNorms.Cells[i, PrevRow];
        PrevRowList.Add(Str);
      end;

      // Set
      for i := 1 to slNorms.ColCount - 1 do
      begin
        Str := RowList.Strings[i];
        slNorms.Cells[i, PrevRow] := Str;
        Str := PrevRowList.Strings[i];
        slNorms.Cells[i, Row] := Str;
      end;
      slNorms.Row := PrevRow;

      FEdited := True;

      FreeAndNil(RowList);
      FreeAndNil(PrevRowList);
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.tbUpClick', E.Message);
  end;
end;

procedure TF_CadNormsList.tbDownClick(Sender: TObject);
var
  i: Integer;
  Row: Integer;
  NextRow: Integer;
  RowList: TStringList;
  NextRowList: TStringList;
  Str: string;
begin
  try
    Row := slNorms.Row;
    NextRow := Row + 1;
    if (Row >= 2) and (Row <= slNorms.RowCount -2) then
    begin
      RowList := TStringList.Create;
      NextRowList := TStringList.Create;

      // Get
      for i := 0 to slNorms.ColCount - 1 do
      begin
        Str := slNorms.Cells[i, Row];
        RowList.Add(Str);
        Str := slNorms.Cells[i, NextRow];
        NextRowList.Add(Str);
      end;

      // Set
      for i := 1 to slNorms.ColCount - 1 do
      begin
        Str := RowList.Strings[i];
        slNorms.Cells[i, NextRow] := Str;
        Str := NextRowList.Strings[i];
        slNorms.Cells[i, Row] := Str;
      end;

      FEdited := True;
      slNorms.Row := NextRow;

      FreeAndNil(RowList);
      FreeAndNil(NextRowList);
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.tbDownClick', E.Message);
  end;
end;

procedure TF_CadNormsList.nMarkForJoinClick(Sender: TObject);
var
  vRow: Integer;
begin
  try
    vRow := slNorms.Row;
    if vRow >= 2 then
    begin
      TSelectedRow(slNorms.Objects[0, vRow]).FSelected := not TSelectedRow(slNorms.Objects[0, vRow]).FSelected;
      slNorms.Repaint;
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.nJoinRowsClick', E.Message);
  end;
end;

procedure TF_CadNormsList.UnSelectAllRows;
var
  i: Integer;
begin
  try
    for i := 0 to slNorms.RowCount - 1 do
      TSelectedRow(slNorms.Objects[0, i]).FSelected := False;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.UnSelectAllRows', E.Message);
  end;
end;

procedure TF_CadNormsList.slNormsDrawCell(Sender: TObject; ACol,
  ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
  try
    if ARow >= 2 then
    begin
      if TSelectedRow(slNorms.Objects[0, ARow]).FSelected then
      begin
        slNorms.Canvas.Brush.Style := bsClear;
        slNorms.Canvas.Pen.Color := clRed;
        slNorms.Canvas.Rectangle(Rect);
      end;
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.slNormsDrawCell', E.Message);
  end;
end;

procedure TF_CadNormsList.tbJoinClick(Sender: TObject);
var
  i, j, k: Integer;
  vRow: Integer;
  vCol: Integer;
  BaseRow: Integer;
  ServiceStr: string;
  Str: string;
begin
  try
    ServiceStr := '; ';
    // BaseRow
    for i := 2 to slNorms.RowCount - 1 do
    begin
      if TSelectedRow(slNorms.Objects[0, i]).FSelected then
      begin
        BaseRow := i;
        Break;
      end;
    end;

    vRow := i + 1;
    while vRow < slNorms.RowCount do
    begin
      if TSelectedRow(slNorms.Objects[0, vRow]).FSelected then
      begin
        // перебросить в базовую строку
        for vCol := 1 to slNorms.ColCount - 1 do
        begin
          Str := slNorms.Cells[vCol, vRow];
          if Str <> '' then
          begin
            if not CheckStrExist(vCol, BaseRow, Str) then
            begin
              if slNorms.Cells[vCol, BaseRow] = '' then
                slNorms.Cells[vCol, BaseRow] := Str
              else
                slNorms.Cells[vCol, BaseRow] := slNorms.Cells[vCol, BaseRow] + ServiceStr + Str;
            end;
          end;
        end;
        // удалить эту строку
        for k := vRow to slNorms.RowCount - 2 do
        begin
          slNorms.Rows[k] := slNorms.Rows[k + 1];
        end;
        slNorms.RowCount := slNorms.RowCount - 1;
      end
      else
        vRow := vRow + 1;
    end;
    FEdited := True;
    UnSelectAllRows;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.tbJoinClick', E.Message);
  end;
end;

function TF_CadNormsList.CheckStrExist(aCol, aRow: Integer; aStr: string): Boolean;
var
  RowStr: string;
begin
  try
    Result := False;
    RowStr := slNorms.Cells[aCol, aRow];
    if Pos(aStr, RowStr) > 0 then
      Result := True;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.CheckStrExist', E.Message);
  end;
end;

procedure TF_CadNormsList.bOKClick(Sender: TObject);
begin
  try
    if not GProjectChanged then // Tolik 28/08/2019 --
      SetProjectChanged(True);
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.bOKClick', E.Message);
  end;
end;

procedure TF_CadNormsList.tbLeftClick(Sender: TObject);
var
  i, j: Integer;
  Col: Integer;
  PrevCol: Integer;
  ColList: TStringList;
  PrevColList: TStringList;
  Str: string;
begin
  try
    Col := slNorms.Col;
    PrevCol := Col - 1;
    if Col >= 5 then
    begin
      ColList := TStringList.Create;
      PrevColList := TStringList.Create;

      // Get
      for i := 0 to slNorms.RowCount - 1 do
      begin
        Str := slNorms.Cells[Col, i];
        ColList.Add(Str);
        Str := slNorms.Cells[PrevCol, i];
        PrevColList.Add(Str);
      end;

      // Set
      for i := 1 to slNorms.RowCount - 1 do
      begin
        Str := ColList.Strings[i];
        slNorms.Cells[PrevCol, i] := Str;
        Str := PrevColList.Strings[i];
        slNorms.Cells[Col, i] := Str;
      end;
      slNorms.Col := PrevCol;

      FEdited := True;

      FreeAndNil(ColList);
      FreeAndNil(PrevColList);
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.tbLeftClick', E.Message);
  end;
end;

procedure TF_CadNormsList.tbRightClick(Sender: TObject);
var
  i: Integer;
  Col: Integer;
  NextCol: Integer;
  ColList: TStringList;
  NextColList: TStringList;
  Str: string;
begin
  try
    Col := slNorms.Col;
    NextCol := Col + 1;
    if (Col >= 4) and (Col <= slNorms.ColCount - 2) then
    begin
      ColList := TStringList.Create;
      NextColList := TStringList.Create;

      // Get
      for i := 0 to slNorms.RowCount - 1 do
      begin
        Str := slNorms.Cells[Col, i];
        ColList.Add(Str);
        Str := slNorms.Cells[NextCol, i];
        NextColList.Add(Str);
      end;

      // Set
      for i := 1 to slNorms.RowCount - 1 do
      begin
        Str := ColList.Strings[i];
        slNorms.Cells[NextCol, i] := Str;
        Str := NextColList.Strings[i];
        slNorms.Cells[Col, i] := Str;
      end;

      FEdited := True;
      slNorms.Col := NextCol;

      FreeAndNil(ColList);
      FreeAndNil(NextColList);
    end;
  except
    on E: Exception do AddExceptionToLogEx('TF_CadNormsList.tbDownClick', E.Message);
  end;
end;

end.
