| /******************************************************************************* |
| * Copyright (c) 2004, 2008 John Krasnay and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * John Krasnay - initial API and implementation |
| * Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325) |
| *******************************************************************************/ |
| package org.eclipse.vex.docbook; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| |
| import org.eclipse.jface.viewers.IBaseLabelProvider; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.vex.core.internal.dom.Document; |
| import org.eclipse.vex.core.internal.dom.Element; |
| import org.eclipse.vex.ui.internal.editor.VexEditor; |
| import org.eclipse.vex.ui.internal.outline.IOutlineProvider; |
| |
| /** |
| * Provides an outline of the sections of a DocBook document. |
| */ |
| public class DocBookOutlineProvider implements IOutlineProvider { |
| |
| public void init(final VexEditor editor) { |
| } |
| |
| public ITreeContentProvider getContentProvider() { |
| return contentProvider; |
| } |
| |
| public IBaseLabelProvider getLabelProvider() { |
| return labelProvider; |
| } |
| |
| public Element getOutlineElement(final Element child) { |
| Element element = child; |
| while (element.getParentElement() != null && !isTitledElement(element)) { |
| element = element.getParentElement(); |
| } |
| |
| return element; |
| } |
| |
| private final ITreeContentProvider contentProvider = new ITreeContentProvider() { |
| |
| public void dispose() { |
| } |
| |
| public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { |
| } |
| |
| public Object[] getChildren(final Object parentElement) { |
| return getOutlineChildren((Element) parentElement); |
| } |
| |
| public Object getParent(final Object element) { |
| final Element parent = ((Element) element).getParentElement(); |
| if (parent == null) { |
| return element; |
| } else { |
| return getOutlineElement(parent); |
| } |
| } |
| |
| public boolean hasChildren(final Object element) { |
| return getOutlineChildren((Element) element).length > 0; |
| } |
| |
| public Object[] getElements(final Object inputElement) { |
| final Document document = (Document) inputElement; |
| return new Object[] { document.getRootElement() }; |
| } |
| |
| }; |
| |
| /** |
| * Returns an array of the children of the given element that represent nodes in the outline. These are elements |
| * such as "section" that contain "title" elements that we can use as label content. |
| * |
| * @param element |
| * @return |
| */ |
| private Element[] getOutlineChildren(final Element element) { |
| final List<Element> children = new ArrayList<Element>(); |
| for (final Element child : element.getChildElements()) { |
| if (titledElements.contains(child.getLocalName())) { |
| children.add(child); |
| } |
| } |
| return children.toArray(new Element[children.size()]); |
| } |
| |
| private final ILabelProvider labelProvider = new LabelProvider() { |
| @Override |
| public String getText(final Object o) { |
| final Element e = (Element) o; |
| Element titleChild = findChild(e, "title"); |
| if (titleChild != null) { |
| return titleChild.getText(); |
| } else { |
| final Element infoChild = findChild(e, e.getLocalName() + "info"); |
| if (infoChild != null) { |
| titleChild = findChild(infoChild, "title"); |
| if (titleChild != null) { |
| return titleChild.getText(); |
| } |
| } |
| } |
| return e.getLocalName(); |
| } |
| }; |
| |
| /** |
| * Returns a value from a map of tag names that contain title elements The tags all have a similar characteristic. |
| * Their content model includes a <title/> element as the first or second child. |
| * |
| * For simplicity, we assume that the document is valid w.r.t. the DTD and thus the 'title' element is optional and |
| * is one of the first two elements inside the given element. |
| * |
| * @param element |
| * @return |
| */ |
| private boolean isTitledElement(final Element e) { |
| |
| if (titledElements.contains(e.getLocalName()) || e.getParent() == null) { |
| final List<Element> children = e.getChildElements(); |
| if (children.size() > 0 && children.get(0).getLocalName().equals("title") || children.size() > 1 && children.get(1).getLocalName().equals("title")) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Finds the first child of the given element with the given name. Returns null if none found. We should move this |
| * to XPath when we gain that facility. |
| */ |
| private Element findChild(final Element parent, final String childName) { |
| for (final Element child : parent.getChildElements()) { |
| if (child.getLocalName().equals(childName)) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| private final static int MAPSIZE = 101; // prime greater than 65/.80 |
| |
| private final static HashSet<String> titledElements = new HashSet<String>(MAPSIZE); |
| |
| static { |
| // Comment on each line indicates tags content model if different than title |
| // We are only interested in location of title tag within Content Model |
| // so any extra following content is ignored. |
| |
| // In general, it is impossible to keep this sort of table accurate and |
| // up-to-date for more than the most basic of cases. It would be better |
| // to extract this information from the DTD for the document. |
| |
| // For the moment, it is observed that this imperfect method works for |
| // vast majority of DocBook documents. |
| |
| titledElements.add("abstract"); // title? |
| titledElements.add("article"); |
| // titledElements.add("articleinfo"); |
| titledElements.add("appendix"); |
| // titledElements.add("authorblurb"); // title? |
| // titledElements.add("bibliodiv"); |
| // titledElements.add("calloutlist"); |
| // titledElements.add("caution"); // title? |
| titledElements.add("chapter"); // docinfo?, title |
| // titledElements.add("colophon"); |
| // titledElements.add("constraintdef"); |
| // titledElements.add("dedication"); |
| |
| // titledElements.add("equation"); // blockinfo?, title |
| // titledElements.add("example"); // blockinfo?, title |
| // titledElements.add("figure"); // blockinfo?, title |
| titledElements.add("glossary"); // glossaryinfo?, title |
| // titledElements.add("glossdiv"); |
| // titledElements.add("glosslist"); // blockinfo?, title |
| // titledElements.add("important"); // title? |
| // titledElements.add("index"); // indexinfo, title |
| // titledElements.add("indexdiv"); |
| // titledElements.add("itemizedlist"); // blockinfo?, title |
| |
| // titledElements.add("legalnotice"); // blockinfo?, title |
| // titledElements.add("lot"); // beginpage?, title |
| // titledElements.add("msg"); // title? |
| // titledElements.add("msgexplan"); // title? |
| // titledElements.add("msgmain"); // title? |
| // titledElements.add("msgrel"); // title? |
| // titledElements.add("msgset"); |
| // titledElements.add("msgsub"); // title? |
| // titledElements.add("note"); // title? |
| // titledElements.add("orderedlist"); // blockinfo?, title |
| |
| titledElements.add("part"); // beginpage?, partinfo?, title |
| titledElements.add("partintro"); |
| // titledElements.add("personblurb"); // title? |
| titledElements.add("preface"); // beginpage?, prefaceinfo?, title |
| // titledElements.add("procedure"); // blockinfo?, title |
| // titledElements.add("productionset"); |
| // titledElements.add("qandadiv"); // blockinfo?, title |
| // titledElements.add("qandaset"); // blockinfo?, title |
| // titledElements.add("reference"); // beginpage?, referenceinfo?, title |
| // titledElements.add("refsect1"); // refsect1info?, title |
| |
| // titledElements.add("refsect2"); // refsect2info, title |
| // titledElements.add("refsect3"); // refsect3info, title |
| // titledElements.add("refsection"); // refsectioninfo?, title |
| // titledElements.add("refsynopsisdiv"); // refsynopsisdivinfo?, title |
| titledElements.add("sect1"); // sect1info?, title |
| titledElements.add("sect2"); // sect2info?, title |
| titledElements.add("sect3"); // sect3info?, title |
| titledElements.add("sect4"); // sect4info?, title |
| titledElements.add("sect5"); // sect5info?, title |
| titledElements.add("section"); // sectioninfo?, title |
| |
| // titledElements.add("segmentedlist"); |
| // titledElements.add("set"); |
| // titledElements.add("setindex"); // setindexinfo?, title |
| // titledElements.add("sidebar"); // sidebarinfo?, title |
| titledElements.add("simplesect"); |
| // titledElements.add("step"); // table? |
| // titledElements.add("table"); // blockinfo?, title |
| // titledElements.add("task"); // blockinfo?, title |
| // titledElements.add("taskprerequisites");// blockinfo?, title |
| // titledElements.add("taskrelated"); // blockinfo?, title |
| |
| // titledElements.add("tasksummary"); // blockinfo?, title |
| // titledElements.add("tip"); // title? |
| titledElements.add("toc"); // beginpage?, title |
| // titledElements.add("variablelist"); // blockinfo?, title |
| // titledElements.add("warning"); // title? |
| } |
| |
| } |