Copying a selected rectangle from one table to another, cell by cell

General TRichView support forum. Please post your questions here
Post Reply
Vitalii
Posts: 70
Joined: Sat Oct 20, 2018 2:55 pm

Copying a selected rectangle from one table to another, cell by cell

Post by Vitalii »

Hi, I'm trying to make it so that copied table cells are inserted into the destination table not as a single embedded table, but into their respective locations (as intuition would suggest). My code works, but the problem is with Undo/Redo. I understand that using "InsertRVFFromStream" for a cell does not undo its contents when Undo is triggered. What would be the correct approach in this case to be able to undo the insertion of content using CTRL+Z? It’s enough to do it once, not for each cell individually.

Code: Select all


procedure TRVClipboardTableRectangle.CopyFromTable(ATable: TRVTableItemInfo);
var
  Row, Col, RowSpan, ColSpan: Integer;
begin
  if ATable = nil then
    raise Exception.Create('ATable=nil in TRVClipboardTableRectangle.CopyCells().');

  if ATable.GetNormalizedSelectionBounds(True, Row, Col, ColSpan, RowSpan) then
    begin
      FStartRow := Row;
      FStartCol := Col;
      FRowCount := RowSpan;
      FColCount := ColSpan;
      ATable.SaveRectangleToStream(FStream, FStartRow, FStartCol, FRowCount, FColCount, True, True);
    end;
end;

procedure TRVClipboardTableRectangle.PasteToTable(ATable: TRVTableItemInfo; AEdit: TCustomRichViewEdit);
var
  TempTable: TRVTableItemInfo;
  StartRow, StartCol, RowSpan, ColSpan: Integer;
  r, c, new_r, new_c: Integer;
  CellStream: TMemoryStream;
  Color: TRVColor;
  Dummy1, Dummy2: Pointer;
  SourceCell, TargetCell: TRVTableCellData;
  CurR, CurC: Integer;
  MainR, MainC: Integer;

begin
  if ATable = nil then
    raise Exception.Create('ATable=nil in TRVClipboardTableRectangle.PasteCells().');

  if AEdit = nil then
    raise Exception.Create('AEdit=nil in TRVClipboardTableRectangle.PasteCells().');

  if not Active then Exit;

  { identify the starting coordinates where the data will be inserted }
  if not ATable.GetNormalizedSelectionBounds(True, StartRow, StartCol, ColSpan, RowSpan) then
    begin
      if ATable.GetEditedCell(CurR, CurC) <> nil then
        begin
          StartRow := CurR;
          StartCol := CurC;
        end
      else
        Exit; { caret is out of table... }
    end;

  Color := clNone;
  Dummy1 := nil;
  Dummy2 := nil;

  TempTable := TRVTableItemInfo.CreateEx(0, 0, AEdit.RVData);
  CellStream := TMemoryStream.Create;

  try
    { load source table rectangle }
    FStream.Position := 0;
    TempTable.LoadFromStream(FStream);

    if (TempTable.RowCount = 0) or (TempTable.ColCount = 0) then Exit;

    for r := 0 to TempTable.RowCount - 1 do
      for c := 0 to TempTable.ColCount - 1 do
        begin
          SourceCell := TempTable.Cells[r, c];

          if Assigned(SourceCell) then
            begin
              new_r := r + StartRow;
              new_c := c + StartCol;

              { are we within the target table range? }
              if (new_r >= ATable.RowCount) or (new_c >= ATable.ColCount) then
                Continue;

              { merge target cells if source cell has ColSpan or RowSpan > 1 }
              if (SourceCell.ColSpan > 1) or (SourceCell.RowSpan > 1) then
                begin
                  { ensure merged area fits within target table bounds }
                  if (new_r + SourceCell.RowSpan <= ATable.RowCount) and
                     (new_c + SourceCell.ColSpan <= ATable.ColCount) then
                    begin
                      ATable.MergeCells(new_r, new_c, SourceCell.ColSpan, SourceCell.RowSpan, True);
                    end;
                end;

              ATable.Rows.GetMainCell(new_r, new_c, MainR, MainC);

              if (MainR >= 0) and (MainC >= 0) and (new_r = MainR) and (new_c = MainC) then
                begin
                  TargetCell := ATable.Cells[MainR, MainC];

                  if Assigned(TargetCell) then
                    begin
                      { copy RVF data of the source cell }
                      CellStream.Clear;
                      SourceCell.SaveRVFToStream(CellStream, False, clNone, nil, nil);

                      { insert RVF data to the target cell }
                      CellStream.Position := 0;
                      TargetCell.Clear;
                      TargetCell.InsertRVFFromStream(CellStream, 0, Color, Dummy1, Dummy2, True, nil, nil);
                      TargetCell.Normalize;

                      { copy cell properties }
                      ATable.SetCellColor(SourceCell.Color, new_r, new_c);
                      ATable.SetCellOpacity(SourceCell.Opacity, new_r, new_c);
                      ATable.SetCellVAlign(SourceCell.VAlign, new_r, new_c);
                      ATable.SetCellBackgroundStyle(SourceCell.BackgroundStyle, new_r, new_c);
                      ATable.SetCellHint(SourceCell.Hint, new_r, new_c);
                      ATable.SetCellRotation(SourceCell.Rotation, new_r, new_c);
                      ATable.SetCellOptions(SourceCell.Options, new_r, new_c);
                      ATable.SetCellTag(SourceCell.Tag, new_r, new_c);

                      if Assigned(SourceCell.BackgroundImage) then
                        ATable.SetCellBackgroundImage(SourceCell.BackgroundImage, new_r, new_c);
                   end;
                end;
            end;
        end;

  finally
    CellStream.Free;
    TempTable.Free;
  end;

  ATable.Changed;
end;
Post Reply