unit BillsClipboard;

interface

uses
  BaseClipboard, Classes, BillsDm, ZhAPI, XmlDoc, XmlIntf, Windows, sdIDTree;

type
  TBillsBlockNode = class
  private
    FID: Integer;
    FParentID: Integer;
    FNextSiblingID: Integer;
    FCode: string;
    FB_Code: string;
    FName: string;
    FUnits: string;
    FPrice: Double;
    FOrgQuantity: Double;
    FOrgTotalPrice: Double;
    FMisQuantity: Double;
    FMisTotalPrice: Double;
    FOthQuantity: Double;
    FOthTotalPrice: Double;
    FQuantity: Double;
    FTotalPrice: Double;
    FCalcType: Integer;
    FDrawingCode: string;
    FAlias: string;
    FDgnQuantity1: Double;
    FDgnQuantity2: Double;
    FMemoStr: string;
    FDealCode: string;
    FDealCompany: string;
  public
    procedure SaveToXmlNode(AXmlNode: IXMLNode);
    procedure LoadFromXmlNode(AXmlNode: IXMLNode);
  end;

  TBillsClipboard = class(TBaseClipboard)
  private
    FBillsData: TBillsData;
    FNodeList: TList;

    procedure SaveNodesToXml(AXmlNode: IXMLNode);
    procedure LoadNodesFromXml(AXmlNode: IXMLNode);

    procedure CopyBillsNodeData(ANode: TsdIDTreeNode);
    procedure CopyBillsNode(ANode: TsdIDTreeNode);
    procedure CopyData(ANode: TsdIDTreeNode; ACount: Integer);

    function AddBillsNode(ANode: TsdIDTreeNode; APos: Integer): TsdIDTreeNode;
    procedure PasteBillsNodeData(ANode: TsdIDTreeNode; APasteNode: TBillsBlockNode);
    procedure PasteChildren(AParentNode: TsdIDTreeNode; APasteParentID: Integer);
    procedure PasteNextSibling(APreSibling: TsdIDTreeNode; APasteNodeID: Integer);
    procedure PasteBillsNode(ANode: TsdIDTreeNode; APos: Integer; APasteNode: TBillsBlockNode);
    procedure PasteData(ANode: TsdIDTreeNode; APos: Integer);

    procedure Clear;
  protected
    procedure LoadXmlData(AXmlDoc: IXmlDocument); override;
    procedure SaveXmlData(AXmlDoc: IXmlDocument); override;
  public
    constructor Create(ABillsData: TBillsData);
    destructor Destroy; override;

    procedure Copy(ANode: TsdIDTreeNode; ACount: Integer);
    // APos: 0[子项] 1[后项] 2[前项]
    procedure Paste(ANode: TsdIDTreeNode; APos: Integer);
  end;

function HasBillsBlockFormat: Boolean;

implementation

uses sdDB, Math, SysUtils, UtilMethods;

var
  CF_BillsBlock: Word;

function HasBillsBlockFormat: Boolean;
begin
  Result := HasClipboardFormat(CF_BillsBlock);
end;

{ TBillsClipboard }

function TBillsClipboard.AddBillsNode(ANode: TsdIDTreeNode;
  APos: Integer): TsdIDTreeNode;
begin
  // 子项插入
  if APos = 0 then
    Result := ANode.Owner.Add(ANode.ID, -1)
  // 后项插入
  else if APos = 1 then
    Result := ANode.Owner.Add(ANode.ParentID, ANode.NextSiblingID)
  // 前项插入
  else if APos = 2 then
    Result := ANode.Owner.Add(ANode.ParentID, ANode.ID);
end;

procedure TBillsClipboard.Clear;
begin
  ClearObjects(FNodeList);
  FNodeList.Clear;
end;

procedure TBillsClipboard.Copy(ANode: TsdIDTreeNode; ACount: Integer);
begin
  Clear;
  CopyData(ANode, ACount);
  SaveToStream;
  SaveToClipboard(CF_BillsBlock);
end;

procedure TBillsClipboard.CopyBillsNode(ANode: TsdIDTreeNode);
var
  iChild: Integer;
begin
  if Assigned(ANode) then
  begin
    CopyBillsNodeData(ANode);
    for iChild := 0 to ANode.ChildCount - 1 do
      CopyBillsNode(ANode.ChildNodes[iChild]);
  end;
end;

procedure TBillsClipboard.CopyBillsNodeData(ANode: TsdIDTreeNode);
var
  vNode: TBillsBlockNode;
