How do I build TOC and index (Delphi)

  • Hi
    I am in the process of building a book with wptools in Delphi. I have to obtain the contents from various database fields and build it into a book. I need to be able to dynamically create a table of contents and an Index.

    Can anyone please tell me how to do this ?

    Thanks

    David

  • As the built in TOC was too unflexible for me I decided to build up one myself :)

    Before Building the document add a Paragraph and save a Pointer to it (TOCParagraph)

    As I'm only using paragraphs to build my Document I used the TParagraph.Name Property to seperate Headlines from Text

    e.g. when building the Document and you got a Headline (In my Document I've only got 2 Levels) name the Paragraph "Head_<Counter>".
    each sublevel gets a different prefix (to recognise which format to use)

    Like:

    A. Big Chapter One! -> Name: Head_1
    A.1 Subchapter One! -> Name: Subhead_1_1
    and so on

    then build your Document

    now run through all paragraphs and search the name for the prefixes. Each time you find an specific prefix append a new Paragraph to your saved TOC Paragraph. You can get the Text via the Paragraph.GetText () function.
    Mark the appended TOCParagraph with toc_ + Paragrpah.Name (so you later know which Content Entry this TOC Entry is related to)

    After doing through the all paragraphs again and search for toc_*. If you find one extract the original paragraph name and run through all paragraphs to determine the page the actual paragraph is on.
    Append the pagenr to the TOC paragraph.

    et voilá a wonderful TOC which is fully formatable =)

    headcounter and subheadcounter are global variables and should be reset each time you rebuild the document.

    Appending a Headline:

    Code
    TParagraph *par;  par = target->LastPar->AppendNewPar(true);  par->ASet(WPAT_Alignment,Integer(paralLeft));  par->ASet(WPAT_IndentLeft,500);  par->ASet(WPAT_ParIsOutline,1);  par->Name = "head_" + IntToStr(++headcounter);  if( NewPage )    par->prop = par->prop <<paprNewPage>SetText(Text,headline);  target->CPPosition = MaxInt;  // Possibility to jump to headline via BookmarkMoveTo();  target->BookmarkInput("head_" + IntToStr(headcounter));

    Appending Subheadline:

    Code
    TParagraph *par;  par = target->LastPar->AppendNewPar(true);  par->ASet(WPAT_Alignment,Integer(paralLeft));  par->ASet(WPAT_IndentLeft,500);  par->ASet(WPAT_ParIsOutline,1);  par->Name = "subhead_" + IntToStr(headcounter) + "_" + IntToStr(++subheadcounter);  par->SetText(Text,subheadline);  target->CPPosition = MaxInt;  target->BookmarkInput("subhead_" + IntToStr(headcounter) + "_" + IntToStr(subheadcounter));

    Building Document and TOC

    Hope I could help :) Sure this is not the best way to build a TOC but it works :P

    P.S.: Oups just saw that you asked for an Delphi example... well I hope it should be no Problem to translate my example to Delphi. Functions and important Member Names are the same is in Delphi

  • Thanks for that reply. I will certainly give it a shot. No problem about the C++ code.. all pretty much the same anyway.

    You said there is a built in TOC too?? i have not found that in the documentation ..

    Regards

    David

  • Got it thanks...
    The documentation is rather sparse isnt it..!!
    I tried using it but the page numbers are all at 1!!!

    I also tried your code, but it does not seem to work.. I get one table of contents entry and thats it... perhaps I have translated it incorrectly to delphi, but I dont think so...

    Any thoughts??

    Thanks
    David

    • Offizieller Beitrag

    Many thanks to fanderlf for the help!

    I have now the possibility to add some comments:

    Yes, CreateTableOfContents is a good way to start. It can be seen as an example implementation, too.

    It implements one possibility to create a TOC by using a certain attribute of the paragraphs. If you have trouble to find an information in the HLP file pleasye don't mind to check out the source code. (I do not think the refrence is "sparse", for technical reasons it has a lot of nodes though. The PDF does not talk about any of the 1000 aspects WPTools has)

    Esspecially the unit WPCtrRich and WPCtrMemo implement high level routines and should be mostly readable. A must-read is the method OnToolbarIconSelection in WPCtrRich.

    CreateTableOfContents uses this modes:

    Code
    TWPCreateTableOfContentsMode = set of (
        wptocAlsoProcessTables, // Also look in tables for marked paragraphs. Only the first paragraph of a cell is checked!
        wptocCreateHyperlinks, // Create hyperlinks for the headlines
        wptocLocateTextAfterBookmark, // use the text after bookmarks as headline
        wptocUseParIsOutline, // only use paragraphs which use the WPAT_ParIsOutline attribute
        wptocCreateOutlineBookmarks, // if WPAT_ParIsOutline then create bookmark if not existing
        wptocCreateHyperlinkNumbers // Place the page numbers in hyperlinks
        );

    CreateTableOfContents is documented in the HLP and online:


    (You can google it!)

    This code can be used to mark a paragraph which should be used as headline:

    WPRichText1.ActiveParagraph.ASet(WPAT_ParIsOutline,1);

    Since
    par.AGetInherited(WPAT_ParIsOutline, outl)

    is used to check it, the flag can be also applied to a paragraph style which has been assigned to a paragraph!

    Julian

  • Hi Julian
    thanks for your response.
    When I said the documentation is sparce, I am meaning the explanation of HOW to do things, and in many cases the help file simply gives the name of the property/method withiout any explanation of how to use it. Often you have methods with parameters such as ASet which do not explain properly what values are to go in the Value parameter.

    With regards to the TOC..
    I am now getting a TOC to appear, but am still not being able to get it formatted nicely at all. It is essential for me to be able to have a properly formatted book. This project is a very high level government project with the result being a book which is distributed to every doctor in the country.
    I wish to have a nicely formatted table of contents but when I have tried to apply a style to the paragraph, I see no change at all. I seem to have no control over the TOC. I am also not quite sure of the following :
    If I apply a par.ASet(WPAT_ParIsOutline,1) to my paragraph, what does it do? Does this make it a header? And I am assuming that by header it is a single line which will preceed the main paragraph. Does this have to be a paragraph on its own followed by the body paragraph?

    I also need to be able to generate an index. Is this possible?
    Thanks..

    David

    • Offizieller Beitrag
    Zitat

    If I apply a par.ASet(WPAT_ParIsOutline,1) to my paragraph, what does it do? Does this make it a header? And I am assuming that by header it is a single line which will preceed the main paragraph. Does this have to be a paragraph on its own followed by the body paragraph?

    It simply markes it. In the CreateTableOfContents method it collects all those paragraphs and creates new text from it. That text is inserted in a certaion field to make it possible to update.

    I believe you should check out that source code and create your TOX yourself. You see how it connects the reference objects to bookmark names in the code, too.

    Julian

  • Hi
    I am having endless problems trying to get the TOC to work properly despite all your efforts to provide help!

    I am loading a block of text (rtf format) and a title from a database field. I am using the title as the headline of the paragraph and then adding the rtf as the subsequent paragraph for it.
    I require the headline tobe part of the TOC.

    When I run it sometimes I only get the LAST headline in my TOC and nothing else. Other times it works but when I try and provide a specific formatting for the TOC it does nothing at all.
    I am doing the following : Any help appreciated

    Thanks
    David


    contSty := WPRichText1.parStyles.Addstyle('Contents');
    contSty.ASetFontName('Times New Roman');
    contSty.ASet(WPAT_CharFontSize,8);

    TOCParagraph := WPRichText1.ActiveParagraph;
    TOCParagraph.ABaseStyle := contSty;
    WPRichText1.reformatall(true,true);
    WPRichText1.InputMergeField(WPTOC_FIELDNAME,'TOC Created here');
    WPRichText1.InputString(#12#13);

    for x := 0 to 10 do
    Begin
    buildheader(dmDataConverter.qryGetNotesTITLE.AsString);
    dmDataConverter.qryGetNotes.next;
    End;

    if WPRichText1.FieldExists(WPTOC_FIELDNAME) then
    begin
    i := WPRichText1.TextCursor.DropMarker;
    WPRichText1.CreateTableOfContents('','_Toc', [wptocUseParIsOutline,
    wptocCreateOutlineBookmarks,wptocCreateHyperlinkNumbers],
    nil,'');
    WPRichText1.TextCursor.GotoMarker(i);
    //trying to set the TOC style!!! Doesnt work...
    currpar := WPRichText1.ActiveParagraph;
    currpar.ABaseStyle := contSty;
    WPRichText1.reformatall(true,true);
    end;


    WPRichText1.reformatall(true,true);
    WPRichText1.invalidate;
    end;

    Procedure TfrmDataConverter.buildheader(text : String);
    Var
    par : TParagraph;
    begin
    par := WPRichText1.LastPar.AppendNewPar(true);
    par.ASet(WPAT_ParIsOutline,1);
    par.loadfromstring(text,[wploadpar_UseWritingAttr] );
    WPRichText1.CPPosition := MaxInt;
    end;

    • Offizieller Beitrag

    Hi,

    a)

    //trying to set the TOC style!!! Doesnt work...
    currpar := WPRichText1.ActiveParagraph;
    currpar.ABaseStyle := contSty;
    WPRichText1.reformatall(true,true);

    This should work if the text itself does not use a character attribute, which is probably does. If it does the attribute from the style is not used.

    par.ClearCharAttr clears the attributes and so a paragraph style can be used. Outher options are available though par.SetStyle

    b)

    par := WPRichText1.LastPar.AppendNewPar(true);
    par.ASet(WPAT_ParIsOutline,1);
    par.loadfromstring(text,[wploadpar_UseWritingAttr] );
    WPRichText1.CPPosition := MaxInt;

    Here you are overwriteing the attribute. I would use

    par.SetText( text ) for your title.

    If you then need to add a text blob use

    WP.InputString(#13)
    WP.SelectionAsString := stringdata

    Normally par.loadfromstring is notr used. It has its special poppose for nested paragraphs.

  • Hi . Thanks for your post, however it still does not work.
    When I use settext to set the header, thats fine, and shows the header, however if I then use

    currpar := WPRichText1.ActiveParagraph;
    currpar := WPRichText1.ActiveParagraph.AppendNewPar(true);
    WPRichText1.InputString(#13); WPRichText1.selectionasString :=dmDataConverter.qryGetNotesRTFDESCRIPTION.AsString;

    to add the contents of the blob field (Which is RTF), then the contents uses the first line of this text AND the header line I have created to build the TOC. (The header line comes from a plain text field, not RTF)

    I also STILL cannot get the style of the TOC to work.
    I have done the following : How do I know which paragraph is the TOC paragraph>? Whould this be the correct way fo doing it?

    Is there any "standard" templates for TOCs, like in word for example?
    How can I get the sub headings indented ?

    if WPRichText1.FieldExists(WPTOC_FIELDNAME) then
    begin
    i := WPRichText1.TextCursor.DropMarker;
    currpar := WPRichText1.ActiveParagraph;
    Currpar.ClearCharAttr;
    currpar.ABaseStyle := contSty;
    WPRichText1.CreateTableOfContents('','_Toc',
    [wptocUseParIsOutline,wptocCreateOutlineBookmarks,wptocCreateHyperlinkNumbers],
    nil,'Contents');
    WPRichText1.TextCursor.GotoMarker(i);
    WPRichText1.reformatall(true,true);
    end;


    Thanks

    David

  • Nope... I have that line in


    par.ASet(WPAT_ParIsOutline,1);
    par.settext(text );
    WPRichText1.CPPosition := MaxInt;

    and then

    currpar := WPRichText1.ActiveParagraph;
    currpar := WPRichText1.ActiveParagraph.AppendNewPar(true);
    (dmDataConverter.qryGetNotesRTFDESCRIPTION.AsString );
    WPRichText1.InputString(#13); WPRichText1.selectionasString :=dmDataConverter.qryGetNotesRTFDESCRIPTION.AsString;

  • a small hint from my side, which made the work much easier (at least for me :))

    try to build the text only using AppendNewPar and par->SetText(). I often had trouble mixing the direct input (WPRichtText1.Insert(...)) with paragraph input (par->SetText).

    I've built myself some functions like:

    Code
    TParagraph * __fastcall Tfrm_TestspecData::AppendTextToDocument(TWPRichText *target, AnsiString Text){  TParagraph *par;  par = target->LastPar->AppendNewPar(false);  par->ASet(WPAT_Alignment,Integer(paralLeft));  par->ASet(WPAT_IndentLeft,500);  par->SetText(Text,txtplain);  return par;}

    of for formated text:

    SetIndent sets the leftindent + 500 from the formated text to append (WPRichtText->AsString saved to blob field in DB), because I'm painting a border arround my document :)

  • I think I am doing something similar to what you are trying to do. When building a final report, I add chapter headings and topic headings followed by the actual rtf text. Chapter headings, Topic headings, and rtf body text are all pulled from the database separately and then assembled. I automatically insert code to make both the chapter and topic headings show up in the TOC, and will be hyperlinkable if then output to a PDF file using wPDF. Example code snippets that might help follow. I modified Julian's CreateTableOfContents code to fit my needs, including honoring the margins and indents of where the TOC tag was inserted in the master template and providing for indentation of Chapters vs. Topics and unique font, size and color for each.

    The snippets might not be complete, but hopefully it will help in some way.

    Adding a chapter heading bookmark for TOC creation:

    Code
    with WPRichText1 do      begin        TextCursor.GetCharAttr;        BookmarkInput( '_Toc_' + TNavFolder(node.Data).ID, true );        ActiveParagraph.ASet(WPAT_ParIsOutline,1);        CurrAttr.Size := 1.0; // WPTools 5.20.6 bug "getaround"        InputString(nodeDesc);      end;

    Adding a topic heading bookmark for TOC creation:

    Code
    with WPRichText1 do            begin              TextCursor.GetCharAttr;              BookmarkInput( '_Toc_' + TNavDocument(node.Data).ID, true );              ActiveParagraph.ASet(WPAT_ParIsOutline,2);              CurrAttr.Size := 1.0; // WPTools 5.20.6 bug "getaround"              InputString(nodeDesc);            end;

    Then I call the TOC creation once the report has been assemled:

    Code
    if WPRichText_Rpt.FieldExists(WPTOC_FIELDNAME) then    begin      preTOCPageCnt := WPRichText_Rpt.PageCount;      MyCreateTableOfContents( '', '_Toc_',                                [ wptocUseParIsOutline,                                  wptocCreateHyperlinks ],                                nil, '', nil);

    And then of course the long table of contents creation code: