Moving footnotes to the end of a document

General TRichView support forum. Please post your questions here
Post Reply
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Moving footnotes to the end of a document

Post by jgkoehn »

How would you recommend moving footnotes to the end of a document? I can already click on a footnote number in text and pull it up. But I need to bring all footnotes to the end of a document. Thanks.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

Do you want to convert footnotes to endnotes? All of them, or only the selected note? Undoable by the user?
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

Basically convert all footnotes to end notes and not undo able it needs to be permanent.

Here is what we are doing. We bring in an RTF document to RichViewEdit. Parse through various parts that will be future topic sections. Now each topic section may have footnotes. We need to then add those footnotes to the end of the topic section.

So I'm working with two RichViewEdits lets call them RVE-whole and RVE-topic
RVE-whole has the whole document with various areas like <:> this indicates a new topic section.
I've already broken down the RVE-whole into topic sections now that topic section is loaded in RVE-topic and then further modified then saved to an SQL database. So here in RVE-topic I need to take the footnotes and move them to the end. I could load the footnotes into another RVE-footnote or RTFStream then add that content to the end of RVE-topic.

My concern is how to go through all the footnotes in that topic section. Do I just run through all the "items" check if it has a footnote and then add it to RVE-footnote. Once all items have been processed add that to RVE-topic? Thoughts?

By the way most of this is already done mainly need to move footnotes to end and have them still be connected to their numbers. (I would love to renumber them per section but understand if that would get really complicated.)
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

I got quite a ways but I'm having trouble with a footnote number inside of a table. (I thought I had seen something in the forum about this but I can't find it.)
Here is my code:

Code: Select all

    note_cnt := 0;
    for notes_i := 0 to RichViewEditClean.ItemCount-1 do
      if RichViewEditClean.GetItem(notes_i) is TCustomRVNoteItemInfo then
        begin
        //Add footnote(s):
        if FootNoteBool = False then RichViewEditClean.AppendFrom(footnoteRVE);
        //Add bookmark to a number here.
        inc(note_cnt);
        RichViewEditClean.Add(#10,0);
        RichViewEditClean.AddCheckpoint('fn' + IntToStr(note_cnt), True, 'fn' + IntToStr(note_cnt));
        RichViewEditClean.Add(IntToStr(note_cnt),1);
        AddNote(RichViewEditClean.GetItem(notes_i) as TCustomRVNoteItemInfo);
        //Remove footnote from RichViewEditClean.GetItem(notes_i)
        RichViewEditClean.SetSelectionBounds(notes_i, RichViewEditClean.GetOffsBeforeItem(notes_i), notes_i, RichViewEditClean.GetOffsBeforeItem(notes_i));
        RichViewEditClean.DeleteItems(notes_i, 1);
        //Set item as a bookmark link
        RichViewEditClean.InsertText(IntToStr(note_cnt), TRUE);
        RichViewEditClean.SearchTextW(IntToStr(note_cnt), [rvseoMatchCase, rvseoDown, rvseoMultiItem]);
        RichViewEditClean.ApplyStyleConversion(CONVERT_TO_SUPER_HYPERTEXT);

        //tw://[self]?tid=1#fn1-
        SetTargetToSelection('tw://[self]?tid=' +IntToStr(topic_sub_i) + '#fn' + IntToStr(note_cnt)+'-');

        FootNoteBool := True;
      end;
   RichViewEditClean.Format;
giovani.erthal
Posts: 9
Joined: Thu Dec 27, 2018 1:48 am

Re: Moving footnotes to the end of a document

Post by giovani.erthal »

jgkoehn wrote: Thu Mar 26, 2020 9:31 pm I got quite a ways but I'm having trouble with a footnote number inside of a table. (I thought I had seen something in the forum about this but I can't find it.)
Here is my code:

