Moved from "Examples Demos||Editing a list of foonotes&

General TRichView support forum. Please post your questions here
Post Reply
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Thanks Sergey,

But now RVStyles make me crazy :(

with this code I can build a table the way I want it

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
var
  table: TRVTableItemInfo;
  line : Integer;
  cell : TRVTableCellData;
begin
  rvs.TextStyles.Clear;
  with rvs.TextStyles.Add do
  begin
    FontName := 'Arial';
    Size := 11;
    Color := clBlack;
    Style := [];
  end;
  with rvs.TextStyles.Add do
  begin
    FontName := 'Arial';
    Size := 11;
    Color := clBlack;
    Style := [fsBold];
  end;

  rvs.ParaStyles.Clear;
  with rvs.ParaStyles.Add do
  begin
    Name := 'Default';
  end;
  with rvs.ParaStyles.Add as TParaInfo do
  begin
    Name := 'ReadOnly';
    Options := [rvpaoReadOnly, rvpaoStyleProtect, rvpaoDoNotWantReturns];
  end;

  table := TRVTableItemInfo.CreateEx(0, 0, rveMain.RVData);
  table.CellHSpacing := 0;
  table.CellVSpacing := 0;
  table.Options := table.Options - [rvtoRowSizing, rvtoColSizing];

  for Line := 0 to 9 do  // this will be a loop : While Query.Eof = False do
  begin
    // add a readonly 1 or 2 columns row
    table.InsertRows(table.RowCount, 1, -1);
    if table.ColCount = 0 then
      table.InsertCols(table.ColCount, 2, -1);
    cell := table.Cells[table.RowCount - 1, 0];
    cell.Clear;
    cell.AddNL('Hello World', 1, 1);
    if Odd(Line) then
    begin
      table.MergeCells(table.RowCount - 1, 0, 2, 1, False); // ColSpan = 2
      table.Cells[table.RowCount - 1, 0].AddNL(' informations', 0, -1);
    end else begin
      cell := table.Cells[table.RowCount - 1, 1];
      cell.Clear;
      cell.AddNL('informations', 0, 1);
    end;
    // add a readwrite 1 column row
    table.InsertRows(table.RowCount, 1, -1);
    table.MergeCells(table.RowCount - 1, 0, 2, 1, False);
  end;

  rveMain.InsertItem('Table', table);
end;
but I have also to insert a Blob field with RVF content in a table Cell, I've tried this:

Code: Select all

        Blob := Query.CreateBlobStream(Query.FieldByName('COMMENT'), TBlobStreamMode.bmRead);
        try
//          Cell.InsertRVFFromStream(Blob, 0, Color, nil, nil, False, nil);
          Cell.LoadRVFFromStream(Blob, Color, nil, nil, nil);
        finally
          Blob.Free;
        end;
but the style of the already inserted texts changes, and the text can disapear !!!

I've seen this comment in the sample:

Code: Select all

  // creating a table containing footnotes
  // (we save RVF without styles, because cells do not support loading RVF with styles;
  // we can do it, because we copied collections of styles, see above)
is there a way to insert the styled RVF anyway ?

the purpose of all this is to show a list of RVF (stored in a DB) inside a single component (allowing scrolling, selection, etc...). Each part will be modified in an other RV then put back in the cell (and the DB)...you can think on someting like a Blog that display differents notes in a single RVF.

Thanks
Sergey Tkachenko
Site Admin
Posts: 17569
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

As you can read in comments, in the current versions of TRichView cells do not support reading RVF containing styles.

There is a workaround:
- create a hidden TRichView linked to the same RVStyle as TRichView containing the table;
- load document in this hidden TRichView; styles from this document will be merged in this RVStyle
- save RVF from this hidden TRichView without styles; load this RVF in a table cell.

There are several examples working in this way, for example
Demos\DelphiUnicode\Assorted\Fields\MailMerge2\

Or http://www.trichview.com/support/files/copyfromcell.zip
(it copies from one of one editor to another cell of another editor; you can use LoadRVFInCell from this project; this example is quite old, add more nil parameters to Cell.LoadRVF.
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Thanks Sergey,

But I still have a bug...is it related to RV version 14.12.6 ?

Image

Image

AFAIK the RVStyles are lost and reset to default values...

you can find Unit1 and the inserted RVF on
http://www.execute.fr/RVF/
Sergey Tkachenko
Site Admin
Posts: 17569
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

You call RVFStreamToCell to load a file to a cell.
In this procedure, you call RichView1.LoadFromStream.
This code replaces all existing styles in rvs to styles from this file.

To avoid this problem, instead of RichView1.LoadFromStream, call:

Code: Select all

  RichView1.Clear;
  RichView1.InsertRVFFromStream(Stream, 0);
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Oh yes ! Thank you very much !
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Me again :)

Everything work fine, but now I have to know on witch cell the user click.

for the cells with text I've use AddNLTag() to put associate a Tag to the text.

Code: Select all

procedure TForm1.RichView1MouseUp(Sender: TCustomRichView; ...)
var
  LRVData: TCustomRVFormattedData;
  LItemNo, LOffs: Integer;
  Pt    : TPoint;
  LItem : TCustomRVItemInfo;
  RVTag : TRVTag;
begin
  Pt := RichView1.ClientToDocument(Point(X, Y));
  if RichView1.GetItemAt(Pt.X, Pt.Y, LRVData, LItemNo, LOffs, False) = False then
    Exit;
  LItem := LRVData.GetItem(LItemNo);

  // don't click outside the table
  if LItem is TRVTableItemInfo then
  begin
    GetParentForm(Self).ActiveControl := nil;
    Exit;
  end;

  RVTag := LRVData.GetItemTag(LItemNo);
  if (RVTag = '') and (LRVData is TRVTableInplaceRVData) then
  begin
    // ??? 
  end;

  if LItem is TRVTextItemInfo then
  begin
    ShowMessage(LRVData.ClassName + ':' + LItem.ClassName + ' (' + RVTag + ') :' + LRVData.GetItemText(LItemNo));
  end else begin
    ShowMessage(LRVData.ClassName + ':' + LItem.ClassName + ' (' + RVTag + ')');
  end;
end;
When the Cell is loaded from a Stream there's no Tag associated with the text...how can I find the parent cell tag ? or any other solution to get a tag (DB id) from the stream (DB blob) loaded in that cell ?
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Hello,

don't know if it's the easiest way but this works

Code: Select all

var
...
  RichView: TCustomRichViewEdit;
  Table   : TCustomRVItemInfo;
  Row, Col: Integer;
begin
...
  RVTag := LRVData.GetItemTag(LItemNo);
  if (RVTag = '') and (LRVData is TRVTableInplaceRVData) then
  begin
    if RichView1.GetCurrentItemEx(TRVTableItemInfo, RichView, Table) then
    begin
      TRVTableitemInfo(Table).GetEditedCell(Row, Col);
      ShowMessage(Format('%d,%d : ', [Row, Col]) + TRVTableItemInfo(Table).Cells[Row, Col].Tag);
    end;
  end;
BTW this helpers can...Help :)

