copy current col to a new current col

General TRichView support forum. Please post your questions here
j&b

copy current col to a new current col

Post by j&b »

Hello,
can someone tell me how I can get the content of one rveTable.cell.

I want to copy the content of current col to a new current col.

my idea:

procedure TForm1.SpaltenInhaltKopierenClick(Sender: TObject);
var r,c,tSpalte: integer;
begin
try
rveTable.GetEditedCell(r,tSpalte);
strl1.Clear; //TStringList
memo.Color:=clBtnFace;
Application.ProcessMessages;
SendMessage(rve.Handle, WM_SETREDRAW, 0, 0);
for r := 0 to rveTable.Rows.Count-1 do
for c := 0 to rveTable.Rows[r].Count-1 do
if rveTable.Cells[r,c]<>nil then begin
// if c=tSpalte then strl1.add(???);
end;
finally
SendMessage(rve.Handle, WM_SETREDRAW, 1, 0);
memo.color:=clWhite;
end;
end;

procedure TForm1.SpaltenInhaltEinfuegenClick(Sender: TObject);
var r,c,tSpalte: integer;
begin
try
rveTable.GetEditedCell(r,tSpalte);
strl1.Clear;
memo.Color:=clBtnFace;
Application.ProcessMessages;
SendMessage(rve.Handle, WM_SETREDRAW, 0, 0);
for r := 0 to rveTable.Rows.Count-1 do
for c := 0 to rveTable.Rows[r].Count-1 do
if rveTable.Cells[r,c]<>nil then begin
if c=tSpalte then begin
rveTable.EditCell(r,c);
memo.TopLevelEditor.SelectAll;
memo.InsertText(strl1.lines[r]);
end;
end;
finally
SendMessage(rve.Handle, WM_SETREDRAW, 1, 0);
rve.Invalidate;
memo.color:=clWhite;
end;
end;
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

I think you may want to go along the lines of
SourceCell.SaveRVFToStream()
DestinationCell.LoadRVFFromStream()

The thread "Cell Streaming does not save Styles" in this forum has slightly more stuff on this subject. E.g., WhateverCell in the pseudo-code-like example above may need to be a more involved "beast" (RVData or the like).

Michel
j&b

Post by j&b »

Thank you, but I don't understand your hints because I'm a beginner.


Can you answer my question

