blob: 5ca480f4a74390a4c734b1eb12a1f4d7b9035fcc [file] [log] [blame]
/*
* 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$ */
package org.apache.fop.render.intermediate.extensions;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.util.XMLUtil;
/**
* ContentHandler that handles the IF document navigation namespace.
*/
public class DocumentNavigationHandler extends DefaultHandler
implements DocumentNavigationExtensionConstants {
/** Logger instance */
protected static Log log = LogFactory.getLog(DocumentNavigationHandler.class);
private StringBuffer content = new StringBuffer();
private Stack objectStack = new Stack();
private IFDocumentNavigationHandler navHandler;
private String structurePointer;
/**
* Main constructor.
* @param navHandler the navigation handler that will receive the events
*/
public DocumentNavigationHandler(IFDocumentNavigationHandler navHandler) {
this.navHandler = navHandler;
}
/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
boolean handled = false;
if (NAMESPACE.equals(uri)) {
if (BOOKMARK_TREE.getLocalName().equals(localName)) {
if (!objectStack.isEmpty()) {
throw new SAXException(localName + " must be the root element!");
}
BookmarkTree bookmarkTree = new BookmarkTree();
objectStack.push(bookmarkTree);
} else if (BOOKMARK.getLocalName().equals(localName)) {
String title = attributes.getValue("title");
String s = attributes.getValue("starting-state");
boolean show = !"hide".equals(s);
Bookmark b = new Bookmark(title, show, null);
Object o = objectStack.peek();
if (o instanceof AbstractAction) {
AbstractAction action = (AbstractAction)objectStack.pop();
o = objectStack.peek();
((Bookmark)o).setAction(action);
}
if (o instanceof BookmarkTree) {
((BookmarkTree)o).addBookmark(b);
} else {
((Bookmark)o).addChildBookmark(b);
}
objectStack.push(b);
} else if (NAMED_DESTINATION.getLocalName().equals(localName)) {
if (!objectStack.isEmpty()) {
throw new SAXException(localName + " must be the root element!");
}
String name = attributes.getValue("name");
NamedDestination dest = new NamedDestination(name, null);
objectStack.push(dest);
} else if (LINK.getLocalName().equals(localName)) {
if (!objectStack.isEmpty()) {
throw new SAXException(localName + " must be the root element!");
}
Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect");
structurePointer = attributes.getValue("ptr");
Link link = new Link(null, targetRect);
objectStack.push(link);
} else if (GOTO_XY.getLocalName().equals(localName)) {
String idref = attributes.getValue("idref");
GoToXYAction action;
if (idref != null) {
action = new GoToXYAction(idref);
} else {
String id = attributes.getValue("id");
int pageIndex = XMLUtil.getAttributeAsInt(attributes, "page-index");
final Point location;
if (pageIndex < 0) {
location = null;
} else {
final int x = XMLUtil
.getAttributeAsInt(attributes, "x");
final int y = XMLUtil
.getAttributeAsInt(attributes, "y");
location = new Point(x, y);
}
action = new GoToXYAction(id, pageIndex, location);
}
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
}
objectStack.push(action);
} else if (GOTO_URI.getLocalName().equals(localName)) {
String id = attributes.getValue("id");
String gotoURI = attributes.getValue("uri");
String showDestination = attributes.getValue("show-destination");
boolean newWindow = "new".equals(showDestination);
URIAction action = new URIAction(gotoURI, newWindow);
if (id != null) {
action.setID(id);
}
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
}
objectStack.push(action);
} else {
throw new SAXException(
"Invalid element '" + localName + "' in namespace: " + uri);
}
handled = true;
}
if (!handled) {
if (NAMESPACE.equals(uri)) {
throw new SAXException("Unhandled element '" + localName + "' in namespace: "
+ uri);
} else {
log.warn("Unhandled element '" + localName + "' in namespace: " + uri);
}
}
}
/** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException {
if (NAMESPACE.equals(uri)) {
try {
if (BOOKMARK_TREE.getLocalName().equals(localName)) {
BookmarkTree tree = (BookmarkTree)objectStack.pop();
if (hasNavigation()) {
this.navHandler.renderBookmarkTree(tree);
}
} else if (BOOKMARK.getLocalName().equals(localName)) {
if (objectStack.peek() instanceof AbstractAction) {
AbstractAction action = (AbstractAction)objectStack.pop();
Bookmark b = (Bookmark)objectStack.pop();
b.setAction(action);
} else {
objectStack.pop();
}
} else if (NAMED_DESTINATION.getLocalName().equals(localName)) {
AbstractAction action = (AbstractAction)objectStack.pop();
NamedDestination dest = (NamedDestination)objectStack.pop();
dest.setAction(action);
if (hasNavigation()) {
this.navHandler.renderNamedDestination(dest);
}
} else if (LINK.getLocalName().equals(localName)) {
AbstractAction action = (AbstractAction)objectStack.pop();
Link link = (Link)objectStack.pop();
link.setAction(action);
if (hasNavigation()) {
this.navHandler.renderLink(link);
}
} else if (localName.startsWith("goto-")) {
if (objectStack.size() == 1) {
//Stand-alone action
AbstractAction action = (AbstractAction)objectStack.pop();
if (hasNavigation()) {
this.navHandler.addResolvedAction(action);
}
}
}
} catch (IFException ife) {
throw new SAXException(ife);
}
}
content.setLength(0); // Reset text buffer (see characters())
}
private boolean hasNavigation() {
return this.navHandler != null;
}
/** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException {
content.append(ch, start, length);
}
/** {@inheritDoc} */
public void endDocument() throws SAXException {
assert objectStack.isEmpty();
}
}