Package org.eclipse.ui.internal.intro.impl.html

Source Code of org.eclipse.ui.internal.intro.impl.html.IntroHTMLGenerator

/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation 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:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.intro.impl.html;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;

import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.internal.intro.impl.IIntroConstants;
import org.eclipse.ui.internal.intro.impl.IntroPlugin;
import org.eclipse.ui.internal.intro.impl.model.AbstractBaseIntroElement;
import org.eclipse.ui.internal.intro.impl.model.AbstractIntroElement;
import org.eclipse.ui.internal.intro.impl.model.AbstractIntroPage;
import org.eclipse.ui.internal.intro.impl.model.IntroContentProvider;
import org.eclipse.ui.internal.intro.impl.model.IntroGroup;
import org.eclipse.ui.internal.intro.impl.model.IntroHTML;
import org.eclipse.ui.internal.intro.impl.model.IntroHead;
import org.eclipse.ui.internal.intro.impl.model.IntroImage;
import org.eclipse.ui.internal.intro.impl.model.IntroInjectedIFrame;
import org.eclipse.ui.internal.intro.impl.model.IntroLink;
import org.eclipse.ui.internal.intro.impl.model.IntroPageTitle;
import org.eclipse.ui.internal.intro.impl.model.IntroSeparator;
import org.eclipse.ui.internal.intro.impl.model.IntroText;
import org.eclipse.ui.internal.intro.impl.model.loader.ContentProviderManager;
import org.eclipse.ui.internal.intro.impl.model.util.BundleUtil;
import org.eclipse.ui.internal.intro.impl.util.Log;
import org.eclipse.ui.intro.config.IIntroContentProvider;
import org.eclipse.ui.intro.config.IIntroContentProviderSite;

public class IntroHTMLGenerator {

  private AbstractIntroPage introPage;

  private IIntroContentProviderSite providerSite;

  /**
   * Generates the HTML code that will be presented in the browser widget for the provided intro
   * page.
   *
   * @param page
   *            the page to generate HTML for
   * @param presentation
   *            the presentation associated with this page.
   */
  public HTMLElement generateHTMLforPage(AbstractIntroPage page, IIntroContentProviderSite providerSite) {
    if (page == null)
      return null;
    this.introPage = page;
    this.providerSite = providerSite;

    // generate and add the appropriate encoding to the top of the document
    // generateEncoding();
    // create the main HTML element, and all of its contents.
    return generateHTMLElement();
  }

  /*
   * private HTMLElement generateEncoding() { HTMLElement encoding = new HTMLElement("");
   * //$NON-NLS-1$ // TODO: figure out how to handle locale based encoding // As far as the HTML
   * generator is concerned, this is probably as // simple as asking the model for the information
   * return encoding; }
   */