if c=tSpalte then strl1.add(content of cell);
(instead of a StringList I can take a delphi-richedit, so that content doesn't loose his attributes),

too ?


It would be nice, if you would write your hint in more detail (I'm a beginner ;-) )

PS: Naturally it must be called 'memo.InsertText(strl1.strings[r])' instead of strl1.lines[r];
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

Thank you, but I don't understand your hints because I'm a beginner.
Oh, sorry. That was not apparent from the cell-iteration code you presented! :wink:
(instead of a StringList I can take a delphi-richedit, so that content doesn't loose his attributes)
That was more or less what I meant. Basically, to save the contents of a cell to some temporary/intermediate storage location/object, you must use a stream (a cell can contain much more than just lines of text, e.g., an entire document with more tables inside). However, you can't use a Delphi TRichEdit as that intermediate storage, that's for sure.
I can offer small pieces of C++ code as an example of what I meant. You'll have to adapt it to your needs.

Code: Select all

TMemoryStream *MS = new TMemoryStream;  // You'll need a stream to transfer cell contents

TRVTableCellData *Cell = Table->Cells[0][0];  // Get somehow to the cell of interest
Cell->SaveRVFToStream(MS, false, clNone, NULL, NULL);  // Save it to the stream

TCustomRVData *CRVD = Cell->GetRVData();  // This is an alternative to the above
CRVD->SaveRVFToStream(MS, false, clNone, NULL, NULL);

TRVTableInplaceRVData *CED = (TRVTableInplaceRVData *)Cell->Edit(); // Another alternative
CED->SaveRVFToStream(MS, false, clNone, NULL, NULL);
There are even more alternative ways to save the cell's contents to a stream, but any of the above should do the job within the same RichView control.

Now, get somehow to the destination cell Dest and with it:

Code: Select all

MS->Position = 0;  // "Rewind" the stream
Dest->LoadRVFFromStream(MS, <...>);  // "Stream in" the saved source cell contents
The only problem is that I don't remember if there are some additional parameters after MS, so you may need to replace <...> by something like DummyTColorVariable, NULL, NULL.

I hope this is starting to make sense. To reiterate, stop thinking of RichView in terms of lists of strings or lines and such. I find it much more useful to think of it as a tree of RVData objects organized into a hierarchy of tables and cells containing more of the same.

Hope this helps,

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

Post by Sergey Tkachenko »

Thanks again, Michel :)

Some comments about copying to the stream:

Code: Select all

// c++
TRVTableCellData *Cell = Table->Cells[0][0]; 
Cell->SaveRVFToStream(MS, false, clNone, NULL, NULL);
// pascal
var Cell: TRVTableCellData;
Cell := Table.Cells[0,0]; 
Cell.SaveRVFToStream(MS, False, clNone, nil, nil);
The code above will work only if the cell is not edited.
It will fail if the cell is edited

Code: Select all

// c++
TCustomRVData *CRVD = Cell->GetRVData();
CRVD->SaveRVFToStream(MS, false, clNone, NULL, NULL); 
// pascal
var CRVD: TCustomRVData;
CRVD := Table.Cells[0,0].GetRVData; 
CRVD.SaveRVFToStream(MS, False, clNone, nil, nil);
This is the best method. Will work in all cases, and it is fast.

Code: Select all

//c++
TRVTableInplaceRVData *CED = (TRVTableInplaceRVData *)Cell->Edit(); CED->SaveRVFToStream(MS, false, clNone, NULL, NULL);
// pascal
var CED: TCustomRVFormattedData;
CED := Table.Cells[0,0].Edit; 
CED.SaveRVFToStream(MS, False, clNone, nil, nil);
This method works, but it creates cell inplace editor for the cell, and it is not necessary and relatively slow.
Sergey Tkachenko
Site Admin
Posts: 17309
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Now about writing from stream to the cell.

There are two ways
1) First, using LoadRVFFromStream.
This method cannot be undone/redone and damages undo buffers (as viewer-style method), so call RichViewEdit1.ClearUndo after calling it.

Cell loading does not support styles, so we must turn off style reading from RVF wile loading.

Code: Select all

var oldps, oldts:TRVFReaderStyleMode;

oldps := RichViewEdit1.RVFParaStylesReadMode;
oldts := RichViewEdit1.RVFTextStylesReadMode;
RichViewEdit1.RVFParaStylesReadMode := rvf_sIgnore;
RichViewEdit1.RVFTextStylesReadMode := rvf_sIgnore;

MS.Position := 0;
DestCell.GetRVData.LoadRVFFromStream(MS, <...>);  

RichViewEdit1.RVFParaStylesReadMode := oldps;
RichViewEdit1.RVFTextStylesReadMode := oldts;
RichViewEdit1 is TDBRichViewEdit, call RichViewEdit1.CanChange before and RichViewEdit1.Change after the operation.

2) Preferred method for editor:

Code: Select all

DestCell.Edit;
RichViewEdit1.TopLevelEditor.SelectAll;
RichViewEdit1.TopLevelEditor.InsertRVFFromStreamEd(MS);
PS: Do not forget to call MS.Free after loading
PPS: Tables already have methods for copying multicell range, but loading it currently has some limitations which will be removed in one of next updates.
Guest

Post by Guest »

Hello,

you are on another level than I.
Is it therefore not more simply for you to show the correct solution, because people will ask you again if there is an error or they have missunderstand you ?

procedure TForm1.SpalteKopierenClick(Sender: TObject);
var oldps, oldts:TRVFReaderStyleMode;
destCell: TRVTableCellData;
begin
if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
ShowMessage('Tabelle hat nicht den Focus.');
exit;
end;

//if (not memo.CanChange) then exit; //s.o.
oldps := memo.RVFParaStylesReadMode;
oldts := memo.RVFTextStylesReadMode;
memo.RVFParaStylesReadMode := rvf_sIgnore;
memo.RVFTextStylesReadMode := rvf_sIgnore;
stream1.Position := 0;


//DestCell.GetRVData.LoadRVFFromStream(Stream1, < whatever I write, I get an error >); <<--------------------

{function LoadRVFFromStream(Stream: TStream; var Color: TColor;
Background: TRVBackground; Layout: TRVLayoutInfo):Boolean;}


