Hi, here's a patch against svn trunk revision 1153319.
It contains 3 things, you may want to edit the patch if you don't want all of them:

1. omit table last header/footer patch

2. fix for hyphenation when interletter values in hyphenation patterns are higher than 7. This is a long standing bug, I had submitted this patch before but it hasn't been incorporated it.

3. a patch to make all links into PDF named destinations rather than direct page references. If the link resolves, the page reference is defined otherwise the link is left with only the named destination. This allows to generate PDF in pieces and then use some concatenation tool like iText and the links will work even if in individual files the links do not resolve. I'm not sure if this is needed anymore in current code, but we needed this to generate big PDFs out of pieces some time ago.


Regards,
Carlos

On 8/19/11 10:49 AM, champagne_chary wrote:
Hello, a long time has passed since you posted this.. I would be interested
in a patch for this.

Thanks



Carlos Villegas wrote:
I implemented this extension. I added fox:table-omit-last-footer and
fox:table-omit-first-header attributes to fo:table. It seems to work
well in my use case.
If anyone is interested I can submit a patch.

Cheers,
Carlos

Carlos Villegas wrote:
Thanks for the pointers. I agree that implementing retrieve-table-marker
is not only a more generic solution but also what the spec requires.
However, I'm short on time and this seems easier so I'll give it a try
first.

Regards,
Carlos

Vincent Hennebert wrote:
Hi Carlos,

Carlos Villegas wrote:
Hi,

I searched the mailing lists and it seems that although some people had
worked at several times at trying to implement retrieve-table-marker,
it's not yet done. Is somebody working on this? What's the status?
It’s not being worked on at the moment. This is still a missing feature.


In many use cases omitting the first table header and the last table
footer will do the trick.

How easy is this to implement?
What will be the steps to add such an extension to FOP?
I just started looking at the code so I'm exploring whether this is
viable solution.
That might work. You would need to change the
o.a.f.layoutmgr.table.TableContentLayoutManager.getNextKnuthElements
method. There is a “if (getTableLM().getTable().omitHeaderAtBreak())”
test that you could augment with a “&&  !(omitFirstHeader)” clause.
Likewise for the footer.

The easiest is to directly modify that class and re-build FOP. A bit
less easy would be to add a variable in the configuration file, so that
you can enable it only for certain FO files. Even less easy would be to
add an extension property to fo:table so that you can enable it only for
some tables of an FO document. Please ask if you need more details.

All that said, such a change would be very hacky and, unless there is
overwhelming demand from the user community, I would oppose to integrate
it in the code base. This is a patch that you would have to maintain on
your side. Better would be of course to actually implement
retrieve-table-marker. Although this would be more involving than
implementing this little trick...


HTH,
Vincent




