trichview.com Forum Index trichview.com
TRichView support forums
 

Move Selection to Original Position

Goto page 1, 2  Next
 
Post new topic   Reply to topic    trichview.com Forum Index -> Support
    View previous topic :: View next topic  
Author Message
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Sat Dec 19, 2009 10:12 pm    Post subject: Move Selection to Original Position Reply with quote

I want to do the same thing as "Move Caret to Original Position" in http://www.trichview.com/forums/viewtopic.php?t=1463 except I want to do it with the selection, instead of the just the caret position.

It needs to work with tables that are only 1 level deep (i.e. they never have tables in the tables).

This is what I tried and I thought might work:

Code:

  RVE.BeginUpdate;

  RVE.GetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo, EndItemOffs, true);
  if RVE.RVData.GetItemStyle(StartItemNo) = rvsTable then begin
    TableRVE := RVE.TopLevelEditor;
    TableRVE.GetSelectionBounds(TableStartItemNo, TableStartItemOffs, TableEndItemNo, TableEndItemOffs, false);
  end;

  ...

  (Add or remove items before the current item)
  (Update StartItemNo and EndItemNo to reflect the items added or removed)

  ...

  RVE.SetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo, EndItemOffs);
  if RVE.GetCurrentItemEx(TRVTableItemInfo, TableRVE, TableItem) then
    TableRVE.SetSelectionBounds(TableStartItemNo, TableStartItemOffs, TableEndItemNo, TableEndItemOffs);

  RVE.EndUpdate;


But this does cause an exception when trying to set the selection into a table.

The document is formatted prior to this code.

I have tried adding an RVE.Invalidate just before the RVE.EndUpdate. but that doesn't help.

Any suggestions as to how I can get this to work?

Thanks.

Louis
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Mon Dec 21, 2009 12:48 pm    Post subject: Reply with quote

I am not sure that I understand completely.
But before making a selection inside a table cell, you need to activate its editing.
Use table.EditCell or
RvData := Cell;
RvData := RvData.Edit;
TCustomRVFormattedData(RvData).SetSelectionBounds(...)
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Tue Dec 22, 2009 5:46 am    Post subject: Reply with quote

I don't know what it is, Sergey, but I seem to be having a lot of trouble with this.

Let's see if I can explain it in detail.

What I'm trying to do is save a selection in a table, rebuild the RichViewEdit to include exactly the same table, but possibly as a different item, and then restore the selection.

So for example, as in my code above, the Table is in item StartItemNo. Then to save the selection, I do this:

Code:
  var
    TableRVE: TCustomRichViewEdit;
   
  if RVE.RVData.GetItemStyle(StartItemNo) = rvsTable then begin
    TableRVE := RVE.TopLevelEditor;
    TableRVE.GetSelectionBounds(TableStartItemNo, TableStartItemOffs, TableEndItemNo, TableEndItemOffs, false);
  end;


But the GetSelectionBounds I used above does not save the cell Row and Column, so I can't pick the cell to edit.

So I guess you're saying that I have to use the TRVTableItemInfo form of GetSelectionBounds and do this:

Code:
  var
    TableItem: TRVTableItemInfo;
   
  if RVE.RVData.GetItemStyle(StartItemNo) = rvsTable then begin
    TableItem := TRVTableItemInfo(RVE.RVData.GetItem(StartItemNo));
    TableItem.GetSelectionBounds(TableStartRow, TableStartCol, TableRowOffs, TableColOffs);
  end;


Now I recreate my RVE and update StartItemNo to be the item containing the identical table I had before. I want to restore the selection.

But I'm not sure how I do that. If I've got TableStartRow and TableStartCol, then I guess I can select the Cell. Then I can activate its editing. But then how do I get the selection back, since there's only TableRowOffs and TableColOffs? That's only one set of offsets. Not two. What do I put into the SetSelectionBounds?
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Sat Dec 26, 2009 5:55 pm    Post subject: Reply with quote

May be you can use functions from RVLinear.pas

They are sensitive to adding/deleting contents, but you need not worrying about indices of tables and cells.
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Wed Dec 30, 2009 6:11 am    Post subject: Reply with quote

Okay. Finally further investigation has led me to discover something.