begin
  vNode := TBillsBlockNode.Create;
  FNodeList.Add(vNode);
  vNode.FID := ANode.Rec.ValueByName('ID').AsInteger;
  vNode.FParentID := ANode.Rec.ValueByName('ParentID').AsInteger;
  vNode.FNextSiblingID := ANode.Rec.ValueByName('NextSiblingID').AsInteger;
  vNode.FCode := ANode.Rec.ValueByName('Code').AsString;
  vNode.FB_Code := ANode.Rec.ValueByName('B_Code').AsString;
  vNode.FName := ANode.Rec.ValueByName('Name').AsString;
  vNode.FUnits := ANode.Rec.ValueByName('Units').AsString;
  vNode.FPrice := ANode.Rec.ValueByName('Price').AsFloat;
  vNode.FOrgQuantity := ANode.Rec.ValueByName('OrgQuantity').AsFloat;
  vNode.FOrgTotalPrice := ANode.Rec.ValueByName('OrgTotalPrice').AsFloat;
  vNode.FMisQuantity := ANode.Rec.ValueByName('MisQuantity').AsFloat;
  vNode.FMisTotalPrice := ANode.Rec.ValueByName('MisTotalPrice').AsFloat;
  vNode.FOthQuantity := ANode.Rec.ValueByName('OthQuantity').AsFloat;
  vNode.FOthTotalPrice := ANode.Rec.ValueByName('OthTotalPrice').AsFloat;
  vNode.FQuantity := ANode.Rec.ValueByName('Quantity').AsFloat;
  vNode.FTotalPrice := ANode.Rec.ValueByName('TotalPrice').AsFloat;
  vNode.FCalcType := ANode.Rec.ValueByName('CalcType').AsInteger;
  vNode.FDrawingCode := ANode.Rec.ValueByName('DrawingCode').AsString;
  vNode.FAlias := ANode.Rec.ValueByName('Alias').AsString;
  vNode.FDgnQuantity1 := ANode.Rec.ValueByName('DgnQuantity1').AsFloat;
  vNode.FDgnQuantity2 := ANode.Rec.ValueByName('DgnQuantity2').AsFloat;
  vNode.FMemoStr := ANode.Rec.ValueByName('MemoStr').AsString;
  vNode.FDealCode := ANode.Rec.ValueByName('DealCode').AsString;
  vNode.FDealCompany := ANode.Rec.ValueByName('DealCompany').AsString;
end;

procedure TBillsClipboard.CopyData(ANode: TsdIDTreeNode; ACount: Integer);
begin
  while Assigned(ANode) and (ACount > 0) do
  begin
    CopyBillsNode(ANode);
    Dec(ACount, ANode.PosterityCount + 1);
    ANode := ANode.NextSibling;
  end;
end;

constructor TBillsClipboard.Create(ABillsData: TBillsData);
begin
  inherited Create;
  FBillsData := ABillsData;
  FNodeList := TList.Create;
end;

destructor TBillsClipboard.Destroy;
begin
  ClearObjects(FNodeList);
  FNodeList.Free;
  inherited;
end;

procedure TBillsClipboard.LoadNodesFromXml(AXmlNode: IXMLNode);
var
  BillsBlockNode: TBillsBlockNode;
  iNum: Integer;
  ParentXmlNode, CurXmlNode: IXMLNode;
begin
  ParentXmlNode := AXmlNode.ChildNodes.FindNode('BillsBlockNodes');
  for iNum := 0 to ParentXmlNode.ChildNodes.Count - 1 do
  begin
    CurXmlNode := ParentXmlNode.ChildNodes.Nodes[iNum];
    BillsBlockNode := TBillsBlockNode.Create;
    FNodeList.Add(BillsBlockNode);
    BillsBlockNode.LoadFromXmlNode(CurXmlNode);
  end;
end;

procedure TBillsClipboard.LoadXmlData(AXmlDoc: IXmlDocument);
begin
  inherited;
  LoadNodesFromXml(AXmlDoc.DocumentElement);
end;

procedure TBillsClipboard.Paste(ANode: TsdIDTreeNode; APos: Integer);
begin
  Clear;
  LoadFromClipboard(CF_BillsBlock);
  LoadFromStream;
  PasteData(ANode, APos);
end;

procedure TBillsClipboard.PasteBillsNode(ANode: TsdIDTreeNode;
  APos: Integer; APasteNode: TBillsBlockNode);
