[Example] Converting table to text

Demos, code samples. Only questions related to the existing topics are allowed here.
Post Reply
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

[Example] Converting table to text

Post by Sergey Tkachenko »

This example "removes" the table at the caret position without removing its content:

Code: Select all

procedure ConvertTableToText(RichViewEdit: TCustomRichViewEdit);
var table: TRVTableItemInfo;
    rv: TRichView;
    rve: TCustomRichViewEdit;
    Stream: TMemoryStream;
    ItemNo,r,c: Integer;
begin
  if not RichViewEdit.GetCurrentItemEx(TRVTableItemInfo, rve,
TCustomRVItemInfo(table)) then
    exit;
  rv := TRichView.Create(nil);
  try
    rv.Visible := False;
    rv.Parent := RichViewEdit.Parent;
    rv.Style := RichViewEdit.Style;
    rv.RVFTextStylesReadMode := rvf_sIgnore;
    rv.RVFParaStylesReadMode := rvf_sIgnore;
    for r := 0 to table.Rows.Count-1 do
      for c := 0 to table.Rows[r].Count-1 do
        if table.Cells[r,c]<>nil then begin
          Stream := TMemoryStream.Create;
          try
            table.Cells[r,c].GetRVData.SaveRVFToStream(Stream, False, clNone, nil, nil);
            Stream.Position := 0;
            rv.InsertRVFFromStream(Stream, rv.ItemCount)
          finally
            Stream.Free;
          end;
        end;
    ItemNo := table.GetMyItemNo;
    Stream := TMemoryStream.Create;
    try
      rv.SaveRVFToStream(Stream, False);
      Stream.Position := 0;
      rve.SetSelectionBounds(ItemNo, 0, ItemNo, 1);
      rve.InsertRVFFromStreamEd(Stream);
    finally
      Stream.Free;
    end;
  finally
    rv.Free;
  end;
end;
The same for C++Builder:

Code: Select all

void ConvertTableToText(TCustomRichViewEdit* RichViewEdit)
{
  TCustomRVItemInfo   *item;
  TCustomRichViewEdit *rve;
  if (! RichViewEdit->GetCurrentItemEx(__classid(TRVTableItemInfo), rve,
item))
    return;
  TRVTableItemInfo*table = (TRVTableItemInfo*)item;
  TRichView* rv = new TRichView((TComponent*)NULL);
  rv->Visible = false;
  rv->Parent  = RichViewEdit->Parent;
  rv->Style   = RichViewEdit->Style;
  rv->RVFTextStylesReadMode = rvf_sIgnore;
  rv->RVFParaStylesReadMode = rvf_sIgnore;
  for (int r=0; r<table->Rows->Count; r++)
    for (int c=0; c<table->Rows->Items[r]->Count; c++)
      if (table->Cells[r][c])
      {
        TMemoryStream*Stream = new TMemoryStream;
        table->Cells[r][c]->GetRVData()->SaveRVFToStream(Stream, false,
          clNone, NULL, NULL);
        Stream->Position = 0;
        rv->InsertRVFFromStream(Stream, rv->ItemCount);
        delete Stream;
      }
  int ItemNo = table->GetMyItemNo();
  TMemoryStream*Stream = new TMemoryStream;
  rv->SaveRVFToStream(Stream, false);
  Stream->Position = 0;
  rve->SetSelectionBounds(ItemNo, 0, ItemNo, 1);
  rve->InsertRVFFromStreamEd(Stream);
  delete Stream;
  delete rv;
}
Last edited by Sergey Tkachenko on Sun Oct 02, 2011 7:53 pm, edited 2 times in total.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

This version of ConvertTableToText inserts ';' instead of line breaks between table cells (line breaks are inserted between rows).
It has a new parameter: EqualDelimCount.
If it is True, the same number (table.ColCount-1) of semicolons will be inserted for each row.
If it is False, semicolons will not be used for horizontally merged cells.

For example, for this table:
Image
EqualDelimCount=False:
1;2;3
4;5
;6
EqualDelimCount=True:
1;2;3
4;;5
;;6

Code: Select all

uses RVNormalize; // from RichViewActions

procedure ConvertTableToText(RichViewEdit: TCustomRichViewEdit; EqualDelimCount: Boolean);
var table: TRVTableItemInfo;
    rv: TRichView;
    rve: TCustomRichViewEdit;
    Stream: TMemoryStream;
    ItemNo,r,c, mr, mc: Integer;
    NewLine: Boolean;