Code: Select all

    note_cnt := 0;
    for notes_i := 0 to RichViewEditClean.ItemCount-1 do
      if RichViewEditClean.GetItem(notes_i) is TCustomRVNoteItemInfo then
        begin
        //Add footnote(s):
        if FootNoteBool = False then RichViewEditClean.AppendFrom(footnoteRVE);
        //Add bookmark to a number here.
        inc(note_cnt);
        RichViewEditClean.Add(#10,0);
        RichViewEditClean.AddCheckpoint('fn' + IntToStr(note_cnt), True, 'fn' + IntToStr(note_cnt));
        RichViewEditClean.Add(IntToStr(note_cnt),1);
        AddNote(RichViewEditClean.GetItem(notes_i) as TCustomRVNoteItemInfo);
        //Remove footnote from RichViewEditClean.GetItem(notes_i)
        RichViewEditClean.SetSelectionBounds(notes_i, RichViewEditClean.GetOffsBeforeItem(notes_i), notes_i, RichViewEditClean.GetOffsBeforeItem(notes_i));
        RichViewEditClean.DeleteItems(notes_i, 1);
        //Set item as a bookmark link
        RichViewEditClean.InsertText(IntToStr(note_cnt), TRUE);
        RichViewEditClean.SearchTextW(IntToStr(note_cnt), [rvseoMatchCase, rvseoDown, rvseoMultiItem]);
        RichViewEditClean.ApplyStyleConversion(CONVERT_TO_SUPER_HYPERTEXT);

        //tw://[self]?tid=1#fn1-
        SetTargetToSelection('tw://[self]?tid=' +IntToStr(topic_sub_i) + '#fn' + IntToStr(note_cnt)+'-');

        FootNoteBool := True;
      end;
   RichViewEditClean.Format;
To access the table cells, you need:

Code: Select all

DoSomething( RichViewEditClean.RVData );

Code: Select all

procedure DoSomething(RVData: TCustomRVData);
var 
  i, r, c : Integer;
  table: TRVTableItemInfo;
begin
  i := RVData.ItemCount - 1;

  while i >= 0 do 
  begin
    if RVData.GetItemStyle( i ) in [ rvsFootnote, rvsEndnote, rvsSidenote, rvsTextBox ] then
    begin
      // your code
    end
    else if RVData.GetItemStyle( i ) = rvsTable then 
    begin
      table := TRVTableItemInfo( RVData.GetItem( i ) );

      for r := 0 to ( table.Rows.Count - 1 ) do
        for c := 0 to ( table.Rows[r].Count - 1 ) do
          if ( table.Cells[ r, c ] <> nil ) then
            DoSomething( table.Cells[ r, c ].GetRVData );    
    end;

    Dec(i);
  end;
end;
I wish I could help you more effectively, however at the moment I don't have Trichview installed.
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

Thank you that is very helpful!

In the table data however I need to be able to edit it. If I save it to a RVFStream so I can load it in a RichViewEditor to eidt it gets quite complicated because the Stream wants various information.

Is there a simple way to load the table info or edit the table info? I can grab the footnote which is excellent but I need to swap out the footnote number in the table.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

Sorry for the delay, I yesterday returned from a hospital (nothing serious, but it took some time).

Your original code has several problems
1) Do not use AppendFrom, this method can copy not all kinds of items. Instead, save the document to a stream and use AppendRVFFromStream.
2) You use a mix of viewer-style methods (Add, AddCheckpoint, DeleteItems) and editing methods (InsertText, ApplyStyleConversion). It is highly not recommended. If you do not need a possibility to undo this operation, I recommend to use only viewer-style methods. There is no method to insert a text item at the specified location, but there is a function RVInsertString from RVInsertItems.pas.

My code will be in the text message.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

Code: Select all

uses RVTable, RVNote, CRVData, RVInsertItems;

// Adds Note's text to the end of document containing RVData.
// note_cnt will be inserted before the Note's text.
procedure AddNoteInfo(RVData: TCustomRVData; Note: TCustomRVNoteItemInfo;
  note_cnt: Integer);