var
  stnCurrent: TsdIDTreeNode;
begin
  stnCurrent := AddBillsNode(ANode, APos);
  PasteBillsNodeData(stnCurrent, APasteNode);
  PasteChildren(stnCurrent, APasteNode.FID);
  PasteNextSibling(stnCurrent, APasteNode.FNextSiblingID);
end;

procedure TBillsClipboard.PasteBillsNodeData(ANode: TsdIDTreeNode;
  APasteNode: TBillsBlockNode);
begin
  ANode.Rec.ValueByName('Code').AsString := APasteNode.FCode;
  ANode.Rec.ValueByName('B_Code').AsString := APasteNode.FB_Code;
  ANode.Rec.ValueByName('Name').AsString := APasteNode.FName;
  ANode.Rec.ValueByName('Units').AsString := APasteNode.FUnits;
  ANode.Rec.ValueByName('Price').AsFloat := APasteNode.FPrice;
  ANode.Rec.ValueByName('OrgQuantity').AsFloat := QuantityRoundTo(APasteNode.FOrgQuantity);
  ANode.Rec.ValueByName('OrgTotalPrice').AsFloat := TotalPriceRoundTo(APasteNode.FOrgTotalPrice);
  ANode.Rec.ValueByName('MisQuantity').AsFloat := QuantityRoundTo(APasteNode.FMisQuantity);
  ANode.Rec.ValueByName('MisTotalPrice').AsFloat := TotalPriceRoundTo(APasteNode.FMisTotalPrice);
  ANode.Rec.ValueByName('OthQuantity').AsFloat := QuantityRoundTo(APasteNode.FOthQuantity);
  ANode.Rec.ValueByName('OthTotalPrice').AsFloat := TotalPriceRoundTo(APasteNode.FOthTotalPrice);
  ANode.Rec.ValueByName('Quantity').AsFloat := QuantityRoundTo(APasteNode.FQuantity);
  ANode.Rec.ValueByName('TotalPrice').AsFloat := TotalPriceRoundTo(APasteNode.FTotalPrice);
  ANode.Rec.ValueByName('CalcType').AsInteger := APasteNode.FCalcType;
  ANode.Rec.ValueByName('DrawingCode').AsString := APasteNode.FDrawingCode;
  ANode.Rec.ValueByName('Alias').AsString := APasteNode.FAlias;
  ANode.Rec.ValueByName('DgnQuantity1').AsFloat := QuantityRoundTo(APasteNode.FDgnQuantity1);
  ANode.Rec.ValueByName('DgnQuantity2').AsFloat := QuantityRoundTo(APasteNode.FDgnQuantity2);
  ANode.Rec.ValueByName('MemoStr').AsString := APasteNode.FMemoStr;
  ANode.Rec.ValueByName('DealCode').AsString := APasteNode.FDealCode;
  ANode.Rec.ValueByName('DealCompany').AsString := APasteNode.FDealCompany;
end;

procedure TBillsClipboard.PasteChildren(AParentNode: TsdIDTreeNode;
  APasteParentID: Integer);
var
  iNode: Integer;
begin
  for iNode := 0 to FNodeList.Count - 1 do
    if TBillsBlockNode(FNodeList.Items[iNode]).FParentID = APasteParentID then
    begin
      PasteBillsNode(AParentNode, 0, TBillsBlockNode(FNodeList.Items[iNode]));
      Break;
    end;
end;

procedure TBillsClipboard.PasteData(ANode: TsdIDTreeNode; APos: Integer);
var
  I: Integer;
  vPasteNode: TBillsBlockNode;
begin
  PasteBillsNode(ANode, APos, TBillsBlockNode(FNodeList.First));
end;

procedure TBillsClipboard.PasteNextSibling(APreSibling: TsdIDTreeNode;
  APasteNodeID: Integer);
var
  iNode: Integer;
begin
  if APasteNodeID = -1 then Exit;
  for iNode := 0 to FNodeList.Count - 1 do
    if TBillsBlockNode(FNodeList.Items[iNode]).FID = APasteNodeID then
    begin
      PasteBillsNode(APreSibling, 1, TBillsBlockNode(FNodeList.Items[iNode]));
      Break;
    end;
end;

procedure TBillsClipboard.SaveNodesToXml(AXmlNode: IXMLNode);
var
  ParentXmlNode, CurXmlNode: IXMLNode;
  iNum: Integer;
  BillsBlockNode: TBillsBlockNode;