Index: src/java/org/apache/fop/render/intermediate/extensions/GoToIDAction.java
===================================================================
--- src/java/org/apache/fop/render/intermediate/extensions/GoToIDAction.java    
(revision 0)
+++ src/java/org/apache/fop/render/intermediate/extensions/GoToIDAction.java    
(revision 0)
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: GoToXYAction.java 815301 2009-09-15 12:50:47Z maxberger $ */
+
+package org.apache.fop.render.intermediate.extensions;
+
+import java.awt.Point;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.util.XMLUtil;
+
+/**
+ * Action class which represents a "go-to" action to an unknown ID.
+ */
+public class GoToIDAction extends AbstractAction implements 
DocumentNavigationExtensionConstants {
+
+
+    /**
+     * Creates a new instance with yet unknown location.
+     * @param id the identifier for this action
+     */
+    public GoToIDAction(String id) {
+        setID(id);
+    }
+
+    
+    /** {@inheritDoc} */
+    public boolean isComplete() {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSame(AbstractAction other) {
+        if (other == null) {
+            throw new NullPointerException("other must not be null");
+        }
+        if (!(other instanceof GoToIDAction)) {
+            return false;
+        }
+        GoToIDAction otherAction = (GoToIDAction)other;
+        if ( !getID().equals(otherAction.getID())) {
+            return false;
+        }
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    public void toSAX(ContentHandler handler) throws SAXException {
+        AttributesImpl atts = new AttributesImpl();
+        atts.addAttribute(null, "idref", "idref", XMLUtil.CDATA, getID());
+        handler.startElement(GOTO_XY.getNamespaceURI(),
+                GOTO_XY.getLocalName(), GOTO_XY.getQName(), atts);
+        handler.endElement(GOTO_XY.getNamespaceURI(),
+                GOTO_XY.getLocalName(), GOTO_XY.getQName());
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return "GoToID: ID=" + getID() + ", "
+            + (isComplete() ? "complete" : "INCOMPLETE");
+    }
+
+}
Index: src/java/org/apache/fop/render/intermediate/IFRenderer.java
===================================================================
--- src/java/org/apache/fop/render/intermediate/IFRenderer.java (revision 
1152996)
+++ src/java/org/apache/fop/render/intermediate/IFRenderer.java (working copy)
@@ -89,6 +89,7 @@
 import org.apache.fop.render.intermediate.extensions.ActionSet;
 import org.apache.fop.render.intermediate.extensions.Bookmark;
 import org.apache.fop.render.intermediate.extensions.BookmarkTree;
+import org.apache.fop.render.intermediate.extensions.GoToIDAction;
 import org.apache.fop.render.intermediate.extensions.GoToXYAction;
 import org.apache.fop.render.intermediate.extensions.Link;
 import org.apache.fop.render.intermediate.extensions.NamedDestination;
@@ -358,14 +359,15 @@
         if (targetID == null || targetID.length() == 0) {
             throw new IllegalArgumentException("DestinationData must contain a 
ID reference");
         }
-        GoToXYAction action = null;
+        AbstractAction action = null;
         PageViewport pv = bookmarkItem.getPageViewport();
 
         if (pv != null) {
             action = getGoToActionForID(targetID, pv.getPageIndex());
         } else {
             //Warning already issued by AreaTreeHandler (debug level is 
sufficient)
-            log.debug("Bookmark with IDRef \"" + targetID + "\" has a null 
PageViewport.");
+            log.debug("Bookmark with IDRef \"" + targetID + "\" has a null 
PageViewport. Generating unresolved bookmark.");
+            action = new GoToIDAction(targetID);
         }
 
         Bookmark b = new Bookmark(
@@ -928,7 +930,17 @@
                 action = getGoToActionForID(idRef, (pageIndex != null ? 
pageIndex.intValue() : -1));
             } else {
                 //Warnings already issued by AreaTreeHandler
+                // But generate a link to a named destination even if it 
doesn't exist
+                action = new GoToIDAction(idRef);
+                log.debug("Generating unresolved link to named destination: " 
+ idRef);
             }
+        } else {
+            String idRef = (String)ip.getTrait(Trait.NAMED_LINK);
+            if ( idRef != null ) {
+                linkTraitFound = true;
+                action = new GoToIDAction(idRef);
+                log.debug("Generating unresolved link to named destination: " 
+ idRef);
+            }
         }
 
         // no INTERNAL_LINK, look for EXTERNAL_LINK
Index: src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
===================================================================
--- src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java        
(revision 1152996)
+++ src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java        
(working copy)
@@ -29,6 +29,7 @@
 import org.apache.fop.pdf.PDFDocument;
 import org.apache.fop.pdf.PDFFactory;
 import org.apache.fop.pdf.PDFGoTo;
+import org.apache.fop.pdf.PDFGoToNamed;
 import org.apache.fop.pdf.PDFLink;
 import org.apache.fop.pdf.PDFOutline;
 import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
@@ -36,6 +37,7 @@
 import org.apache.fop.render.intermediate.extensions.AbstractAction;
 import org.apache.fop.render.intermediate.extensions.Bookmark;
 import org.apache.fop.render.intermediate.extensions.BookmarkTree;
+import org.apache.fop.render.intermediate.extensions.GoToIDAction;
 import org.apache.fop.render.intermediate.extensions.GoToXYAction;
 import org.apache.fop.render.intermediate.extensions.Link;
 import org.apache.fop.render.intermediate.extensions.NamedDestination;
@@ -51,6 +53,7 @@
 
     private final Map incompleteActions = new java.util.HashMap();
     private final Map completeActions = new java.util.HashMap();
+    private final Map namedActions = new java.util.HashMap();
 
     /**
      * Default constructor.
@@ -85,7 +88,10 @@
         if (parent == null) {
             parent = getPDFDoc().getOutlineRoot();
         }
-        PDFAction action = getAction(bookmark.getAction());
+        PDFAction action = getNamedAction(bookmark.getAction());
+        if ( action == null ) {
+            System.out.println("UNKNOWN BOOKMARK: " + bookmark.getTitle());
+        }
         String actionRef = (action != null ? action.makeReference().toString() 
: null);
         PDFOutline pdfOutline = getPDFDoc().getFactory().makeOutline(parent,
             bookmark.getTitle(), actionRef, bookmark.isShown());
@@ -105,7 +111,7 @@
                 (pageHeight - targetRect.getMinY() - targetRect.getHeight()) / 
1000.0,
                 targetRect.getWidth() / 1000.0,
                 targetRect.getHeight() / 1000.0);
-        PDFAction pdfAction = getAction(link.getAction());
+        PDFAction pdfAction = getNamedAction(link.getAction());
         //makeLink() currently needs a PDFAction and not a reference
         //TODO Revisit when PDFLink is converted to a PDFDictionary
         PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
@@ -141,6 +147,36 @@
         }
     }
 
+    private PDFAction getNamedAction(String id) {
+        PDFAction namedAction = (PDFAction)namedActions.get(id);
+        if ( namedAction != null ) {
+            return namedAction;
+        }
+        PDFGoToNamed namedGoTo = new PDFGoToNamed(id);
+        getPDFDoc().assignObjectNumber(namedGoTo);
+        getPDFDoc().addObject(namedGoTo);
+        namedActions.put(id, namedGoTo);
+        return namedGoTo;
+    }
+
+    private PDFAction getNamedAction(AbstractAction action) {
+        if ( action == null )
+            return null;
+        PDFAction pdfAction = getAction(action);
+        PDFAction namedAction = (PDFAction)namedActions.get(action.getID());
+        if ( namedAction != null ) {
+            return namedAction;
+        } else if ( (action instanceof GoToXYAction) || (action instanceof 
GoToIDAction) ) {
+            PDFGoToNamed namedGoTo = new PDFGoToNamed(action.getID());
+            getPDFDoc().assignObjectNumber(namedGoTo);
+            getPDFDoc().addObject(namedGoTo);
+            namedActions.put(action.getID(), namedGoTo);
+            return namedGoTo;
+        } else {
+            return pdfAction;
+        }
+    }
+
     private PDFAction getAction(AbstractAction action) {
         if (action == null) {
             return null;
@@ -175,6 +211,8 @@
             }
             this.completeActions.put(action.getID(), pdfAction);
             return pdfAction;
+        } else if ( action instanceof GoToIDAction ) {
+            return null;
         } else {
             throw new UnsupportedOperationException("Unsupported action type: "
                     + action + " (" + action.getClass().getName() + ")");
Index: src/java/org/apache/fop/layoutmgr/ElementListUtils.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/ElementListUtils.java     (revision 
1152996)
+++ src/java/org/apache/fop/layoutmgr/ElementListUtils.java     (working copy)
@@ -119,6 +119,10 @@
                     UnresolvedListElementWithLength uel = 
(UnresolvedListElementWithLength)el;
                     len += uel.getLength().getOpt();
                 }
+            } else if ( el instanceof SpaceElement ) {
+                SpaceElement spaceEl = (SpaceElement)el;
+                MinOptMax l = spaceEl.getLength();
+                len += l.getMin();
             } else {
                 KnuthElement kel = (KnuthElement)el;
                 len += kel.getWidth();
Index: src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java      
(revision 1152996)
+++ src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java      
(working copy)
@@ -155,7 +155,7 @@
             TableHeaderFooterPosition pos = new TableHeaderFooterPosition(
                     getTableLM(), true, this.headerList);
             KnuthBox box = new KnuthBox(headerNetHeight, pos, false);
-            if (getTableLM().getTable().omitHeaderAtBreak()) {
+            if (getTableLM().getTable().omitHeaderAtBreak() && 
!getTableLM().getTable().omitFirstHeader()) {
                 //We can simply add the table header at the start
                 //of the whole list
                 headerAsFirst = box;
@@ -198,7 +198,8 @@
             if (returnList.size() > 0 && 
((ListElement)returnList.getLast()).isForcedBreak()) {
                 insertionPoint--;
             }
-            returnList.add(insertionPoint, footerAsLast);
+            if (!getTableLM().getTable().omitLastFooter() )
+                returnList.add(insertionPoint, footerAsLast);
         }
         return returnList;
     }
@@ -366,7 +367,8 @@
                 //these positions need to be unpacked
                 if (thfpos.header) {
                     //Positions for header will be added first
-                    headerElements = thfpos.nestedElements;
+                    if ( !(getTableLM().isFirst(pos) && 
getTableLM().getTable().omitFirstHeader()) )
+                        headerElements = thfpos.nestedElements;
                 } else {
                     //Positions for footers are simply added at the end
                     footerElements = thfpos.nestedElements;
@@ -388,7 +390,8 @@
             if (penaltyPos.headerElements != null) {
                 //Header positions for the penalty position are in the last 
element and need to
                 //be handled first before all other TableContentPositions
-                headerElements = penaltyPos.headerElements;
+                if ( !(getTableLM().isFirst(lastPos) && 
getTableLM().getTable().omitFirstHeader()) )
+                    headerElements = penaltyPos.headerElements;
             }
             if (penaltyPos.footerElements != null) {
                 footerElements = penaltyPos.footerElements;
Index: src/java/org/apache/fop/hyphenation/HyphenationTree.java
===================================================================
--- src/java/org/apache/fop/hyphenation/HyphenationTree.java    (revision 
1152996)
+++ src/java/org/apache/fop/hyphenation/HyphenationTree.java    (working copy)
@@ -110,13 +110,13 @@
         StringBuffer buf = new StringBuffer();
         byte v = vspace.get(k++);
         while (v != 0) {
-            char c = (char)((v >>> 4) - 1 + '0');
+           char c = (char)(((v >>> 4) & 0x0f) - 1 + '0');
             buf.append(c);
             c = (char)(v & 0x0f);
             if (c == 0) {
                 break;
             }
-            c = (char)(c - 1 + '0');
+            c = (char)((c & 0x0f) - 1 + '0');
             buf.append(c);
             v = vspace.get(k++);
         }
@@ -203,13 +203,13 @@
         StringBuffer buf = new StringBuffer();
         byte v = vspace.get(k++);
         while (v != 0) {
-            char c = (char)((v >>> 4) - 1);
+           char c = (char)(((v >>> 4) & 0x0f) - 1);
             buf.append(c);
             c = (char)(v & 0x0f);
             if (c == 0) {
                 break;
             }
-            c = (char)(c - 1);
+            c = (char)((c & 0x0f) - 1);
             buf.append(c);
             v = vspace.get(k++);
         }
Index: src/java/org/apache/fop/fo/Constants.java
===================================================================
--- src/java/org/apache/fop/fo/Constants.java   (revision 1152996)
+++ src/java/org/apache/fop/fo/Constants.java   (working copy)
@@ -781,8 +781,15 @@
     /** Property constant - FOP proprietary prototype (in XSL-FO 2.0 
Requirements) */
     int PR_X_XML_BASE = 276;
 
+
+    /** Property constant - FOP proprietary: omit first header extension */
+    int PR_X_TABLE_OMIT_FIRST_HEADER = 277;
+    /** Property constant - FOP proprietary: omit last footer extension */
+    int PR_X_TABLE_OMIT_LAST_FOOTER = 278;
+
+
     /** Number of property constants defined */
-    int PROPERTY_COUNT = 276;
+    int PROPERTY_COUNT = 278;
 
     // compound property constants
 
Index: src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java  
(revision 1152996)
+++ src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java  
(working copy)
@@ -49,6 +49,8 @@
         PROPERTY_ATTRIBUTES.add("disable-column-balancing");
         //These are FOP's extension properties for accessibility
         PROPERTY_ATTRIBUTES.add("alt-text");
+        PROPERTY_ATTRIBUTES.add("table-omit-first-header");
+        PROPERTY_ATTRIBUTES.add("table-omit-last-footer");
     }
 
     /**
Index: src/java/org/apache/fop/fo/flow/table/Table.java
===================================================================
--- src/java/org/apache/fop/fo/flow/table/Table.java    (revision 1152996)
+++ src/java/org/apache/fop/fo/flow/table/Table.java    (working copy)
@@ -71,6 +71,10 @@
     private Length widowContentLimit;
     private Length orphanContentLimit;
 
+    /** cav extension properties */
+    private int tableOmitFirstHeader;
+    private int tableOmitLastFooter;
+
     /** collection of columns in this table */
     private List columns = new ArrayList();
 
@@ -131,6 +135,9 @@
         widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength();
         orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength();
 
+        tableOmitFirstHeader = 
pList.get(PR_X_TABLE_OMIT_FIRST_HEADER).getEnum();
+        tableOmitLastFooter = pList.get(PR_X_TABLE_OMIT_LAST_FOOTER).getEnum();
+        
         if (!blockProgressionDimension.getOptimum(null).isAuto()) {
             TableEventProducer eventProducer = TableEventProducer.Provider.get(
                     getUserAgent().getEventBroadcaster());
@@ -423,6 +430,16 @@
         return (this.tableOmitFooterAtBreak == EN_TRUE);
     }
 
+    /** @return true if the first table-header should be omitted */
+    public boolean omitFirstHeader() {
+        return (this.tableOmitFirstHeader == EN_TRUE);
+    }
+
+    /** @return true if the last table-footer should be omitted */
+    public boolean omitLastFooter() {
+        return (this.tableOmitLastFooter == EN_TRUE);
+    }
+
     /**
      * @return the "inline-progression-dimension" property.
      */
Index: src/java/org/apache/fop/fo/FOPropertyMapping.java
===================================================================
--- src/java/org/apache/fop/fo/FOPropertyMapping.java   (revision 1152996)
+++ src/java/org/apache/fop/fo/FOPropertyMapping.java   (working copy)
@@ -2455,6 +2455,20 @@
         m.setInherited(false);
         m.setDefault("false");
         addPropertyMaker("table-omit-header-at-break", m);
+
+        // fox:table-omit-first-header
+        m  = new EnumProperty.Maker(PR_X_TABLE_OMIT_FIRST_HEADER);
+        m.useGeneric(genericBoolean);
+        m.setInherited(false);
+        m.setDefault("false");
+        addPropertyMaker("fox:table-omit-first-header", m);
+
+        // fox:table-omit-last-footer
+        m  = new EnumProperty.Maker(PR_X_TABLE_OMIT_LAST_FOOTER);
+        m.useGeneric(genericBoolean);
+        m.setInherited(false);
+        m.setDefault("false");
+        addPropertyMaker("fox:table-omit-last-footer", m);
     }
 
     private void createWritingModeProperties() {
Index: src/java/org/apache/fop/area/LinkResolver.java
===================================================================
--- src/java/org/apache/fop/area/LinkResolver.java      (revision 1152996)
+++ src/java/org/apache/fop/area/LinkResolver.java      (working copy)
@@ -43,6 +43,8 @@
     public LinkResolver(String id, Area a) {
         idRef = id;
         area = a;
+        // add the id to the area so we can create a named link
+        area.addTrait(Trait.NAMED_LINK, id);
     }
 
     /**
@@ -81,6 +83,7 @@
             resolved = true;
             Trait.InternalLink iLink = new Trait.InternalLink(pv.getKey(), 
idRef);
             area.addTrait(Trait.INTERNAL_LINK, iLink);
+            area.addTrait(Trait.NAMED_LINK, null);
         }
     }
 }
Index: src/java/org/apache/fop/area/Trait.java
===================================================================
--- src/java/org/apache/fop/area/Trait.java     (revision 1152996)
+++ src/java/org/apache/fop/area/Trait.java     (working copy)
@@ -156,8 +156,11 @@
     /** The ptr trait. Used for accessibility   */
     public static final Integer PTR = 37;
 
+    /** Trait used to create unresolved links to named destinations */
+    public static final Integer NAMED_LINK = new Integer(38);
+
     /** Maximum value used by trait keys */
-    public static final int MAX_TRAIT_KEY = 37;
+    public static final int MAX_TRAIT_KEY = 38;
 
     private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY 
+ 1];
 
@@ -221,6 +224,7 @@
         put(SPACE_AFTER,    new TraitInfo("space-after", Integer.class));
         put(IS_REFERENCE_AREA,  new TraitInfo("is-reference-area", 
Boolean.class));
         put(IS_VIEWPORT_AREA,   new TraitInfo("is-viewport-area", 
Boolean.class));
+        put(NAMED_LINK, new TraitInfo("named-link", String.class));
 
     }
 