var
  Stream: TMemoryStream;
  RootRVData: TCustomRVData;
  Color: TColor;
begin
  RootRVData := RVData.GetAbsoluteRootData;
  Stream := TMemoryStream.Create;
  try
    RootRVData.AddCheckpoint('fn' + IntToStr(note_cnt), True, 'fn' + IntToStr(note_cnt));
    RootRVData.AddNL(IntToStr(note_cnt), RVGetNoteTextStyleNo(RVData.GetRVStyle, 0), 0);
    RootRVData.AddNL(' ',0);
    Note.Document.SaveRVFToStream(Stream);
    Stream.Position := 0;
    RootRVData.AppendRVFFromStream(Stream, -1, Color, nil);
  finally
    Stream.Free;
  end;
end;

// Deletes the ItemNo-th item from RVData
procedure DeleteNote(RVData: TCustomRVData; ItemNo: Integer);
var
  FNL: Boolean;
begin
  FNL := RVData.IsFromNewLine(ItemNo);
  RVData.DeleteItems(ItemNo, 1);
  if RVData.ItemCount = 0 then
  begin
    RVData.AddNL('', 0, 0);
    exit;
  end;
  if FNL and (ItemNo < RVData.ItemCount) then
    RVData.GetItem(ItemNo).SameAsPrev := False;
end;

// Returns the index of text style in RVStyle. This style has all properties
// of the StyleNo-th style, but it is hypertext, blue and underlined
function GetNoteHypertextStyleNo(RVStyle: TRVStyle; StyleNo: Integer): Integer;
var
  TextStyle: TFontInfo;
begin
  TextStyle := TFontInfo.Create(nil);
  try
    TextStyle.Assign(RVStyle.TextStyles[StyleNo]);
    TextStyle.Color := clBlue;
    TextStyle.Style := TextStyle.Style + [fsUnderline];
    TextStyle.Jump := True;
    Result := RVStyle.FindTextStyle(TextStyle);
  finally
    TextStyle.Free;
  end;
end;

// Converts a note (the ItemNo-th item in RVData) to a hyperlink
procedure ConvertNoteToText(RVData: TCustomRVData; ItemNo, note_cnt: Integer);
var
  ParaNo, StyleNo: Integer;
begin
  if RVData.IsFromNewLine(ItemNo) then
    ParaNo := RVData.GetItemPara(ItemNo)
  else
    ParaNo := -1;
  StyleNo := GetNoteHypertextStyleNo(RVData.GetRVStyle,
    TCustomRVNoteItemInfo(RVData.GetItem(ItemNo)).TextStyleNo);
  RVData.DeleteItems(ItemNo, 1);
  RVInsertString(RVData, ItemNo, IntToStr(note_cnt), StyleNo, ParaNo,
    'tw://[self]?tid=SOMETHING#fn' + IntToStr(note_cnt)+'-');
end;

// Converts all notes in RVData (and all tables inside it) to hyperlinks,
// and add their text to the end of the root document
procedure ProcessNotes(RVData: TCustomRVData; var note_cnt: Integer);
var
  i, r, c: Integer;
  Table: TRVTableItemInfo;

begin
  for i := RVData.ItemCount - 1 downto 0 do
    if RVData.GetItem(i) is TRVTableItemInfo 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
            ProcessNotes(Table.Cells[r, c].GetRVData, note_cnt);
    end
    else if RVData.GetItem(i) is TCustomRVNoteItemInfo then
    begin
      inc(note_cnt);
      AddNoteInfo(RVData, TCustomRVNoteItemInfo(RVData.GetItem(i)), note_cnt);
      ConvertNoteToText(RVData, i, note_cnt);
    end;
end;

// Delete all note references from RVData. They may appear when we copied
// note documents to the end of the document
procedure DeleteNoteRefs(RVData: TCustomRVData);
var
  i: Integer;
begin
  for i := RVData.ItemCount - 1 downto 0 do
    if RVData.GetItem(i) is TRVNoteReferenceItemInfo then
      DeleteNote(RVData, i);