memo.RVFParaStylesReadMode := oldps;
memo.RVFTextStylesReadMode := oldts;
memo.Change;
end;

procedure TForm1.SpalteEinfuegenClick(Sender: TObject);
var destCell: TRVTableCellData;
begin
if (not memo.CanChange) or (not memo.GetCurrentItemEx(TRVTableItemInfo, rve, TCustomRVItemInfo(rveTable))) then begin
ShowMessage('Tabelle hat nicht den Focus.');
exit;
end;

// because of error in procedure TForm1.SpalteKopierenClick

DestCell.Edit;
memo.TopLevelEditor.SelectAll;
memo.TopLevelEditor.InsertRVFFromStreamEd(Stream1);
//Stream1 created and free in form1.activate and form1.close
end;
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

I can only fluently write in C++, and it may not be of much help, so I'll leave the challenge up to Sergey! :wink:

The point you seem to be missing though is that the code snippets we have suggested are just that - the most crucial pieces that are supposed to be integrated into your original code from your first post.

In the last code you posted you were obviously missing
DestCell := rveTable.Cells[r, c];
or similar. But this and all that stuff needs to go into your original functions - where you do somehow get the r and c of interest.

Sorry if I can't offer a complete solution.

Michel
j&b

Post by j&b »

Hello Michel,

I am happy that you (or other people) give me a hint so that I further can go on at my work (if I could convert the hints). Often it is so that one only gets some code, which can't be used in lack of experience or knowledge.
In this case you/Sergey use a shortened call (DestCell.GetRVData.LoadRVFFromStream(MS, <...>)).
I looked up for the parameters in RVData.pas

(function LoadRVFFromStream(Stream: TStream; var Color: TColor;
Background: TRVBackground; Layout: TRVLayoutInfo):Boolean

and tried it with them. The result is an error.

In addition that I am not sure if I set the code correctly in my program I think that often it is better for both sides (and the inexperienced readers of the question) that helper give an executable code (with call).

Here I would thank expressly Sergey for his many helps and I hope that he doesn't understand my inquiring as beef.

Jürgen
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

Hey there!

I haven't tried it, but I think that call should go something like this:

Code: Select all

var DummyColor: TColor;
LoadRVFFromStream(MS, DummyColor, nil, nil);
If that's not what you have tried, try this. If it still gives you trouble, let us know what the exact results/problems are (e.g., when you say "error" - what is it?). Perhaps once you have hit the proverbial "brick wall" it'd be time for you to re-post your latest code (so that Sergey could take a look :wink: ).

All this stuff takes a little time to wrap one's head around, so don't give up. Good luck!

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

Post by Sergey Tkachenko »

Copying the column SourceCol to the column DestCol.

Code: Select all

procedure CopyTableColumn(rv: TCustomRichView; table: TRVTableItemInfo;
  SourceCol, DestCol: Integer);
var r: Integer;
    Stream: TMemoryStream;
    UnusedColor: TColor;
    oldps, oldts:TRVFReaderStyleMode;
begin
  if SourceCol=DestCol then
    exit;
  UnusedColor := clNone;
  oldps := rv.RVFParaStylesReadMode;
  oldts := rv.RVFTextStylesReadMode;
  rv.RVFParaStylesReadMode := rvf_sIgnore;
  rv.RVFTextStylesReadMode := rvf_sIgnore;
  try
    for r := 0 to table.Rows.Count-1 do
      if (table.Cells[r, SourceCol]<>nil) and
         (table.Cells[r, DestCol]<>nil) then begin
        Stream := TMemoryStream.Create;
        try
          table.Cells[r, SourceCol].GetRVData.SaveRVFToStream(Stream,
            False, UnusedColor, nil, nil);
          Stream.Position := 0;
          table.Cells[r, DestCol].GetRVData.LoadRVFFromStream(Stream,
            UnusedColor, nil, nil);
        finally
          Stream.Free;
        end;
      end;
  finally
    rv.RVFParaStylesReadMode := oldps;
    rv.RVFTextStylesReadMode := oldts;
  end;
end;
This method works for all RichViews, not only for the editors.
It cannot be undone/redone.

Example of call (I assume that you already assigned table variable):

Code: Select all

CopyTableColumn(RichViewEdit1, table, 0, 1);
  RichViewEdit1.ClearUndo;
  RichViewEdit1.Format;
Example of call for DBRichViewEdit:

Code: Select all

if DBRichViewEdit1.CanChange then begin
  CopyTableColumn(DBRichViewEdit1, table, 0, 1);
  DBRichViewEdit1.ClearUndo;
  DBRichViewEdit1.Change;
  DBRichViewEdit1.Format;
Last edited by Sergey Tkachenko on Sun Nov 06, 2005 10:05 pm, edited 1 time in total.
Sergey Tkachenko
Site Admin
Posts: 17309
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

This method can be called only for editors, and it can be undone/redone by the user.

Code: Select all

procedure CopyTableColumnEd(rv: TCustomRichViewEdit; table: TRVTableItemInfo;
  SourceCol, DestCol: Integer);
var r: Integer;
    Stream: TMemoryStream;
    UnusedColor: TColor;
    oldps, oldts:TRVFReaderStyleMode;
begin
  if SourceCol=DestCol then
    exit;
  UnusedColor := clNone;
  oldps := rv.RVFParaStylesReadMode;
  oldts := rv.RVFTextStylesReadMode;
  rv.RVFParaStylesReadMode := rvf_sIgnore;
  rv.RVFTextStylesReadMode := rvf_sIgnore;
  SendMessage(rv.Handle, WM_SETREDRAW, 0, 0);
  try
    for r := 0 to table.Rows.Count-1 do
      if (table.Cells[r, SourceCol]<>nil) and
         (table.Cells[r, DestCol]<>nil) then begin
        Stream := TMemoryStream.Create;
        try
          table.Cells[r, SourceCol].GetRVData.SaveRVFToStream(Stream,
            False, UnusedColor, nil, nil);
          Stream.Position := 0;
          table.Cells[r, DestCol].Edit;
          rv.TopLevelEditor.SelectAll;
          rv.TopLevelEditor.InsertRVFFromStreamEd(Stream);
        finally
          Stream.Free;
        end;
      end;
  finally
    rv.RVFParaStylesReadMode := oldps;
    rv.RVFTextStylesReadMode := oldts;
  SendMessage(rv.Handle, WM_SETREDRAW, 1, 0);
  while rv<>nil do begin
    rv.Invalidate;
    rv := TCustomRichViewEdit(rv.InplaceEditor);
  end;
  end;
end;
Calling is the same for DBRichViewEdit and RichViewEdit:

Code: Select all

CopyTableColumn(RichViewEdit1, table, 0, 1);
Since editing-style method is used (InsertText), CanChange+Change+ClearUndo+Format are not required.

PS: Modifying RVFParaStylesReadMode and RVFTextStylesReadMode is not required in this method, but makes loading faster a bit.
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

You never sleep, Sergey, do you? :)