Code: Select all

{ TRichViewEditHelper }

function TRichViewEditHelper.CreateTable(ACols, AParaNo: Integer): TRVTableItemInfo;
begin
  Result := TRVTableItemInfo.CreateEx(1, ACols, RVData);
  Result.CellHSpacing := 0;
  Result.CellVSpacing := 0;
  Result.Options := Result.Options - [rvtoRowSizing, rvtoColSizing, rvtoRowSelect, rvtoColSelect, rvtoNoCellSelect];
  Result.ParaNo := AParaNo;
end;

function TRichViewEditHelper.FieldToStream(AField: TField;
  ALoader: TRichView): TStream;
var
  rvCell: TRichView;
  Blob  : TStream;
begin
  if AField.IsNull then
    Exit(nil);
  if ALoader = nil then
    rvCell := TRichView.Create(nil)
  else
    rvCell := ALoader;
  try
    rvCell.Style := Style;
    rvCell.RVFTextStylesReadMode := rvf_sInsertMerge;
    rvCell.RVFParaStylesReadMode := rvf_sInsertMerge;
    Blob := AField.DataSet.CreateBlobStream(AField, TBlobStreamMode.bmRead);
    try
      rvCell.Clear();
      rvCell.InsertRVFFromStream(Blob, 0);
      if rvCell.IsEmpty then
        Exit(nil);
    finally
      Blob.Free;
    end;

    Result := TMemoryStream.Create;
    try
      rvCell.RVFOptions := rvCell.RVFOptions - [rvfoSaveTextStyles, rvfoSaveParaStyles];
      rvCell.SaveRVFToStream(Result, False);
      rvCell.Clear();
      Result.Position := 0;
    except
      Result.Free;
      Result := nil;
      raise;
    end;
  finally
    if ALoader = nil then
      rvCell.Free;
  end;