end;

// How to use
procedure TForm3.ToolButton12Click(Sender: TObject);
var
  note_cnt: Integer;
begin
  note_cnt := 0;
  ProcessNotes(RichViewEdit1.RVData, note_cnt);
  if note_cnt > 0 then
  begin
    DeleteNoteRefs(RichViewEdit1.RVData);
    RichViewEdit1.ClearUndo;
    RichViewEdit1.Format;
  end;
end;
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

But the simplest solution would be a conversion of all footnotes (TRVFootnoteItemInfo) to endnotes (TRVEndnoteItemInfo).
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

Sounds like a good idea since endnotes are in document. How can I do this?

Would this also update the numbers? Since I am basically turning the document into multiple smaller documents and savig it to an sqlite.
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

Endnotes are numbered sequentially. But you can define the number for some endnote (or all endnotes) explicitly (in the endnote constructor, specify the number in StartFrom parameter, and pass True to Reset parameter).
By default, endnotes are numbered using lower Roman numbers (i, ii, iii, etc.). You can change the numbering style in RVStyle.EndnoteNumbering property.

Like footnotes, endnotes are not shown in TRichView. They are visible only on printing/print preview (and in ScaleRichView editor).
Sergey Tkachenko
Site Admin
Posts: 17564
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Moving footnotes to the end of a document

Post by Sergey Tkachenko »

Here is the code for converting all footnotes to endnotes.

Code: Select all

uses RVNote, CRVData, RVInsertItems;

// Converts the footnote (the ItemNo-th item in RVData) to an endnote
procedure FootnoteToEndnote(RVData: TCustomRVData; ItemNo: Integer);
var
  Stream: TMemoryStream;
  Footnote: TRVFootnoteItemInfo;
  Endnote: TRVEndnoteItemInfo;
  S: TRVUnicodeString;
begin
  Footnote := RVData.GetItem(ItemNo) as TRVFootnoteItemInfo;
  Endnote := TRVEndnoteItemInfo.CreateEx(RVData, Footnote.TextStyleNo, Footnote.StartFrom,
    Footnote.Reset);
  if RVData.IsFromNewLine(ItemNo) then
    Endnote.ParaNo := Footnote.ParaNo
  else
    Endnote.ParaNo := -1;
  Stream := TMemoryStream.Create;
  try
    S := RVData.GetItemTextW(ItemNo);
    Footnote.Document.SaveRVFToStream(Stream);
    Stream.Position := 0;
    Endnote.Document.LoadRVFFromStream(Stream);
  finally
    Stream.Free;
  end;
  RVData.DeleteItems(ItemNo, 1);
  RVInsertItem(RVData, ItemNo, S, Endnote);
  RVData.AddSeqInList(ItemNo);
end;


// Converts all footnotes in RVData (and all tables inside it) to endnotes
procedure ProcessNotes(RVData: TCustomRVData);
var
  i, r, c: Integer;
  Table: TRVTableItemInfo;
begin
  for i := RVData.ItemCount - 1 downto 0 do
    if RVData.GetItem(i) is TRVTableItemInfo 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
            ProcessNotes(Table.Cells[r, c].GetRVData);
    end
    else if RVData.GetItem(i) is TRVFootnoteItemInfo then
    begin
      FootnoteToEndnote(RVData, i);
    end;
end;

// How to use
procedure TForm3.ToolButton12Click(Sender: TObject);
begin
  ProcessNotes(RichViewEdit1.RVData);
  RichViewEdit1.ClearUndo;
  RichViewEdit1.Format;
end;
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

Thank you very much. That will make the process easlet.
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

Oh, I missed that endnotes are not show in the TRichView.
That is what I need. so I will check your previous code. Thanks again
jgkoehn
Posts: 303
Joined: Thu Feb 20, 2020 9:32 pm

Re: Moving footnotes to the end of a document

Post by jgkoehn »

The previous code is working excellently. Thank you.
Post Reply