It seems that in my code, the GetSelection Bounds, update items, and then SetSelectionBounds is actually working.

What isn't working is when my cursor starts inside a table, I do a cursor movement down, I do my Get-Update-Set procedure, and then I wait for the cursor movement to happen. Then an exception occurs which you have well documented in your Forums as the "limitation" of being unable to cursor out of a table.

You say that we should use PostMessage to solve this. I've looked through your examples, but I don't see any that tell me how to do it for the arrow and page-up/down keys.

I am thinking that the end of my RVEditKeyDown routine will have to look like this:

Code:
  case Key of
    VK_UP: PostMessage(Handle, WM_????, 0, 0);
    VK_DOWN: PostMessage(Handle, WM_????, 0, 0);
    VK_PRIOR: PostMessage(Handle, WM_????, 0, 0);
    VK_NEXT: PostMessage(Handle, WM_????, 0, 0);
  end;
  abort;


What I need to know is what WM_ messages to use for the four keys. I can't find them in the Messages unit. Do you know what I should use here?
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Wed Dec 30, 2009 7:03 pm    Post subject: Reply with quote

I do not understand where is exactly the problem in your code.
Yes, inside OnKeyDown event, you cannot do any operation that destroys the cell inplace editor (for example, moving the caret from this cell to another location).

But do you call your code in OnKeyDown? Why do you need OnKeyDown?
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Wed Dec 30, 2009 7:58 pm    Post subject: Reply with quote

I have pretty well succeeded in virtualizing my very large TRichView documents so as to allow huge document size, but only loading the page you see as well as a couple of pages before and after that.

So on the key down (RVEditKeyDown) event, if a Page Up, Page Down, Arrow Up or Arrow Down is pressed, then I have to ensure that enough "extra" at the top or bottom is available. When it isn't then I may add to the beginning and end of the virtual document and remove any excess from the other end. Then on exit of my RVEditKeyDown event, I can pass control to TRichView's key down processing to now do the movement for the key.

However, since allowing control to pass directly back to TRichView's key down causes an exception, I have to abort that and instead use the PostMessage method to process the key.
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Thu Dec 31, 2009 3:13 am    Post subject: Reply with quote

Oh. Maybe I'm getting it now.

So you are saying that in my OnKeyDown event, for VK_UP, VK_DOWN, VK_PRIOR and VK_NEXT, I should do this:

Code:
    PostMessage(Handle, WM_ExtendView, 0, 0);


and then declare

Code:
const
  WM_ExtendView = WM_USER + 10;
type
  MyForm = class(TForm)
    ...
    procedure WMExtendView(var Msg: TMessage); message WM_ExtendView;


and then call my ExtendView procedure from:

Code:
procedure MyForm.WMExtendView(var Msg: TMessage);
begin
  ExtendView;
end;


Then, it should work with the WMExtendView procedure being called after the RIchView Key handling is completed, instead of before.

I'd have to change my logic to allow it to happen after. I'm not sure if that's easy.
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Thu Dec 31, 2009 9:20 am    Post subject: Reply with quote

Yes, this is a correct solution. You can pass a key code in parameters of PostMessage.
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Mon Jan 04, 2010 6:10 am    Post subject: Reply with quote

We've fixed that little sidetrack problem.

But now I need to get back to the original problem: "Move Selection to Original Position"

I am saving my original position as follows:

Code:
 RVE.GetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo, EndItemOffs, true);
  if RVE.RVData.GetItemStyle(StartItemNo) = rvsTable then begin
    TableRVE := RVE.TopLevelEditor;
    TableRVE.GetSelectionBounds(TableStartRow, TableStartCol, TableRowOffs, TableColOffs, false);
  end;


Then I'm doing something in between, possibly inserting or deleting items before the current selection. While doing that, I update StartItemNo and EndItemNo appropriately and then do a Format.

Now I want to restore the position:

Code:
      RVE.SetSelectionBounds(StartItemNo, StartItemOffs, EndItemNo, EndItemOffs);
      if RVE.GetCurrentItemEx(TRVTableItemInfo, TableRVE, TableItem) then
        TableRVE.SetSelectionBounds(TableStartRow, TableStartCol, TableRowOffs, TableColOffs);