end;

{ TCustomRichViewHelper }

function TCustomRichViewHelper.IsEmpty: Boolean;
begin
  Result := (ItemCount = 0) or ((ItemCount = 1) and (GetItemStyle(0) >= 0) and (GetItemText(0)= ''));
end;

{ TRVTableItemInfoHelper }

function TRVTableItemInfoHelper.GetCell(ARow, ACol: Integer; AColSpan : Integer = 1): TRVTableCellData;
begin
  if ARow >= RowCount then
    InsertRows(RowCount, ARow - RowCount + 1, -1);

  if (AColSpan > 1) and (ACol + AColSpan <= ColCount) then
    MergeCells(ARow, ACol, AColSpan, 1, False);

  Result := Cells[ARow, ACol];
end;

// to be used with FieldToStream above
function TRVTableItemInfoHelper.LoadCellFromStream(AStream: TStream; ARow, ACol: Integer;
  AColSpan : Integer = 1; AColor : TColor = clNone; const ATag: TRVTag = ''): Boolean;
var
  Stream: TStream;
  Color : TColor;
  Cell  : TRVTableCellData;
begin
  if AStream = nil then
    Exit(False);
  try
    Cell := GetCell(ARow, ACol, AColSpan);
    Cell.Tag := ATag;
    Cell.Color := AColor;
    Cell.LoadRVFFromStream(AStream, Color, nil, nil, nil);
  finally
    AStream.Free;
  end;
  Result := True;
end;

function TRVTableItemInfoHelper.SetCell(ARow, ACol: Integer; const AStr: string;
  AStyleNo, AParaNo, AColSpan: Integer; AColor: TColor; const ATag: TRVTag): TRVTableCellData;
begin
  Result := GetCell(ARow, ACol, AColSpan);
  Result.Clear();
  Result.AddNLTag(AStr, AStyleNo, AParaNo, ATag);
  Result.Color := AColor;
end;

{ TRVTableCellDataHelper }

procedure TRVTableCellDataHelper.AppendStream(AStream: TStream);
var
  Color : TColor;
begin
  if AStream = nil then
    Exit;
  try
    InsertRVFFromStream(AStream, 0, Color, nil, nil, True, nil);
  finally
    AStream.Free;
  end;
end;

Sergey Tkachenko
Site Admin
Posts: 17569
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Does the user click on TRichViewEdit, not in TRichView?
In this case, in OnRVMouseUp, the caret is already at the point of clicking.
So you can get the clicked cell very simple:

Code: Select all

if RichViewEdit1.InplaceEdit=nil then
  exit; // not in a cell
Cell := TRVTableInplaceEdit(RichViewEdit1.TopLevelEditor).FCell
As for using text using Add*** method - this is not an editing method, it may make data in undo buffer incorrect.
So you need either disable undo completely, or call ClearUndo, or use InsertStringTag method instead.
tothpaul
Posts: 42
Joined: Fri Feb 06, 2015 10:41 am

Post by tothpaul »

Ok,

in fact, like the Note demo I use a Table inside a RichViewEdit to edit multiple informations in a single component.

some cells are readonly, and when the use click on it, a popup let him change informations. For this cell I use AddNLTag() to bind the text with a DB ID

some other cells are read-write with data loaded from a DB blob, I just need a way to store the DB ID...I could also keep the row/cell pair somewhere to know witch record to update...actualy I store the ID in the cell's tag
Post Reply