  /**
   * Generates the HTML element and its content:
   *
   * <pre>
   *  
   *                        &lt;HTML&gt;
   *                        &lt;HEAD&gt;
   *                        head content
   *                        &lt;/HEAD&gt;
   *                        &lt;BODY&gt;
   *                        body content
   *                        &lt;/BODY&gt;
   *                        &lt;/HTML&gt;
   *   
   * </pre>
   *
   * @return the html HTMLElement
   */
  private HTMLElement generateHTMLElement() {
    // this is the outermost element, so it has no indent
    int indentLevel = 0;
    HTMLElement html = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_HTML, indentLevel, true);
    HTMLElement head = generateHeadElement(indentLevel + 1);
    HTMLElement body = generateBodyElement(indentLevel + 1, head);
    html.addContent(head);
    html.addContent(body);
    return html;
  }

  /**
   * Generates the HEAD element and its content:
   *
   * <pre>
   *  
   *               
   *                        &lt;HEAD&gt;
   *                        &lt;BASE href=&quot;base_plugin_location&gt;
   *                        &lt;style type=&quot;text/css&quot;&gt;HTML, IMG { border: 0px; } &lt;/style&gt;
   *                        &lt;TITLE&gt;page title &lt;/TITLE&gt;
   *                        &lt;LINK href=&quot;style sheet&quot;&gt;
   *                        additional head content, if specified
   *                        &lt;/HEAD&gt;
   *   
   * </pre>
   *
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return the head HTMLElement
   */
  private HTMLElement generateHeadElement(int indentLevel) {
    HTMLElement head = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_HEAD, indentLevel, true);
    // add the title
    head.addContent(generateTitleElement(null, indentLevel + 1));
    // create the BASE element
    String basePath = BundleUtil.getResolvedResourceLocation(introPage.getBase(), introPage.getBundle());
    HTMLElement base = generateBaseElement(indentLevel + 1, basePath);
    if (base != null)
      head.addContent(base);
    // create the HTML style block
    head.addContent(generateStyleElement(indentLevel + 1));
    // add the presentation style
    String[] presentationStyles = IntroPlugin.getDefault().getIntroModelRoot().getPresentation()
        .getImplementationStyles();
    if (presentationStyles != null && introPage.injectSharedStyle()) {
      for (int i=0; i<presentationStyles.length; i++)
        head.addContent(generateLinkElement(presentationStyles[i], indentLevel + 1));
    }
    String pageStyle = introPage.getStyle();
    if (pageStyle != null)
      head.addContent(generateLinkElement(pageStyle, indentLevel + 1));
    // add javascript
    head.addContent(generateJavascriptElement(indentLevel + 1));

    // add the page's inherited style(s)
    String[] pageStyles = introPage.getStyles();
    for (int i = 0; i < pageStyles.length; i++) {
      pageStyle = pageStyles[i];
      if (pageStyle != null)
        head.addContent(generateLinkElement(pageStyle, indentLevel + 1));
    }
    // if there is additional head conent specified in an external file,
    // include it. Additional head content can be specified at the
    // implementation level (which would apply to ALL pages) and at the
    // page level (which would apply only to that particular page).
    // For the implementation's head contribution:
    StringBuffer content = null;
    IntroHead introHead = IntroPlugin.getDefault().getIntroModelRoot().getPresentation().getHead();
    if (introHead != null) {
      content = readFromFile(introHead.getSrc(), introHead.getInlineEncoding());
      if (content != null)
        head.addContent(content);
    }
    // For the page's head contribution:
    // TODO: there should only be one of these at the page level, not a
    // collection..
    IntroHead[] htmlHeads = introPage.getHTMLHeads();
    for (int i = 0; i < htmlHeads.length; i++) {
      introHead = htmlHeads[i];
      if (introHead != null) {
        content = readFromFile(introHead.getSrc(), introHead.getInlineEncoding());
        if (content != null)
          head.addContent(content);
      }
    }
    return head;
  }

  private HTMLElement generateJavascriptElement(int indentLevel) {
    String rel = "javascript/common.js"; //$NON-NLS-1$
    String abs = BundleUtil.getResolvedResourceLocation(rel, IntroPlugin.getDefault().getBundle());
    HTMLElement jselement = new FormattedHTMLElement("script", indentLevel, false); //$NON-NLS-1$
    jselement.addAttribute("type", "text/javascript"); //$NON-NLS-1$ //$NON-NLS-2$
    jselement.addAttribute("src", abs); //$NON-NLS-1$
    return jselement;
  }

  /**
   * Generates the BODY element and its content:
   *
   * <pre>
   *  
   *              
   *                        &lt;BODY&gt;
   *                        &lt;DIV id=&quot;pageId&quot; class=&quot;pageClass&quot;&gt;
   *                        page content
   *                        &lt;/DIV&gt;
   *                        &lt;/BODY&gt;
   *   
   * </pre>
   *
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return the body HTMLElement
   */
  private HTMLElement generateBodyElement(int indentLevel, HTMLElement head) {
    HTMLElement body = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_BODY, indentLevel, true);
    // Create the div that contains the page content
    String pageId = (introPage.getId() != null) ? introPage.getId() : IIntroHTMLConstants.DIV_ID_PAGE;
    HTMLElement pageContentDiv = generateDivElement(pageId, indentLevel + 1);
    if (introPage.getStyleId() != null)
      pageContentDiv.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, introPage.getStyleId());
    if (introPage.getBackgroundImage() != null)
      pageContentDiv.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE,
          "background-image : url(" + introPage.getBackgroundImage() + ")"); //$NON-NLS-1$ //$NON-NLS-2$

    // Add any children of the page, in the order they are defined
    AbstractIntroElement[] children = introPage.getChildren();
    for (int i = 0; i < children.length; i++) {
      AbstractIntroElement child = children[i];
      // use indentLevel + 2 here, since this element is contained within
      // the pageContentDiv
      HTMLElement childElement = generateIntroElement(child, indentLevel + 2);
      if (childElement != null) {
        addMixinStyle(childElement, child.getMixinStyle());
        pageContentDiv.addContent(childElement);
      }
    }
    body.addContent(pageContentDiv);
    return body;
  }

  /**
   * Given an IntroElement, generate the appropriate HTMLElement
   *
   * @param element
   *            the IntroElement
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an HTMLElement
   */
  private HTMLElement generateIntroElement(AbstractIntroElement element, int indentLevel) {
    if (element == null)
      return null;
    // check to see if this element should be filtered from the HTML
    // presentation
    if (filteredFromPresentation(element))
      return null;
    switch (element.getType()) {
    case AbstractIntroElement.GROUP:
      return generateIntroDiv((IntroGroup) element, indentLevel);
    case AbstractIntroElement.LINK:
      return generateIntroLink((IntroLink) element, indentLevel);
    case AbstractIntroElement.HTML:
      return generateIntroHTML((IntroHTML) element, indentLevel);
    case AbstractIntroElement.CONTENT_PROVIDER:
      return generateIntroContent((IntroContentProvider) element, indentLevel);
    case AbstractIntroElement.IMAGE:
      return generateIntroImage((IntroImage) element, indentLevel);
    case AbstractIntroElement.HR:
      return generateIntroSeparator((IntroSeparator) element, indentLevel);     
    case AbstractIntroElement.TEXT:
      return generateIntroText((IntroText) element, indentLevel);
    case AbstractIntroElement.PAGE_TITLE:
      return generateIntroTitle((IntroPageTitle) element, indentLevel);
    case AbstractIntroElement.INJECTED_IFRAME:
      return generateIntroInjectedIFrame((IntroInjectedIFrame) element, indentLevel);
    default:
      return null;
    }
  }

  /**
   * Create a div element and its content from an IntroDiv:
   *
   * <pre>
   *  
   *                   
   *                        &lt;div id=&quot;attrvalue&quot;&gt;
   *                        &lt;h4&gt;&lt;span class=&quot;div-label&quot;&gt;attrvalue&lt;/span&gt;&lt;h4&gt;
   *                        any defined divs, links, html, images, text, includes
   *                        &lt;/div&gt;
   *   
   * </pre>
   *
   * @param element
   *            the IntroDiv
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a div HTMLElement
   */
  private HTMLElement generateIntroDiv(IntroGroup element, int indentLevel) {
    // Create the outer div element
    HTMLElement divElement = generateDivElement(element.getId(), indentLevel);
    HTMLElement childContainer = divElement;
    // if a div class was specified, add it
    if (element.getStyleId() != null)
      divElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, element.getStyleId());
    // Create the div label, if specified
    if (element.getLabel() != null) {
      if (element.isExpandable()) {
        HTMLElement divLabel = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_SPAN,
            indentLevel + 2, false);
        divLabel.addContent(element.getLabel());
        divLabel.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS,
                        "section-title");//$NON-NLS-1$
        String clientId = element.getId() + "-content"; //$NON-NLS-1$
        String toggleClosedId = element.getId() + "-toggle-closed"; //$NON-NLS-1$
        String toggleOpenId = element.getId() + "-toggle-open"; //$NON-NLS-1$
        String href = "#"; //$NON-NLS-1$
        HTMLElement link = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_ANCHOR,
            indentLevel + 1, true);
        link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, href);
        link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, "section-title-link"); //$NON-NLS-1$
        StringBuffer call = new StringBuffer();
        call.append("return (toggleSection('");//$NON-NLS-1$
        call.append(clientId);
        call.append("','");//$NON-NLS-1$
        call.append(toggleClosedId);
        call.append("','");//$NON-NLS-1$
        call.append(toggleOpenId);
        call.append("'))"); //$NON-NLS-1$
        link.addAttribute("onClick", call.toString()); //$NON-NLS-1$
        link.addContent(divLabel);
        divElement.addContent(link);
        // Add toggle images
        HTMLElement toggleImageClosed = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_IMG,
            indentLevel + 2, false, false);
        toggleImageClosed.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, toggleClosedId);
        toggleImageClosed.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SRC, BundleUtil
            .getResolvedResourceLocation(IIntroHTMLConstants.IMAGE_SRC_BLANK,
                IIntroConstants.PLUGIN_ID));
        toggleImageClosed.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, "section-toggle-image-closed"); //$NON-NLS-1$
        if (element.isExpanded())
          toggleImageClosed.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, "display: none"); //$NON-NLS-1$
        link.addContent(toggleImageClosed);
        HTMLElement toggleImageOpen = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_IMG,
            indentLevel + 2, false, false);
        toggleImageOpen.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, toggleOpenId);
        toggleImageOpen.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SRC, BundleUtil
            .getResolvedResourceLocation(IIntroHTMLConstants.IMAGE_SRC_BLANK,
                IIntroConstants.PLUGIN_ID));
        toggleImageOpen.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, "section-toggle-image-open"); //$NON-NLS-1$
        if (element.isExpanded())
          toggleImageOpen.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, "display: inline"); //$NON-NLS-1$       
        link.addContent(toggleImageOpen);
        childContainer = generateDivElement(clientId, indentLevel + 1);
        childContainer.addAttribute("class", "section-body"); //$NON-NLS-1$//$NON-NLS-2$
        if (element.isExpanded())
          childContainer.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, "display: block"); //$NON-NLS-1$
        divElement.addContent(childContainer);
      } else {
        HTMLElement divLabel = generateTextElement(IIntroHTMLConstants.ELEMENT_H4, null,
            IIntroHTMLConstants.SPAN_CLASS_DIV_LABEL, element.getLabel(), indentLevel + 1);
        divElement.addContent(divLabel);
      }
    }
    if (element.getBackgroundImage() != null) {
      String imageUrl = element.getBackgroundImage();
      imageUrl = BundleUtil.getResolvedResourceLocation(element.getBase(), imageUrl, element
          .getBundle());
      String style;
      if (Platform.getWS().equals(Platform.WS_WIN32) && imageUrl.toLowerCase().endsWith(".png")) { //$NON-NLS-1$
        // IE 5.5+ does not handle alphas in PNGs without
        // this hack. Remove when IE7 becomes widespread
        style = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imageUrl + "', sizingMethod='crop');"; //$NON-NLS-1$ //$NON-NLS-2$
      } else {
        style = "background-image : url(" + imageUrl + ")"; //$NON-NLS-1$ //$NON-NLS-2$
      }
      divElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, style);
    }
    // Add any children of the div, in the order they are defined
    AbstractIntroElement[] children = element.getChildren();
    for (int i = 0; i < children.length; i++) {
      AbstractIntroElement child = children[i];
      HTMLElement childElement = generateIntroElement(child, indentLevel + 1);
      if (childElement != null) {
        addMixinStyle(childElement, child.getMixinStyle());
        childContainer.addContent(childElement);
      }
    }
    return divElement;
  }

  private void addMixinStyle(HTMLElement element, String mixinStyle) {
    if (mixinStyle == null)
      return;
    String key = "class"; //$NON-NLS-1$
    String original = (String) element.getElementAttributes().get(key);
    if (original == null)
      original = mixinStyle;
    else
      original += " " + mixinStyle; //$NON-NLS-1$
    element.addAttribute(key, original);
  }

  /**
   * Generates an anchor (link) element and its content from an IntroLink:
   *
   * <pre>
   *  
   *                        &lt;A id=linkId class=&quot;link&quot; href=linkHref&gt;
   *                        &lt;IMG src=&quot;blank.gif&quot;&gt;
   *                        &lt;SPAN class=&quot;link-label&quot;&gt;linkLabel &lt;/SPAN&gt;
   *                        &lt;P&gt;&lt;SPAN&gt;text&lt;/SPAN&gt;&lt;/P&gt;
   *                        &lt;/A&gt;
   *   
   * </pre>
   *
   * @param element
   *            the IntroLink
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an anchor (&lt;A&gt;) HTMLElement
   */
  private HTMLElement generateIntroLink(IntroLink element, int indentLevel) {
    HTMLElement anchor = generateAnchorElement(element, indentLevel);
    // add <IMG src="blank.gif">
    String blankImageURL = BundleUtil.getResolvedResourceLocation(IIntroHTMLConstants.IMAGE_SRC_BLANK,
        IIntroConstants.PLUGIN_ID);
    if (blankImageURL != null) {
      anchor.addContent(generateImageElement(blankImageURL, null, IIntroHTMLConstants.IMAGE_CLASS_BG,
          indentLevel + 1));
    }
    // add link image, if one is specified
    if (element.getImg() != null) {
      HTMLElement img = generateIntroElement(element.getImg(), indentLevel + 1);
      if (img != null)
        anchor.addContent(img);
    }
    HTMLElement imageDiv = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_DIV, indentLevel+1, false);
    imageDiv.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS,
        IIntroHTMLConstants.LINK_EXTRA_DIV);
    anchor.addContent(imageDiv);
    // add <SPAN class="link-label">linkLabel</SPAN>
    if (element.getLabel() != null) {
      HTMLElement label = generateSpanElement(IIntroHTMLConstants.SPAN_CLASS_LINK_LABEL,
          indentLevel + 1);
      label.addContent(element.getLabel());
      anchor.addContent(label);
    }
    IntroText linkText = element.getIntroText();
    if (linkText != null && linkText.getText() != null) {
      HTMLElement text = generateIntroElement(linkText, indentLevel + 1);
      if (text != null)
        anchor.addContent(text);
    }
    return anchor;
  }

  /**
   * Generate the appropriate HTML from an IntroHTML. If the IntroHTML type is "inline", then the
   * content from the referenced file is emitted as-is into a div element. If the type is "embed",
   * an OBJECT html element is created whose <code>data</code> attribute is equal to the
   * IntroHTML's <code>src</code> value
   *
   * @param element
   *            the IntroHTML
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an HTMLElement
   */
  private HTMLElement generateIntroHTML(IntroHTML element, int indentLevel) {
    if (element.isInlined())
      return generateInlineIntroHTML(element, indentLevel);

    return generateEmbeddedIntroHTML(element, indentLevel);
  }

  /**
   * Generate an image element from an IntroImage:
   *
   * <pre>
   *  
   *                        &lt;IMG src=imageSrc id=imageId&gt;
   *   
   * </pre>
   *
   * @param element
   *            the IntroImage
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an img HTMLElement
   */
  private HTMLElement generateIntroImage(IntroImage element, int indentLevel) {
    HTMLElement imageElement = generateImageElement(element.getSrc(), element.getAlt(), element
        .getStyleId(), indentLevel);
    if (element.getId() != null)
      imageElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, element.getId());
    return imageElement;
  }
 
  private HTMLElement generateIntroSeparator(IntroSeparator element, int indentLevel) {
    HTMLElement hrElement = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_HR, indentLevel, false);
    if (element.getId() != null)
      hrElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, element.getId());
    if (element.getStyleId() != null)
      hrElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, element.getStyleId());
    return hrElement;
  }

  /**
   * Generate a paragraph (&lt;P&gt;) element from an IntroText. The paragraph element will
   * contain a span element that will contain the actual text. Providing the span element provides
   * additional flexibility for CSS designers.
   *
   * <pre>
   *             
   *              
   *                        &lt;P&gt;&lt;SPAN&gt;spanContent&lt;/SPAN&gt;&lt;/P&gt;
   *                
   * </pre>
   *
   * @param element
   *            the IntroText
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a paragraph HTMLElement
   */
  private HTMLElement generateIntroText(IntroText element, int indentLevel) {
    String spanClass = (element.getStyleId() != null) ? element.getStyleId()
        : IIntroHTMLConstants.SPAN_CLASS_TEXT;
    HTMLElement textElement = generateTextElement(IIntroHTMLConstants.ELEMENT_PARAGRAPH, element.getId(),
        spanClass, element.getText(), indentLevel);
    return textElement;
  }

  /**
   * @param element
   * @param indentLevel
   * @return
   */
  private HTMLElement generateIntroInjectedIFrame(IntroInjectedIFrame element, int indentLevel) {
    HTMLElement iframe = generateIFrameElement(element.getIFrameURL(), "0", //$NON-NLS-1$
        "auto", indentLevel); //$NON-NLS-1$
    return iframe;
  }

  /**
   * @param element
   * @param indentLevel
   * @return
   */
  private HTMLElement generateIntroTitle(IntroPageTitle element, int indentLevel) {
    HTMLElement titleElement = generateHeaderDiv(element.getId(), element.getStyleId(),
        IIntroHTMLConstants.ELEMENT_H1, element.getTitle(), indentLevel);
    return titleElement;
  }

  /**
   * Generate "inline" content from an IntroHTML. The content from the file referenced by the
   * IntroHTML's <code>src</code> attribute is emitted as-is into a div element:
   *
   * <pre>
   *              
   *                   
   *                        &lt;div id=&quot;attrvalue&quot; class=&quot;attrvalue2&quot;&gt;
   *                        content from file specified in src attribute
   *                        &lt;/div&gt;
   *               
   * </pre>
   *
   * @param element
   *            the IntroHTML
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a div HTMLElement, or null if there was a problem reading from the file
   */
  private HTMLElement generateInlineIntroHTML(IntroHTML element, int indentLevel) {
    // make sure to ask model for encoding. If encoding is null (ie: not
    // specified in
    // markup, local encoding is used.
    StringBuffer content = readFromFile(element.getSrc(), element.getInlineEncoding());
    if (content != null && content.length() > 0) {
      // Create the outer div element
      String divClass = (element.getStyleId() != null) ? element.getStyleId()
          : IIntroHTMLConstants.DIV_CLASS_INLINE_HTML;
      HTMLElement divElement = generateDivElement(element.getId(), divClass, indentLevel);
      // add the content of the specified file into the div element
      divElement.addContent(content);
      return divElement;
    }
    return null;
  }

  /**
   * Includes HTML content that is created by an IIntroContentProvider implementation.
   *
   * @param element
   * @param indentLevel
   * @return
   */
  private HTMLElement generateIntroContent(IntroContentProvider element, int indentLevel) {
    // create a new div to wrap the content
    HTMLElement divElement = generateDivElement(element.getId(),
        IIntroHTMLConstants.DIV_CLASS_PROVIDED_CONTENT, indentLevel);

    // If we've already loaded the content provider for this element,
    // retrieve it, otherwise load the class
    IIntroContentProvider providerClass = ContentProviderManager.getInst().getContentProvider(element);
    if (providerClass == null)
      // content provider never created before, create it.
      providerClass = ContentProviderManager.getInst().createContentProvider(element, providerSite);

    if (providerClass != null) {
      StringWriter stringWriter = new StringWriter();
      PrintWriter pw = new PrintWriter(stringWriter);
      // create the specialized content
      providerClass.createContent(element.getId(), pw);
      // add the content of the specified file into the div element
      stringWriter.flush();
      divElement.addContent(stringWriter.toString());
      pw.close();
    } else {
      // we couldn't load the content provider, so add any alternate
      // text content if there is any
      IntroText htmlText = element.getIntroText();
      if (htmlText != null && htmlText.getText() != null) {
        String textClass = (htmlText.getStyleId() != null) ? htmlText.getStyleId()
            : IIntroHTMLConstants.SPAN_CLASS_TEXT;
        HTMLElement text = generateTextElement(IIntroHTMLConstants.ELEMENT_PARAGRAPH, htmlText
            .getId(), textClass, element.getText(), indentLevel);
        if (text != null)
          divElement.addContent(text);
      }
    }
    return divElement;
  }

  /**
   * Generate "embedded" content from an IntroHTML. An OBJECT html element is created whose
   * <code>data</code> attribute is equal to the IntroHTML's <code>src</code> value.
   *
   * <pre>
   *               
   *                        &lt;OBJECT type=&quot;text/html&quot; data=&quot;attrvalue&quot;&gt;
   *                        alternative text in case the object can not be rendered
   *                        &lt;/OBJECT&gt;
   *    
   * </pre>
   *
   * @param element
   *            the IntroHTML
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an object HTMLElement
   */
  private HTMLElement generateEmbeddedIntroHTML(IntroHTML element, int indentLevel) {
    HTMLElement objectElement = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_OBJECT, indentLevel,
        true);
    objectElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_TYPE, IIntroHTMLConstants.OBJECT_TYPE);
    if (element.getId() != null)
      objectElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, element.getId());
    if (element.getSrc() != null)
      objectElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_DATA, element.getSrc());
    if (element.getStyleId() != null)
      objectElement.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, element.getStyleId());
    // The alternative content is added in case the browser can not render
    // the specified content.
    IntroText htmlText = element.getIntroText();
    if (htmlText != null && htmlText.getText() != null) {
      String textClass = (htmlText.getStyleId() != null) ? htmlText.getStyleId()
          : IIntroHTMLConstants.SPAN_CLASS_TEXT;
      HTMLElement text = generateTextElement(IIntroHTMLConstants.ELEMENT_PARAGRAPH, htmlText.getId(),
          textClass, element.getText(), indentLevel);
      if (text != null)
        objectElement.addContent(text);
    }
    if (element.getIntroImage() != null) {
      HTMLElement img = generateIntroImage(element.getIntroImage(), indentLevel);
      if (img != null)
        objectElement.addContent(img);
    }
    return objectElement;
  }

  /**
   * Generates the BASE element for the head of the html document. Each document can have only one
   * base element
   *
   * <pre>
   *  
   *               
   *                        &lt;BASE href=baseURL&gt;
   * </pre>
   *
   * @param indentLevel
   * @param baseURL
   * @return
   */
  private HTMLElement generateBaseElement(int indentLevel, String baseURL) {
    HTMLElement base = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_BASE, indentLevel, true,
        false);
    if (baseURL != null)
      base.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, baseURL);
    return base;
  }

  /**
   * Generates the style element that goes into HEAD:
   *
   * <pre>
   *               
   *                        &lt;style type=&quot;text/css&quot;&gt;HTML, IMG { border: 0px; } &lt;/style&gt;
   *                  
   * </pre>
   *
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return the style HTMLElement
   */
  private HTMLElement generateStyleElement(int indentLevel) {
    HTMLElement style = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_STYLE, indentLevel, false);
    style.addAttribute(IIntroHTMLConstants.ATTRIBUTE_TYPE, IIntroHTMLConstants.LINK_STYLE);
    style.addContent(IIntroHTMLConstants.STYLE_HTML);
    return style;
  }

  /**
   * Generates the title element and its content:
   *
   * <pre>
   *  
   *                        &lt;TITLE&gt;intro title&lt;/TITLE&gt;
   *                    
   * </pre>
   *
   * @param title
   *            the title of this intro page
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return the title HTMLElement
   */
  private HTMLElement generateTitleElement(String title, int indentLevel) {
    HTMLElement titleElement = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_TITLE, indentLevel,
        false);
    if (title != null)
      titleElement.addContent(title);
    return titleElement;
  }

  /**
   * Generates a link element that refers to a cascading style sheet (CSS):
   *
   * <pre>
   *               
   *                   
   *                        &lt;LINK rel=&quot;stylesheet&quot; style=&quot;text/css&quot; href=&quot;style sheet&quot;&gt;
   * </pre>
   *
   * @param href
   *            the value of the href attribute for this link element
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a link HTMLElement
   */
  private HTMLElement generateLinkElement(String href, int indentLevel) {
    HTMLElement link = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_LINK, indentLevel, true,
        false);
    link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_RELATIONSHIP, IIntroHTMLConstants.LINK_REL);
    link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_TYPE, IIntroHTMLConstants.LINK_STYLE);
    if (href != null)
      link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, href);
    return link;
  }

  /**
   * Generate an anchor element:
   *
   * <pre>
   *  
   *                        &lt;A id=linkId class=linkClass href=linkHref&gt; &lt;/A&gt;
   *                    
   * </pre>
   *
   * @param link
   *            the IntroLink element that contains the value for the id and href attributes
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an anchor (&lt;A&gt;) HTMLElement
   */
  private HTMLElement generateAnchorElement(IntroLink link, int indentLevel) {
    HTMLElement anchor = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_ANCHOR, indentLevel, true);
    if (link.getId() != null)
      anchor.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, link.getId());
    if (link.getUrl() != null)
      anchor.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, link.getUrl());
    if (link.getStyleId() != null)
      anchor.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, link.getStyleId());
    else
      anchor.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, IIntroHTMLConstants.ANCHOR_CLASS_LINK);
    return anchor;
  }

  /**
   * Generates a div block that contains a header and span element:
   *
   * <pre>
   *  
   *                     
   *                        &lt;DIV id=divId&gt;
   *                        &lt;H&gt;&lt;SPAN&gt;spanContent &lt;/SPAN&gt; &lt;/H&gt;
   *                        &lt;/DIV&gt;
   *                    
   * </pre>
   *
   * @param divId
   *            the id of the div to create
   * @param divClass
   *            the class of the div
   * @param headerType
   *            what type of header to create (e.g., H1, H2, etc)
   * @param spanContent
   *            the span content
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a div HTMLElement that contains a header
   */
  private HTMLElement generateHeaderDiv(String divId, String divClass, String headerType,
      String spanContent, int indentLevel) {
    // create the text element: <P><SPAN>spanContent</SPAN></P>
    HTMLElement text = generateTextElement(headerType, null, null, spanContent, indentLevel + 1);
    // create the containing div element
    HTMLElement div = generateDivElement(divId, divClass, indentLevel);
    div.addContent(text);
    return div;
  }

  /**
   * Generates a span element inside a text element, where the text element can be a P
   * (paragraph), or any of the H (Header) elements. Providing the span element provides
   * additional flexibility for CSS designers.
   *
   * <pre>
   *               
   *                        &lt;P&gt;&lt;SPAN&gt;spanContent&lt;/SPAN&gt;&lt;/P&gt;
   *                   
   * </pre>
   *
   * @param type
   *            the type of text element to create (e.g., P, H1, H2, etc)
   * @param spanID
   *            the id of the span element, or null
   * @param spanClass
   *            the class of the span element, or null
   * @param spanContent
   *            the span content
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a text HTMLElement that contains a span element
   */
  private HTMLElement generateTextElement(String type, String spanID, String spanClass, String spanContent,
      int indentLevel) {
    // Create the span: <SPAN>spanContent</SPAN>
    HTMLElement span = new HTMLElement(IIntroHTMLConstants.ELEMENT_SPAN);
    if (spanID != null)
      span.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, spanID);
    if (spanClass != null)
      span.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, spanClass);
    if (spanContent != null)
      span.addContent(spanContent);
    // Create the enclosing text element: <P><SPAN>spanContent</SPAN></P>
    HTMLElement text = new FormattedHTMLElement(type, indentLevel, false);
    text.addContent(span);
    return text;
  }

  /**
   * Generates a DIV element with the provided indent, id, and class.
   *
   * @param divId
   *            value for the div's id attribute
   * @param divClass
   *            value for the div's class attribute
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a div HTMLElement
   */
  private HTMLElement generateDivElement(String divId, String divClass, int indentLevel) {
    HTMLElement div = generateDivElement(divId, indentLevel);
    div.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, divClass);
    return div;
  }

  /**
   * Generates a DIV element with the provided indent and id.
   *
   * @param divId
   *            value for the div's id attribute
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a div HTMLElement
   */
  private HTMLElement generateDivElement(String divId, int indentLevel) {
    HTMLElement div = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_DIV, indentLevel, true);
    if (divId != null)
      div.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ID, divId);
    return div;
  }

  /**
   * Generates an IMG element:
   *
   * <pre>
   *  
   *                     
   *                        &lt;IMG src=imageSrc alt=altText&gt;
   *                    
   * </pre>
   *
   * @param imageSrc
   *            the value to be supplied to the src attribute
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return an img HTMLElement
   */
  private HTMLElement generateImageElement(String imageSrc, String altText, String imageClass,
      int indentLevel) {
    HTMLElement image = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_IMG, indentLevel, true,
        false);
    boolean pngOnWin32 = imageSrc != null && Platform.getWS().equals(Platform.WS_WIN32)
        && imageSrc.toLowerCase().endsWith(".png"); //$NON-NLS-1$
    if (imageSrc == null || pngOnWin32) {
      // we must handle PNGs here - IE does not support alpha blanding well.
      // We will set the alpha image loader and load the real image
      // that way. The 'src' attribute in the image itself will
      // get the blank image.
      String blankImageURL = BundleUtil.getResolvedResourceLocation(
          IIntroHTMLConstants.IMAGE_SRC_BLANK, IIntroConstants.PLUGIN_ID);
      if (blankImageURL != null) {
        image.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SRC, blankImageURL);
        if (pngOnWin32) {
          String style = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imageSrc + "', sizingMethod='image')"; //$NON-NLS-1$//$NON-NLS-2$
          image.addAttribute(IIntroHTMLConstants.ATTRIBUTE_STYLE, style);
        }
      }
    } else
      image.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SRC, imageSrc);
    if (altText == null)
      altText = ""; //$NON-NLS-1$
    image.addAttribute(IIntroHTMLConstants.ATTRIBUTE_ALT, altText);
    if (imageClass != null)
      image.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, imageClass);
    return image;
  }

  /**
   * Generate a span element
   *
   * <pre>
   *  
   *                        &lt;SPAN class=spanClass&gt; &lt;/SPAN&gt;
   *     
   *   
   * </pre>
   *
   * @param spanClass
   *            the value to be supplied to the class attribute
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a span HTMLElement
   */
  private HTMLElement generateSpanElement(String spanClass, int indentLevel) {
    HTMLElement span = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_SPAN, indentLevel, false);
    span.addAttribute(IIntroHTMLConstants.ATTRIBUTE_CLASS, spanClass);
    return span;
  }

  /**
   * Generate a span element
   *
   * <pre>
   *  
   *                     &lt;iframe src=&quot;localPage1.xhtml&quot; frameborder=&quot;1&quot; scrolling=&quot;auto&quot; longdesc=&quot;localPage1.xhtml&quot;&gt;
   * </pre>
   *
   * @param spanClass
   *            the value to be supplied to the class attribute
   * @param indentLevel
   *            the number of indents to insert before the element when it is printed
   * @return a span HTMLElement
   */
  private HTMLElement generateIFrameElement(String src, String frameborder, String scrolling,
      int indentLevel) {
    HTMLElement iframe = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_IFrame, indentLevel, false);
    if (src != null)
      iframe.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SRC, src);
    if (frameborder != null)
      iframe.addAttribute(IIntroHTMLConstants.ATTRIBUTE_FRAMEBORDER, frameborder);
    if (scrolling != null)
      iframe.addAttribute(IIntroHTMLConstants.ATTRIBUTE_SCROLLING, scrolling);
    return iframe;
  }




  private boolean filteredFromPresentation(AbstractIntroElement element) {
    if (element.isOfType(AbstractIntroElement.BASE_ELEMENT))
      return ((AbstractBaseIntroElement) element).isFiltered();

    return false;
  }

  /**
   * Reads the content of the file referred to by the <code>src</code> parameter and returns the
   * content in the form of a StringBuffer. If the file read contains substitution segments of the
   * form $plugin:plugin_id$ then this method will make the proper substitution (the segment will
   * be replaced with the absolute path to the plugin with id plugin_id).
   *
   * @param src -
   *            the file that contains the target conent
   * @param charsetName -
   *            the encoding of the file to be read. If null, local encoding is used. But the
   *            default of the model is UTF-8, so we should not get a null encoding.
   * @return a StringBuffer containing the content in the file, or null
   */
  private StringBuffer readFromFile(String src, String charsetName) {
    if (src == null)
      return null;
    InputStream stream = null;
    StringBuffer content = new StringBuffer();
    BufferedReader reader = null;
    try {
      URL url = new URL(src);
      stream = url.openStream();
      // TODO: Do we need to worry about the encoding here? e.g.:
      // reader = new BufferedReader(new InputStreamReader(stream,
      // ResourcesPlugin.getEncoding()));
      if (charsetName == null)
        reader = new BufferedReader(new InputStreamReader(stream));
      else
        reader = new BufferedReader(new InputStreamReader(stream, charsetName));
      while (true) {
        int character = reader.read();
        if (character == -1) // EOF
          break; // done reading file

        else if (character == PluginIdParser.SUBSTITUTION_BEGIN) { // possible
          // substitution
          PluginIdParser parser = new PluginIdParser(character, reader);
          // If a valid plugin id was found in the proper format, text
          // will be the absolute path to that plugin. Otherwise, text
          // will simply be all characters read up to (but not
          // including)
          // the next dollar sign that follows the one just found.
          String text = parser.parsePluginId();
          if (text != null)
            content.append(text);
        } else {
          // make sure character is in char range before making cast
          if (character > 0x00 && character < 0xffff)
            content.append((char) character);
          else
            content.append(character);
        }
      }
    } catch (Exception exception) {
      Log.error("Error reading from file", exception); //$NON-NLS-1$
    } finally {
      try {
        if (reader != null)
          reader.close();
        if (stream != null)
          stream.close();
      } catch (IOException e) {
        Log.error("Error closing input stream", e); //$NON-NLS-1$
        return null;
      }
    }
    return content;
  }

  /**
   * A helper class to help identify substitution strings in a content file. A properly formatted
   * substitution string is of the form: <code>$plugin:plugin_id$</code> where plugin_id is the
   * valid id of an installed plugin. The substitution string will be replaced with the absolute
   * path to the plugin.
   *
   * An example usage of the string substution: The html file <code>inline.html</code> is
   * included in your intro via the html inline mechanism . This file needs to reference a
   * resource that is located in another plugin. The following might be found in inline.html:
   * <code>
   *    <a href="$plugin:test.plugin$html/test.html">link to file</a>
   * </code> When this file
   * is read in, the relevant section will be replaced as follows: <code>
   *   <a href="file:/install_path/plugins/test.plugin/html/test.html">link to file</a>
   * </code>
   *
   */
  private static class PluginIdParser {

    private BufferedReader reader;

    private static final char SUBSTITUTION_BEGIN = '$';

    private static final char SUBSTITUTION_END = '$';

    // tokenContent will contain all characters read by the parser, starting
    // with and including the initial $ token.
    private StringBuffer tokenContent;

    // pluginId will contain the content between the "$plugin:" segment
    // and the closing "$" token
    private StringBuffer pluginId;

    protected PluginIdParser(char tokenBegin, BufferedReader bufferedreader) {
      reader = bufferedreader;
      tokenContent = new StringBuffer(tokenBegin);
      pluginId = new StringBuffer();
    }

    protected PluginIdParser(int tokenBegin, BufferedReader bufferedreader) {
      reader = bufferedreader;
      tokenContent = new StringBuffer();
      pluginId = new StringBuffer();
      // make sure tokenBegin is in char range before making cast
      if (tokenBegin > 0x00 && tokenBegin < 0xffff)
        tokenContent.append((char) tokenBegin);
    }

    /**
     * This method should be called after the initial substitution identifier has been read in
     * (the substition string begins and ends with the "$" character). A properly formatted
     * substitution string is of the form:</code> "$plugin:plugin_id$</code>- the initial "$"
     * is immediately followed by the "plugin:" segment - the <code>plugin_id </code> refers to
     * a valid, installed plugin - the substitution string is terminated by a closing "$" If the
     * above conditions are not met, no substitution occurs. If the above conditions are met,
     * the content between (and including) the opening and closing "$" characters will be
     * replaced by the absolute path to the plugin
     *
     * @return
     */
    protected String parsePluginId() {
      if (reader == null || tokenContent == null || pluginId == null)
        return null;

      try {
        // Mark the current position of the reader so we can roll
        // back to this point if the proper "plugin:" segment is not
        // found.
        // Use 1024 as our readAheadLimit
        reader.mark(0x400);
        if (findValidPluginSegment()) {
          String pluginPath = getPluginPath();
          if (pluginPath == null) {
            // Didn't find a valid plugin id.
            // return tokenContent, which contains all characters
            // read up to (not including) the last $. (if the
            // last $ is part of a subsequent "$plugin:" segment
            // it can still be processed properly)
            return tokenContent.toString();
          }
          return pluginPath;
        }

        // The "plugin:" segment was not found. Reset the reader
        // so we can continue reading character by character.
        reader.reset();
        return tokenContent.toString();

      } catch (IOException exception) {
        Log.error("Error reading from file", exception); //$NON-NLS-1$
        return tokenContent.toString();
      }
    }

    /**
     * This method should be called after an initial substitution character has been found (that
     * is, after a $). It looks at the subsequent characters in the input stream to determine if
     * they match the expected <code>plugin:</code> segment of the substitution string. If the
     * expected characters are found, they will be appended to the tokenContent StringBuffer and
     * the method will return true. If they are not found, false is returned and the caller
     * should reset the BufferedReader to the position it was in before this method was called.
     *
     * Resetting the reader ensures that the characters read in this method can be re-examined
     * in case one of them happens to be the beginning of a valid substitution segment.
     *
     * @return true if the next characters match <code>plugin:</code>, and false otherwise.
     */
    private boolean findValidPluginSegment() {
      final char[] PLUGIN_SEGMENT = { 'p', 'l', 'u', 'g', 'i', 'n', ':' };
      char[] streamContent = new char[PLUGIN_SEGMENT.length];
      try {
        int peek = reader.read(streamContent, 0, PLUGIN_SEGMENT.length);
        if ((peek == PLUGIN_SEGMENT.length)
            && (HTMLUtil.equalCharArrayContent(streamContent, PLUGIN_SEGMENT))) {
          // we have found the "$plugin:" segment
          tokenContent.append(streamContent);
          return true;
        }
        // The "plugin:" segment did not immediately follow the initial
        // $.
        return false;
      } catch (IOException exception) {
        Log.error("Error reading from file", exception); //$NON-NLS-1$
        return false;
      }
    }

    /**
     * This method continues to read from the input stream until either the end of the file is
     * reached, or until a character is found that indicates the end of the substitution. If the
     * SUBSTITUTION_END character is found, the method looks up the plugin id that has been
     * built up to see if it is a valid id. If so, return the absolute path to that plugin. If
     * not, return null.
     *
     * This method assumes that the reader is positioned just after a valid <code>plugin:</code>
     * segment in a substitution string.
     *
     * @return absolute path of the plugin id, if valid. null otherwise
     */
    private String getPluginPath() {
      try {
        while (true) {
          int nextChar = reader.read();

          if (nextChar == -1) {
            // reached EOF while looking for closing $
            return null;
          } else if (nextChar == SUBSTITUTION_END) { // end of plugin
            // id
            // look up the plugin id. If it is a valid id
            // return the absolute path to this plugin.
            // otherwise return null.
            String path = BundleUtil.getResolvedBundleLocation(pluginId.toString());

            // If the plugin id was not valid, reset reader to the
            // previous mark. The mark should be at the character
            // just before the last dollar sign.
            if (path == null)
              reader.reset();

            return path;
          } else { // we have a regular character
            // mark the most recent non-dollar char in case we don't
            // find a valid plugin id and have to roll back
            // Use 1024 as our readAheadLimit
            reader.mark(0x400);
            // Add this character to the pluginId and tokenContent
            // String.
            // make sure we have a valid character before performing
            // cast
            if (nextChar > 0x00 && nextChar < 0xffff) {
              tokenContent.append((char) nextChar);
              // only include non-whitespace characters in plugin
              // id
              if (!Character.isWhitespace((char) nextChar))
                pluginId.append((char) nextChar);
            } else {
              tokenContent.append(nextChar);
              pluginId.append(nextChar);
            }
          }
        }
      } catch (IOException exception) {
        Log.error("Error reading from file", exception); //$NON-NLS-1$
        return null;
      }
    }
  }

}
TOP

Related Classes of org.eclipse.ui.internal.intro.impl.html.IntroHTMLGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.