This works perfectly when I'm not in a table. But it doesn't work when I'm in a table.

Do you know what I need to do to get this to set the selection back when the selection is in a table?
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Mon Jan 04, 2010 7:21 pm    Post subject: Reply with quote

In general case, if you cannot store selection as a count of characters from the beginning of the document, you will need to store this information:
[item index of table, row and column]*
StartItemNo, StartItemOffs, EndItemNo, EndItemOffs in the top level editor

*- as many times as many nested tables
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Mon Jan 04, 2010 7:37 pm    Post subject: Reply with quote

Code:
type

  TRVSelection = class
    private
      TableItemNoArr, RowArr, ColArr: array of Integer;
      SelStartNo, SelStartOffs, SelEndNo, SelEndOffs: Integer;
    public
      procedure GetFromRichViewEdit(rve: TCustomRichViewEdit);
      procedure SetToRichViewEdit(rve: TCustomRichViewEdit);
  end;

{ TRVSelection }

procedure TRVSelection.GetFromRichViewEdit(rve: TCustomRichViewEdit);
var rve2: TCustomRichViewEdit;
    Count: Integer;
begin
  Count := 0;
  rve2 := rve;
  while rve2.InplaceEditor<>nil do begin
    rve2 := rve2.InplaceEditor as TCustomRichViewEdit;
    inc(Count);
  end;
  SetLength(TableItemNoArr, Count);
  SetLength(RowArr, Count);
  SetLength(ColArr, Count);

  rve2 := rve;
  Count := 0;
  while rve2.InplaceEditor<>nil do begin
    TableItemNoArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FTableItemNo;
    RowArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FRow;
    ColArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FCol;
    inc(Count);
    rve2 := rve2.InplaceEditor as TCustomRichViewEdit;
  end;
  rve2.RVData.GetSelectionBoundsEx(SelStartNo, SelStartOffs, SelEndNo, SelEndOffs, False);
end;

procedure TRVSelection.SetToRichViewEdit(rve: TCustomRichViewEdit);
var i : Integer;
    RVData: TCustomRVData;
begin
   RVData := rve.RVData;
   for i := 0 to High(TableItemNoArr) do
     RVData := (RVData.GetItem(TableItemNoArr[i]) as TRVTableItemInfo).
       Cells[RowArr[i], ColArr[i]].GetRVData;
   RVData := RVData.Edit;
   TCustomRVFormattedData(RVData).SetSelectionBounds(SelStartNo, SelStartOffs, SelEndNo, SelEndOffs);
   TCustomRVFormattedData(RVData).Invalidate;
end;
Back to top
View user's profile Send private message Visit poster's website
lkessler



Joined: 01 Sep 2005
Posts: 96
Location: Winnipeg, Manitoba, Canada

PostPosted: Tue Jan 05, 2010 4:56 am    Post subject: Reply with quote

Sergey. Thank you exceptionally much for drafting out the code. Looking at it as a class, and what you are doing in there is something I would never have thought up.

I implemented it like this:

Code:
var
  CurrentSelection: TRVSelection;

...
  CurrentSelection.GetFromRichViewEdit(RVE);
...
  (code that adds and/or deletes items before the selection)
  RVE.Format;
...
  CurrentSelection.SetToRichViewEdit(RVE); 


I tried it in my program and immediately came up with two problems.

First, I got an access violation on the line:

Code:
 SetLength(RowArr, Count);


Since I know I do not have tables nested in my tables, I changed:

Code:
      TableItemNoArr, RowArr, ColArr: array of Integer;


to

Code:
      TableItemNoArr, RowArr, ColArr: array [0..1] of Integer;


and I commented out the 3 SetLength statements:

Code:
//  SetLength(TableItemNoArr, Count);
//  SetLength(RowArr, Count);
//  SetLength(ColArr, Count);


Then I ran it again and got a: "List index out of bounds (53719630)" exception on the line:

Code:
     RVData := (RVData.GetItem(TableItemNoArr[i]) as TRVTableItemInfo).
       Cells[RowArr[i], ColArr[i]].GetRVData;


I did check and High(TableItemNoArr) is 1.

I think the problem is that the particular selection I had was not in a table, so the while loop in the GetFromRichViewEdit routine was not executed and the TableItemNoArr was not set.