Just a little question for my own understanding: why is it necessary (especially in this example) to set RVF*StylesReadMode := rvf_sIgnore? Here's why I'm asking:
A) As we have discussed earlier in the "Cell Streaming does not save Styles" thread, SaveRVFToStream() doesn't appear to be saving any styles to the stream, so there should be nothing to ignore, and
B) The saving/loading operations are obviously within the same RichView, so "incoming" styles (if any) would be the same ones we already have, so we can't get any problems with styles "overlapping" or missing.

I suspect that I am overlooking some subtle (or not) problem, so I would greatly appreciate it if you could explain this.

Thanks!

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

Post by Sergey Tkachenko »

Well, really, if RVF does not contain styles, it's not necessary to set modes to ignore.
In the second example, it is not necessary because editor.InsertRVFFromStreamEd supports styles. But... In the ignore mode, the i-th style in RVF is mapped to the i-th style of document. In the merge mode, the component first tries to find the existing style equal to the style from RVF. If all styles are unique (which is normal), the i-th style will be mapped to the i-th style. But if, for some reason, they are not unique, it will be mapped to another style (visually the same, though). Exception: list styles are mapped to the same list styles when copying from the same document (it's not necessary for numbering to be unique). So, the ignore mode has 2 benefits: it is faster, and it guarantees the exact copy of the original.
Michel
Posts: 92
Joined: Fri Oct 14, 2005 2:56 pm
Contact:

Post by Michel »

Thanks, Sergey, for a very clear explanation! That was pretty much my understanding from reading the Help, and that's why I got a bit surprised when you seemed to have insisted on forcing the ignore mode.
Thanks again,
Michel
Post Reply