Page 1 of 1
Traversing hyperlinks
Posted: Thu Mar 22, 2007 4:24 pm
by momsoft
Hi,
I have a document loaded in a TRichViewEditor (in ReadOnly mode) with many hyperlinks, both in text and in tables. I'd like to traverse the list of hyperlinks to replace text and replace the formatting of the hyperlinks:
Something like (in pseudocode):
Code: Select all
for i := 1 to Hyperlinks.Count do
if Hyperlink.Tag = ATag then begin
Hyperlink.BackColor := clNavy;
Hyperlink.Color := clYellow;
end;
and,
Code: Select all
for i := 1 to Hyperlinks.Count do
if Hyperlink.Tag = ATag then
Hyperlink.Text := NewText;
Is this possible?
Thank you very much in advance,
- Manuel Onate
Posted: Fri Mar 23, 2007 12:19 pm
by Michael Pro
As it's said in help
ReadOnly
...
This property does not affect behavior of methods introduced in TRichView.
All RichView methods are still working.
This means, that you have to cycle through all items and make something like this
Code: Select all
if GetItemStyle(i) >= 0 then //Check for text style
if (Style.TextStyles[GetItemStyle(StartNo)].Jump) and (GetItemTag(i) = ATag) then //Check for assigned jump and for tags equality
SetItemText(i, <newtext>);
This code had to work with text items correctly, but not with tables - actually, I didn't work with tables in RichView and didn't examine, how to get styles from it.
In case of changing hyperlink color it's more difficult - you need to create new text style with new color parameters, check if any equal style exists, add it, if not found and change item style in RVData. It could affect formatting of document - I did smth in my project, but it's not so simple.
By the way, you didn't wrote pseudocode in right way, because hyperlinks in text are also text items - and the main conception is to cycle through all items in RichView, checking styles of current item.
Posted: Tue Mar 27, 2007 6:30 pm
by Sergey Tkachenko
Code: Select all
{ Returns (and creates, if required) text style having all properties of
the StyleNo-th style, but yellow on navy }
function GetNewLinkStyleNo(RVStyle: TRVStyle; StyleNo: Integer): Integer;
var TextStyle: TFontInfo;
begin
TextStyle := TFontInfo.Create(nil);
TextStyle.Assign(RVStyle.TextStyles[StyleNo]);
TextStyle.Color := clYellow;
TextStyle.BackColor := clNavy;
TextStyle.HoverColor := clYellow;
TextStyle.HoverBackColor := clNavy;
Result := RVStyle.TextStyles.FindSuchStyle(StyleNo, TextStyle,
RVAllFontInfoProperties);
if Result<0 then begin
RVStyle.TextStyles.Add;
Result := RVStyle.TextStyles.Count-1;
RVStyle.TextStyles[Result].Assign(TextStyle);
RVStyle.TextStyles[Result].Standard := False;
end;
TextStyle.Free;
end;
procedure ChangeLinks(RVData: TCustomRVData);
var i,r,c, StyleNo: Integer;
Table: TRVTableItemInfo;
begin
for i := 0 to RVData.ItemCount-1 do begin
StyleNo := RVData.GetItemStyle(i);
if (StyleNo>=0) and RVData.GetRVStyle.TextStyles[StyleNo].Jump and
(StrComp(PChar(RVData.GetItemTag(i)), 'test')=0) then begin
RVData.SetItemTextA(i, 'New Text');
RVData.GetItem(i).StyleNo := GetNewLinkStyleNo(RVData.GetRVStyle, StyleNo);
end
else if StyleNo=rvsTable then begin
Table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to Table.RowCount-1 do
for c := 0 to Table.ColCount-1 do
if Table.Cells[r,c]<>nil then
ChangeLinks(Table.Cells[r,c].GetRVData);
end;
end;
end;
Test:
Code: Select all
with RichViewEdit1 do begin
SetSelectionBounds(0, GetOffsBeforeItem(0), 0, GetOffsBeforeItem(0));
ChangeLinks(RVData);
ClearUndo;
Format;
end;
This code assumes that rvoTagsArePChars is included in RichViewEdit1.Options (tags are compared as strings). If tags are integers, change
Code: Select all
(StrComp(PChar(RVData.GetItemTag(i)), 'test')=0)
to
Posted: Wed Apr 25, 2007 8:37 pm
by momsoft
Sorry for the delay in answering. I thought I had solved my needs by using code like the one below, and forgot to check the forum.
Code: Select all
procedure TfmMain.EnumMark(RVData: TCustomRVData; ItemNo: Integer; var UserData1: Integer;
const UserData2: String; var ContinueEnum: Boolean);
// Mark all Jumps with Tag = UserData1 as Selected and the rest as Normal
var
IsLink : Boolean;
ATag,OldStyle,NewStyle,L,T : integer;
begin
IsLink := RVData.GetItem(ItemNo).GetBoolValueEx(rvbpJump,RVData.GetRVStyle);
if IsLink then begin
ATag := RVData.GetItemTag(ItemNo) - 1; // Tags are 1-based
OldStyle := RVData.GetItemStyle(ItemNo);
if ATag = UserData1 then begin
NewStyle := GetSelectedStyle(Styles,OldStyle)
end else
NewStyle := GetNormalStyle(Styles,OldStyle);
RVData.GetItem(ItemNo).StyleNo := NewStyle;
end;
end;
procedure TfmMain.EnumSelect(RVData: TCustomRVData; ItemNo: Integer; var UserData1: Integer;
const UserData2: String; var ContinueEnum: Boolean);
// Scroll to the NumInstance Instance of UserData1 Field
var
IsLink : Boolean;
ATag,L,T : integer;
s : String;
begin
IsLink := RVData.GetItem(ItemNo).GetBoolValueEx(rvbpJump,RVData.GetRVStyle);
if IsLink then begin
ATag := RVData.GetItemTag(ItemNo) - 1; // Tags are 1-based
If ATag = UserData1 then begin //
Inc(CurrInstance);
if CurrInstance = NumInstance then begin
Preview.GetItemCoords(ItemNo,L,T);
s := Preview.GetItemTextA(ItemNo);
T := T - Preview.Height div 2; if T < 0 then T := 0;
Preview.ScrollTo(T);
// Select the item
Preview.SetSelectionBounds(ItemNo,0,ItemNo,Length(s)+1);
ContinueEnum := False; // Stop the iteration
end;
end;
end;
end;
EnumMark and EnumSelect are called with the EnumItems method of the RVData object of the RichView
GetSelectedStyle and GetNormalStyle are similar to your suggested GetNewLinkStyleNo function.
EnumMark works as intended.
EnumSelect works perfectly when the richview does not contain tables, but it fails when there are tables. The reason is that the GetItemCoords gives me the position of the item relative to the top of the cell rather than to the top of the document.
What do you suggest?
Posted: Thu Apr 26, 2007 6:42 am
by Sergey Tkachenko
ItemNo is an item index inside RVData parameter. If RVData is a table cell (or cell inplace editor's RVData), you cannot use ItemNo to access items in Preview.
Selecting:
Code: Select all
RVData := RVData.Edit;
TCustomRVFormattedData(RVData).SetSelectionBounds(ItemNo,
RVData.GetOffsBeforeItem(ItemNo), ItemNo, RVData.GetOffsAfterItem(ItemNo));
As for scrolling:
Code: Select all
var OL, OT: Integer;
RVData.GetItemCoords(ItemNo, L, T);
RVData.GetOriginEx(OL, OT);
T := OT + T - Preview.Height div 2;
if T < 0 then
T := 0;
Preview.ScrollTo(T);
Posted: Thu Apr 26, 2007 6:00 pm
by momsoft
Sergey,
Thank you very much for your prompt reply. The scrolling part works perfectly. The selection doesn't.
If I add the line: RVData := RVData.Edit; as per your suggestion, I get a List Index Out of Bounds exception in the function TCustomRVData.EnumItems when I try to select an item contained inside a table, the exception occurs in this line.
Result := RVData.GetRVData.EnumItems(Proc, UserData1, UserData2);
I hope this information helps you to determine the error.
Posted: Sat Apr 28, 2007 11:22 am
by Sergey Tkachenko
Well, really, it was not expected in EnumItems that some RVData is moved to the editing state.
So use cycle, as in my example above.
Posted: Wed May 02, 2007 9:12 am
by momsoft
Sergey,
Sorry. I don't understand you. What do you mean by 'use cycle'.
Thank you,
- Manuel Onate
Posted: Wed May 02, 2007 12:58 pm
by Sergey Tkachenko
I mean a procedure like ChangeLinks, see above in this topic.