Index: src/java/org/apache/fop/pdf/PDFGoToNamed.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFGoToNamed.java       (revision 0)
+++ src/java/org/apache/fop/pdf/PDFGoToNamed.java       (revision 0)
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: PDFGoTo.java 815358 2009-09-15 15:07:51Z maxberger $ */
+
+package org.apache.fop.pdf;
+
+/**
+ * class representing a /GoTo object.
+ * This can either have a Goto to a page reference and location
+ * or to a specified PDF reference string.
+ */
+public class PDFGoToNamed extends PDFAction {
+
+    /**
+     * the pageReference
+     */
+    private String destination = null;
+
+    /**
+     * create a /GoTo object.
+     *
+     * @param pageReference the pageReference represented by this object
+     */
+    public PDFGoToNamed(String destination) {
+        /* generic creation of object */
+        super();
+
+        this.destination = destination;
+    }
+
+
+    /**
+     * Set the destination string for this Goto.
+     *
+     * @param dest the PDF destination string
+     */
+    public void setDestination(String dest) {
+        destination = dest;
+    }
+
+    /**
+     * Get the PDF reference for the GoTo action.
+     *
+     * @return the PDF reference for the action
+     */
+    public String getAction() {
+        return referencePDF();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toPDFString() {
+        String dest;
+        if (destination == null) {
+            dest = "/D (UNKNOWN)\n";
+        } else {
+            dest = "/D (" +  destination + ")\n";
+        }
+        return getObjectID()
+                    + "<< /Type /Action\n/S /GoTo\n" + dest
+                    + ">>\nendobj\n";
+    }
+
+    /*
+     * example
+     * 29 0 obj
+     * <<
+     * /S /GoTo
+     * /D (N123232)
+     * >>
+     * endobj
+     */
+
+    /** {@inheritDoc} */
+    protected boolean contentEquals(PDFObject obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null || !(obj instanceof PDFGoToNamed)) {
+            return false;
+        }
+
+        PDFGoToNamed gt = (PDFGoToNamed)obj;
+
+        
+
+        if (destination == null) {
+            if (gt.destination != null) {
+                return false;
+            }
+        } else {
+            if (!destination.equals(gt.destination)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
+

Reply via email to