begin
  ParentXmlNode := AXmlNode.AddChild('BillsBlockNodes');
  for iNum := 0 to FNodeList.Count - 1 do
  begin
    BillsBlockNode := TBillsBlockNode(FNodeList.Items[iNum]);
    CurXmlNode := ParentXmlNode.AddChild('BillsBlockNode');
    BillsBlockNode.SaveToXmlNode(CurXmlNode);
  end;
end;

procedure TBillsClipboard.SaveXmlData(AXmlDoc: IXmlDocument);
begin
  SaveNodesToXml(AXmlDoc.DocumentElement);
  inherited;
end;

{ TBillsBlockNode }

procedure TBillsBlockNode.LoadFromXmlNode(AXmlNode: IXMLNode);
begin
  FID := AXmlNode.Attributes['ID'];
  FParentID := AXmlNode.Attributes['ParentID'];
  FNextSiblingID := AXmlNode.Attributes['NextSiblingID'];
  FCode := AXmlNode.Attributes['Code'];
  FB_Code := AXmlNode.Attributes['B_Code'];
  FName := AXmlNode.Attributes['Name'];
  FUnits := AXmlNode.Attributes['Units'];
  FPrice := AXmlNode.Attributes['Price'];
  FOrgQuantity := AXmlNode.Attributes['OrgQuantity'];
  FOrgTotalPrice := AXmlNode.Attributes['OrgTotalPrice'];
  FMisQuantity := AXmlNode.Attributes['MisQuantity'];
  FMisTotalPrice := AXmlNode.Attributes['MisTotalPrice'];
  FOthQuantity := AXmlNode.Attributes['OthQuantity'];
  FOthTotalPrice := AXmlNode.Attributes['OthTotalPrice'];
  FQuantity := AXmlNode.Attributes['Quantity'];
  FTotalPrice := AXmlNode.Attributes['TotalPrice'];
  FCalcType := AXmlNode.Attributes['CalcType'];
  FDrawingCode := AXmlNode.Attributes['DrawingCode'];
  FAlias := AXmlNode.Attributes['Alias'];
  FDgnQuantity1 := AXmlNode.Attributes['DgnQuantity1'];
  FDgnQuantity2 := AXmlNode.Attributes['DgnQuantity2'];
  FMemoStr := AXmlNode.Attributes['MemoStr'];
  FDealCode := AXmlNode.Attributes['DealCode'];
  FDealCompany := AXmlNode.Attributes['DealCompany'];
end;

procedure TBillsBlockNode.SaveToXmlNode(AXmlNode: IXMLNode);
begin
  AXmlNode.Attributes['ID'] := FID;
  AXmlNode.Attributes['ParentID'] := FParentID;
  AXmlNode.Attributes['NextSiblingID'] := FNextSiblingID;
  AXmlNode.Attributes['Code'] := FCode;
  AXmlNode.Attributes['B_Code'] := FB_Code;
  AXmlNode.Attributes['Name'] := FName;
  AXmlNode.Attributes['Units'] := FUnits;
  AXmlNode.Attributes['Price'] := FPrice;
  AXmlNode.Attributes['OrgQuantity'] := FOrgQuantity;
  AXmlNode.Attributes['OrgTotalPrice'] := FOrgTotalPrice;
  AXmlNode.Attributes['MisQuantity'] := FMisQuantity;
  AXmlNode.Attributes['MisTotalPrice'] := FMisTotalPrice;
  AXmlNode.Attributes['OthQuantity'] := FOthQuantity;
  AXmlNode.Attributes['OthTotalPrice'] := FOthTotalPrice;
  AXmlNode.Attributes['Quantity'] := FQuantity;
  AXmlNode.Attributes['TotalPrice'] := FTotalPrice;
  AXmlNode.Attributes['CalcType'] := FCalcType;
  AXmlNode.Attributes['DrawingCode'] := FDrawingCode;
  AXmlNode.Attributes['Alias'] := FAlias;
  AXmlNode.Attributes['DgnQuantity1'] := FDgnQuantity1;
  AXmlNode.Attributes['DgnQuantity2'] := FDgnQuantity2;
  AXmlNode.Attributes['MemoStr'] := FMemoStr;
  AXmlNode.Attributes['DealCode'] := FDealCode;
  AXmlNode.Attributes['DealCompany'] := FDealCompany;
end;

initialization
  CF_BillsBlock := RegisterClipboardFormat('Zh.BillsBlock');

end.