begin
  if not RichViewEdit.GetCurrentItemEx(TRVTableItemInfo, rve,
    TCustomRVItemInfo(table)) then
    exit;
  rv := TRichView.Create(nil);
  try
    rv.Visible := False;
    rv.Parent := RichViewEdit.Parent;
    rv.Style := RichViewEdit.Style;
    rv.RVFTextStylesReadMode := rvf_sIgnore;
    rv.RVFParaStylesReadMode := rvf_sIgnore;
    for r := 0 to table.RowCount-1 do begin
      NewLine := True;
      for c := 0 to table.ColCount-1 do begin
        if (c<>0) then begin
          if EqualDelimCount then
            if NewLine then
              rv.AddNLATag(';',0, 0, '')
            else
              rv.AddNLATag(';',0,-1, '')
          else begin
            table.Rows.GetMainCell(r, c, mr, mc);
            if mc=c then
              if NewLine then
                rv.AddNLATag(';',0, 0, '')
              else
                rv.AddNLATag(';',0,-1, '')
            else
              if NewLine then
                rv.AddNLATag('',0, 0, '');
          end;
          NewLine := False;
        end;
        if table.Cells[r,c]<>nil then begin
          Stream := TMemoryStream.Create;
          try
            table.Cells[r,c].GetRVData.SaveRVFToStream(Stream, False, clNone, nil, nil);
            Stream.Position := 0;
            if ((c=0) and (r<>0)) or NewLine or
               (table.Cells[r,c].GetRVData.GetItemStyle(0)=rvsListMarker) or
               table.Cells[r,c].GetRVData.GetItem(0).GetBoolValue(rvbpFullWidth) then
              rv.InsertRVFFromStream(Stream, rv.ItemCount)
            else
              rv.AppendRVFFromStream(Stream, -1);
            NewLine := False;
          finally
            Stream.Free;
          end;
        end;
      end;
    end;
    NormalizeRichView(rv.RVData);
    ItemNo := table.GetMyItemNo; 
    Stream := TMemoryStream.Create; 
    try 
      rv.SaveRVFToStream(Stream, False); 
      Stream.Position := 0; 
      rve.SetSelectionBounds(ItemNo, 0, ItemNo, 1); 
      rve.InsertRVFFromStreamEd(Stream); 
    finally 
      Stream.Free; 
    end; 
  finally 
    rv.Free; 
  end; 
end;
Ways to improve:
1) this code uses TextStyles[0] and ParaStyles[0] for AddNLATag. You can change it to text style from table cells.
2) to do something with semicolons and line breaks inside table cells (this code keeps them as they are)

Note: a slightly improved version of this code is included in RichViewActions. It is used in TrvActionTableToText.

Updates:
2011-Oct-2: for compatibility with TRichView 13.4
Last edited by Sergey Tkachenko on Sun Oct 02, 2011 7:53 pm, edited 2 times in total.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

The examples above convert the current table (at the caret position) as an editing operation. The user can undo it.

The procedure ConvertAllTablesToText below converts all tables, without a possibility to undo. If Recursive=True, nested tables are converted as well.

Code: Select all

procedure ConvertAllTablesToText(RVData: TCustomRVData;
  Recursive: Boolean); forward;

procedure ConvertOneTableToText(RVData: TCustomRVData; ItemNo: Integer;
  Recursive: Boolean);
var table: TRVTableItemInfo;
    rv: TRichView;
    Stream: TMemoryStream;
    r,c: Integer;
    Color: TColor;
begin
  table := RVData.GetItem(ItemNo) as TRVTableItemInfo;
  if Recursive then
    for r := 0 to table.Rows.Count-1 do
      for c := 0 to table.Rows[r].Count-1 do
        if table.Cells[r,c]<>nil then
          ConvertAllTablesToText(table.Cells[r,c].GetRVData, Recursive);
  rv := TRichView.Create(nil);
  try
    rv.Visible := False;
    rv.Style := RVData.GetRVStyle;
    rv.RVFTextStylesReadMode := rvf_sIgnore;
    rv.RVFParaStylesReadMode := rvf_sIgnore;
    for r := 0 to table.Rows.Count-1 do
      for c := 0 to table.Rows[r].Count-1 do
        if table.Cells[r,c]<>nil then begin
          Stream := TMemoryStream.Create;
          try
            table.Cells[r,c].GetRVData.SaveRVFToStream(Stream, False, clNone, nil, nil);
            Stream.Position := 0;
            rv.InsertRVFFromStream(Stream, rv.ItemCount)
          finally
            Stream.Free;
          end;
        end;
    RVData.DeleteItems(ItemNo, 1);
    Stream := TMemoryStream.Create;
    try
      rv.SaveRVFToStream(Stream, False);
      Stream.Position := 0;
      RVData.InsertRVFFromStream(Stream, ItemNo, Color, nil, nil, False, nil, nil);
    finally
      Stream.Free;
    end;
  finally
    rv.Free;
  end;
end;

procedure ConvertAllTablesToText(RVData: TCustomRVData;
  Recursive: Boolean);
var i: Integer;
begin
  for i := RVData.ItemCount-1 downto 0 do
    if RVData.GetItemStyle(i)=rvsTable then
      ConvertOneTableToText(RVData, i, Recursive);
end;
How to use:

Code: Select all

  ConvertAllTablesToText(RichViewEdit1.RVData, True);
  RichViewEdit1.Format;
  RichViewEdit1.ClearUndo;
Update:
2018-Apr-9: changed for compatibility with TRichView 17
Last edited by Sergey Tkachenko on Sun Oct 02, 2011 7:54 pm, edited 1 time in total.
Post Reply