Could you please help me fix this to handle the "selection not in a table case".

And actually aren't there 3 different possible selections that need to be handled?
1. Outside of tables
2. One or more full cells in a table
3. Within a cell of a table

Thanks.

Louis
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Tue Jan 05, 2010 8:19 am    Post subject: Reply with quote

It's strange, in my tests this code worked ok for selection outside table.
Of course, if you set a fixed number of elements in the array (2 in your case), this will correspond to two levels of nested tables (because the cycle is to High(array)), so it will fail with another nesting level.

Yes, my code ignores the case of multicell selection.

I'll create a fixed version.
Back to top
View user's profile Send private message Visit poster's website
Sergey Tkachenko
Site Admin


Joined: 27 Aug 2005
Posts: 10717

PostPosted: Tue Jan 05, 2010 8:51 am    Post subject: Reply with quote

This is a modified version.
For any case, it does not use dynamic arrays, max nesting level is 12 (I know you need only 1, but I wanted to create an universal procedure).
Now it supports multicell selections.
Code:
const MAXNESTINGLEVEL = 12;

type

  TRVSelection = class
    private
      Count: Integer;
      TableItemNoArr, RowArr, ColArr: array [0..MAXNESTINGLEVEL-1] of Integer;
      SelStartNo, SelStartOffs, SelEndNo, SelEndOffs: Integer;
      MultiCell: Boolean;
      StartRow, StartCol, RowOffs, ColOffs: Integer;
    public
      procedure GetFromRichViewEdit(rve: TCustomRichViewEdit);
      procedure SetToRichViewEdit(rve: TCustomRichViewEdit);
  end;

{ TRVSelection }

procedure TRVSelection.GetFromRichViewEdit(rve: TCustomRichViewEdit);
var rve2: TCustomRichViewEdit;
begin
  Count := 0;
  rve2 := rve;
  while (rve2.InplaceEditor<>nil) and (Count<MAXNESTINGLEVEL) do begin
    rve2 := rve2.InplaceEditor as TCustomRichViewEdit;
    inc(Count);
  end;
  rve2 := rve;
  Count := 0;
  while (rve2.InplaceEditor<>nil) and (Count<MAXNESTINGLEVEL) do begin
    TableItemNoArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FTableItemNo;
    RowArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FRow;
    ColArr[Count] := TRVTableInplaceEdit(rve2.InplaceEditor).FCol;
    inc(Count);
    rve2 := rve2.InplaceEditor as TCustomRichViewEdit;
  end;
  MultiCell := (rve2.RVData.PartialSelectedItem<>nil) and
    (rve2.RVData.PartialSelectedItem is TRVTableItemInfo);
  if MultiCell then begin
    TRVTableItemInfo(rve2.RVData.PartialSelectedItem).GetSelectionBounds(
      StartRow, StartCol, RowOffs, ColOffs);
    SelStartNo := TRVTableItemInfo(rve2.RVData.PartialSelectedItem).GetMyItemNo;
    end
  else
    rve2.RVData.GetSelectionBoundsEx(SelStartNo, SelStartOffs, SelEndNo, SelEndOffs, False);
end;

procedure TRVSelection.SetToRichViewEdit(rve: TCustomRichViewEdit);
var i : Integer;
    RVData: TCustomRVData;
begin
   RVData := rve.RVData;
   for i := 0 to Count-1 do
     RVData := (RVData.GetItem(TableItemNoArr[i]) as TRVTableItemInfo).
       Cells[RowArr[i], ColArr[i]].GetRVData;
   RVData := RVData.Edit;
   if MultiCell then begin
     TCustomRVFormattedData(RVData).SetSelectionBounds(SelStartNo,1,SelStartNo,1);
     (TCustomRVFormattedData(RVData).GetItem(SelStartNo) as TRVTableItemInfo).
       Select(StartRow, StartCol, RowOffs, ColOffs)
     end
   else
     TCustomRVFormattedData(RVData).SetSelectionBounds(SelStartNo, SelStartOffs, SelEndNo, SelEndOffs);
   TCustomRVFormattedData(RVData).Invalidate;
end;
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    trichview.com Forum Index -> Support All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group