| View previous topic :: View next topic |
| Author |
Message |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Sat Dec 19, 2009 10:12 pm Post subject: Move Selection to Original Position |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Mon Dec 21, 2009 12:48 pm Post subject: |
|
|
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 |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Tue Dec 22, 2009 5:46 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Sat Dec 26, 2009 5:55 pm Post subject: |
|
|
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 |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Wed Dec 30, 2009 6:11 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Wed Dec 30, 2009 7:03 pm Post subject: |
|
|
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 |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Wed Dec 30, 2009 7:58 pm Post subject: |
|
|
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 |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Thu Dec 31, 2009 3:13 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Thu Dec 31, 2009 9:20 am Post subject: |
|
|
| Yes, this is a correct solution. You can pass a key code in parameters of PostMessage. |
|
| Back to top |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Mon Jan 04, 2010 6:10 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Mon Jan 04, 2010 7:21 pm Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Mon Jan 04, 2010 7:37 pm Post subject: |
|
|
| 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 |
|
 |
lkessler
Joined: 01 Sep 2005 Posts: 95 Location: Winnipeg, Manitoba, Canada
|
Posted: Tue Jan 05, 2010 4:56 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Tue Jan 05, 2010 8:19 am Post subject: |
|
|
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 |
|
 |
Sergey Tkachenko Site Admin
Joined: 27 Aug 2005 Posts: 9845
|
Posted: Tue Jan 05, 2010 8:51 am Post subject: |
|
|
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 |
|
 |
|
|
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
|