diff options
author | Dejan Gloszic | 2006-02-22 06:27:10 +0000 |
---|---|---|
committer | Dejan Gloszic | 2006-02-22 06:27:10 +0000 |
commit | 9e10585f019ddb316a181615c73c2a2f41ad2b06 (patch) | |
tree | d4b24ad520fbc3cdc710f3c3163f4935aad7a7a2 | |
parent | f887a2faf56a3ad7fe14108137db117ffa925446 (diff) | |
download | eclipse.platform.ua-9e10585f019ddb316a181615c73c2a2f41ad2b06.tar.gz eclipse.platform.ua-9e10585f019ddb316a181615c73c2a2f41ad2b06.tar.xz eclipse.platform.ua-9e10585f019ddb316a181615c73c2a2f41ad2b06.zip |
*** empty log message ***
15 files changed, 1346 insertions, 1244 deletions
diff --git a/org.eclipse.ui.intro/javascript/common.js b/org.eclipse.ui.intro/javascript/common.js new file mode 100644 index 000000000..4da3b9c22 --- /dev/null +++ b/org.eclipse.ui.intro/javascript/common.js @@ -0,0 +1,8 @@ + +function toggleSection(id) { + if (document.getElementById) { + var element = document.getElementById(id); + element.style.display=(element.style.display=="block")?"none":"block"; + } + return false; +}
\ No newline at end of file diff --git a/org.eclipse.ui.intro/plugin.xml b/org.eclipse.ui.intro/plugin.xml index bbadaaa02..3739d943e 100644 --- a/org.eclipse.ui.intro/plugin.xml +++ b/org.eclipse.ui.intro/plugin.xml @@ -49,11 +49,13 @@ introId="org.eclipse.ui.intro.universal"> <presentation home-page-id="root" standby-page-id="standby"> + <!-- --> <implementation style="$theme$/html/shared.css" kind="html" os="win32,linux,macosx"> </implementation> + <!-- --> <implementation kind="swt"> </implementation> diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/html/IntroHTMLGenerator.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/html/IntroHTMLGenerator.java index 22d076606..eafd430fe 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/html/IntroHTMLGenerator.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/html/IntroHTMLGenerator.java @@ -1,13 +1,11 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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 +/*************************************************************************************************** + * Copyright (c) 2004, 2005 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 - *******************************************************************************/ + * + * Contributors: IBM Corporation - initial API and implementation + **************************************************************************************************/ package org.eclipse.ui.internal.intro.impl.html; import java.io.BufferedReader; @@ -41,1227 +39,1171 @@ 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> - * - * <HTML> - * <HEAD> - * head content - * </HEAD> - * <BODY> - * body content - * </BODY> - * </HTML> - * - * </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); - html.addContent(head); - html.addContent(body); - return html; - } - - /** - * Generates the HEAD element and its content: - * - * <pre> - * - * - * <HEAD> - * <BASE href="base_plugin_location> - * <style type="text/css">HTML, IMG { border: 0px; } </style> - * <TITLE>page title </TITLE> - * <LINK href="style sheet"> - * additional head content, if specified - * </HEAD> - * - * </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 style = IntroPlugin.getDefault().getIntroModelRoot() - .getPresentation().getImplementationStyle(); - if (style != null && introPage.injectSharedStyle()) - head.addContent(generateLinkElement(style, indentLevel + 1)); - style = introPage.getStyle(); - if (style != null) - head.addContent(generateLinkElement(style, indentLevel + 1)); - // add the page's inherited style(s) - String[] pageStyles = introPage.getStyles(); - for (int i = 0; i < pageStyles.length; i++) { - style = pageStyles[i]; - if (style != null) - head.addContent(generateLinkElement(style, 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; - } - - /** - * Generates the BODY element and its content: - * - * <pre> - * - * - * <BODY> - * <DIV id="pageId" class="pageClass"> - * page content - * </DIV> - * </BODY> - * - * </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 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) - 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.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> - * - * - * <div id="attrvalue"> - * <h4><span class="div-label">attrvalue</span><h4> - * any defined divs, links, html, images, text, includes - * </div> - * - * </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); - // 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) { - 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) - divElement.addContent(childElement); - } - return divElement; - } - - /** - * Generates an anchor (link) element and its content from an IntroLink: - * - * <pre> - * - * <A id=linkId class="link" href=linkHref> - * <IMG src="blank.gif"> - * <SPAN class="link-label">linkLabel </SPAN> - * <P><SPAN>text</SPAN></P> - * </A> - * - * </pre> - * - * @param element - * the IntroLink - * @param indentLevel - * the number of indents to insert before the element when it is - * printed - * @return an anchor (<A>) 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); - } - // 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> - * - * <IMG src=imageSrc id=imageId> - * - * </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; - } - - /** - * Generate a paragraph (<P>) 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> - * - * - * <P><SPAN>spanContent</SPAN></P> - * - * </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> - * - * - * <div id="attrvalue" class="attrvalue2"> - * content from file specified in src attribute - * </div> - * - * </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> - * - * <OBJECT type="text/html" data="attrvalue"> - * alternative text in case the object can not be rendered - * </OBJECT> - * - * </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> - * - * - * <BASE href=baseURL> - * </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> - * - * <style type="text/css">HTML, IMG { border: 0px; } </style> - * - * </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> - * - * <TITLE>intro title</TITLE> - * - * </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> - * - * - * <LINK rel="stylesheet" style="text/css" href="style sheet"> - * </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_STYLE, - IIntroHTMLConstants.LINK_STYLE); - if (href != null) - link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, href); - return link; - } - - /** - * Generate an anchor element: - * - * <pre> - * - * <A id=linkId class=linkClass href=linkHref> </A> - * - * </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 (<A>) 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> - * - * - * <DIV id=divId> - * <H><SPAN>spanContent </SPAN> </H> - * </DIV> - * - * </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> - * - * <P><SPAN>spanContent</SPAN></P> - * - * </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> - * - * - * <IMG src=imageSrc alt=altText> - * - * </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='scale')"; //$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> - * - * <SPAN class=spanClass> </SPAN> - * - * - * </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> - * - * <iframe src="localPage1.xhtml" frameborder="1" scrolling="auto" longdesc="localPage1.xhtml"> - * </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; - } - } - } + 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> + * + * <HTML> + * <HEAD> + * head content + * </HEAD> + * <BODY> + * body content + * </BODY> + * </HTML> + * + * </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> + * + * + * <HEAD> + * <BASE href="base_plugin_location> + * <style type="text/css">HTML, IMG { border: 0px; } </style> + * <TITLE>page title </TITLE> + * <LINK href="style sheet"> + * additional head content, if specified + * </HEAD> + * + * </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 style = IntroPlugin.getDefault().getIntroModelRoot().getPresentation() + .getImplementationStyle(); + if (style != null && introPage.injectSharedStyle()) + head.addContent(generateLinkElement(style, indentLevel + 1)); + style = introPage.getStyle(); + if (style != null) + head.addContent(generateLinkElement(style, 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++) { + style = pageStyles[i]; + if (style != null) + head.addContent(generateLinkElement(style, 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> + * + * + * <BODY> + * <DIV id="pageId" class="pageClass"> + * page content + * </DIV> + * </BODY> + * + * </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.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> + * + * + * <div id="attrvalue"> + * <h4><span class="div-label">attrvalue</span><h4> + * any defined divs, links, html, images, text, includes + * </div> + * + * </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) { + HTMLElement divLabel = generateTextElement(IIntroHTMLConstants.ELEMENT_H4, null, + IIntroHTMLConstants.SPAN_CLASS_DIV_LABEL, element.getLabel(), indentLevel + 1); + if (element.isExpandable()) { + String clientId = element.getId()+"-content"; //$NON-NLS-1$ + String href = "#"; //$NON-NLS-1$ + HTMLElement link = new FormattedHTMLElement(IIntroHTMLConstants.ELEMENT_ANCHOR, + indentLevel + 1, true); + link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, href); + String call = "return (toggleSection('" + clientId + "'))"; //$NON-NLS-1$ //$NON-NLS-2$ + link.addAttribute("onClick", call); //$NON-NLS-1$ + link.addContent(divLabel); + divElement.addContent(link); + childContainer = generateDivElement(clientId, indentLevel+1); + childContainer.addAttribute("class", "section-body"); //$NON-NLS-1$//$NON-NLS-2$ + divElement.addContent(childContainer); + } else + 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> + * + * <A id=linkId class="link" href=linkHref> + * <IMG src="blank.gif"> + * <SPAN class="link-label">linkLabel </SPAN> + * <P><SPAN>text</SPAN></P> + * </A> + * + * </pre> + * + * @param element + * the IntroLink + * @param indentLevel + * the number of indents to insert before the element when it is printed + * @return an anchor (<A>) 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); + } + // 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> + * + * <IMG src=imageSrc id=imageId> + * + * </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; + } + + /** + * Generate a paragraph (<P>) 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> + * + * + * <P><SPAN>spanContent</SPAN></P> + * + * </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> + * + * + * <div id="attrvalue" class="attrvalue2"> + * content from file specified in src attribute + * </div> + * + * </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> + * + * <OBJECT type="text/html" data="attrvalue"> + * alternative text in case the object can not be rendered + * </OBJECT> + * + * </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> + * + * + * <BASE href=baseURL> + * </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> + * + * <style type="text/css">HTML, IMG { border: 0px; } </style> + * + * </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> + * + * <TITLE>intro title</TITLE> + * + * </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> + * + * + * <LINK rel="stylesheet" style="text/css" href="style sheet"> + * </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_STYLE, IIntroHTMLConstants.LINK_STYLE); + if (href != null) + link.addAttribute(IIntroHTMLConstants.ATTRIBUTE_HREF, href); + return link; + } + + /** + * Generate an anchor element: + * + * <pre> + * + * <A id=linkId class=linkClass href=linkHref> </A> + * + * </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 (<A>) 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> + * + * + * <DIV id=divId> + * <H><SPAN>spanContent </SPAN> </H> + * </DIV> + * + * </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> + * + * <P><SPAN>spanContent</SPAN></P> + * + * </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> + * + * + * <IMG src=imageSrc alt=altText> + * + * </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='scale')"; //$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> + * + * <SPAN class=spanClass> </SPAN> + * + * + * </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> + * + * <iframe src="localPage1.xhtml" frameborder="1" scrolling="auto" longdesc="localPage1.xhtml"> + * </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; + } + } + } } diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroContainer.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroContainer.java index 345d4a8e0..7f46a9b02 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroContainer.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroContainer.java @@ -228,7 +228,7 @@ public abstract class AbstractIntroContainer extends AbstractBaseIntroElement { vector.copyInto(filteredElements); // add the elements at the end children's vector. insertElementsBefore(filteredElements, getBundle(), base, children - .size()); + .size(), null); loaded = true; // we cannot free DOM model element because a page's children may be // nulled when reflowing a content provider. @@ -241,13 +241,14 @@ public abstract class AbstractIntroContainer extends AbstractBaseIntroElement { * @param childElements */ protected void insertElementsBefore(Element[] childElements, Bundle bundle, - String base, int index) { + String base, int index, String mixinStyle) { for (int i = 0; i < childElements.length; i++) { Element childElement = childElements[i]; AbstractIntroElement child = getModelChild(childElement, bundle, base); if (child != null) { child.setParent(this); + child.setMixinStyle(mixinStyle); children.add(index, child); // index is only incremented if we actually added a child. index++; @@ -262,12 +263,12 @@ public abstract class AbstractIntroContainer extends AbstractBaseIntroElement { * @param childElements */ protected void insertElementsBefore(Element[] childElements, Bundle bundle, - String base, AbstractIntroElement child) { + String base, AbstractIntroElement child, String mixinStyle) { int childLocation = children.indexOf(child); if (childLocation == -1) // bad reference child. return; - insertElementsBefore(childElements, bundle, base, childLocation); + insertElementsBefore(childElements, bundle, base, childLocation, mixinStyle); } diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroElement.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroElement.java index 0c7a5290b..d841b225c 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroElement.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/AbstractIntroElement.java @@ -175,6 +175,7 @@ public abstract class AbstractIntroElement extends FilterableUAElement implement private AbstractIntroElement parent; private IConfigurationElement cfgElement; private Bundle bundle; + private String mixinStyle; /** @@ -443,5 +444,17 @@ public abstract class AbstractIntroElement extends FilterableUAElement implement } + + public String getMixinStyle() { + return mixinStyle; + } + + + + public void setMixinStyle(String mixinStyle) { + this.mixinStyle = mixinStyle; + } + + }
\ No newline at end of file diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroGroup.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroGroup.java index a74900e4a..217b7a2a3 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroGroup.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroGroup.java @@ -26,6 +26,7 @@ public class IntroGroup extends AbstractIntroContainer { protected static final String TAG_GROUP = "group"; //$NON-NLS-1$ private static final String ATT_LABEL = "label"; //$NON-NLS-1$ private static final String ATT_COMPUTED = "computed"; //$NON-NLS-1$ + private static final String ATT_EXPANDABLE = "expandable"; //$NON-NLS-1$ private String label; /** * @param element @@ -51,6 +52,11 @@ public class IntroGroup extends AbstractIntroContainer { return AbstractIntroElement.GROUP; } + public boolean isExpandable() { + String value=getAttribute(element, ATT_EXPANDABLE); + return value!=null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ + } + protected void loadChildren() { String value = getAttribute(element, ATT_COMPUTED); if (value!=null && value.equalsIgnoreCase("true")) //$NON-NLS-1$ diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroModelRoot.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroModelRoot.java index f2671331a..0991d0e2a 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroModelRoot.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/model/IntroModelRoot.java @@ -579,8 +579,24 @@ public class IntroModelRoot extends AbstractIntroContainer { AbstractIntroContainer anchorParent = (AbstractIntroContainer) anchor .getParent(); // insert the elements of the extension before the anchor. - anchorParent.insertElementsBefore(extensionContent.getChildren(), - bundle, base, anchor); + String mixinStyle = getMixinStyle(extensionContent); + Element [] children = extensionContent.getChildren(); + anchorParent.insertElementsBefore(children, + bundle, base, anchor, mixinStyle); + } + + private String getMixinStyle(IntroExtensionContent extensionContent) { + String path = extensionContent.getPath(); + if (!path.endsWith("/@")) //$NON-NLS-1$ + return null; + String pageId = path.substring(0, path.length()-2); + IntroModelRoot modelRoot = getModelRoot(); + if (modelRoot==null) + return null; + IntroConfigurer configurer = modelRoot.getConfigurer(); + if (configurer==null) + return null; + return configurer.getMixinStyle(pageId, extensionContent.getId()); } diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/swt/PageWidgetFactory.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/swt/PageWidgetFactory.java index 1714a163a..280bee1b1 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/swt/PageWidgetFactory.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/impl/swt/PageWidgetFactory.java @@ -188,10 +188,13 @@ public class PageWidgetFactory { private Composite createGroup(Composite parent, IntroGroup group) { String label = group.getLabel(); String description = styleManager.getDescription(group); + boolean expandable = group.isExpandable(); Composite client = null; Composite control = null; - if (description != null || label != null) { + if (description != null || label != null || expandable) { int style = description != null ? Section.DESCRIPTION : SWT.NULL; + if (expandable) + style |= Section.TWISTIE | Section.FOCUS_TITLE | Section.CLIENT_INDENT; Section section = toolkit.createSection(parent, style); if (label != null) section.setText(label); diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ExtensionData.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ExtensionData.java index a17677bf0..3d2a45c79 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ExtensionData.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ExtensionData.java @@ -24,6 +24,10 @@ public class ExtensionData { ISharedIntroConstants.LOW, ISharedIntroConstants.MEDIUM, ISharedIntroConstants.HIGH, ISharedIntroConstants.NEW }; + public static final String[] IMPORTANCE_STYLE_TABLE = { ISharedIntroConstants.STYLE_CALLOUT, + ISharedIntroConstants.STYLE_LOW, ISharedIntroConstants.STYLE_MEDIUM, ISharedIntroConstants.STYLE_HIGH, + ISharedIntroConstants.STYLE_NEW }; + public static final String [] IMPORTANCE_NAME_TABLE = { Messages.ExtensionData_callout, Messages.ExtensionData_low, Messages.ExtensionData_medium, Messages.ExtensionData_high, Messages.ExtensionData_new }; diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ISharedIntroConstants.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ISharedIntroConstants.java index 2901091a9..9e3209e06 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ISharedIntroConstants.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/ISharedIntroConstants.java @@ -8,6 +8,12 @@ public interface ISharedIntroConstants { String CALLOUT = "callout"; //$NON-NLS-1$ String HIDDEN = "hidden"; //$NON-NLS-1$ String NEW = "new"; //$NON-NLS-1$ + + String STYLE_LOW = "importance-low"; //$NON-NLS-1$ + String STYLE_MEDIUM = "importance-medium"; //$NON-NLS-1$ + String STYLE_HIGH = "importance-high"; //$NON-NLS-1$ + String STYLE_CALLOUT = "importance-callout"; //$NON-NLS-1$ + String STYLE_NEW = "importance-new"; //$NON-NLS-1$ String DEFAULT_ANCHOR = "defaultAnchor"; //$NON-NLS-1$ String DEFAULT_CONTENT_PATH = "/page-content/bottom/"+DEFAULT_ANCHOR; //$NON-NLS-1$ // Page ids diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/PageData.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/PageData.java index e64c0e22e..b24fb5380 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/PageData.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/PageData.java @@ -89,7 +89,7 @@ public class PageData { } return null; } - + private void addGroup(Element element, boolean hide) { GroupData gd = new GroupData(element); if (hide) hidden = gd; @@ -98,7 +98,7 @@ public class PageData { } public void addImplicitExtension(String extensionId, String name) { - ExtensionData ed = findExtension(extensionId); + ExtensionData ed = findExtension(extensionId, true); if (ed!=null) { // see if name needs to be supplied if (ed.getName()==null || ed.getName().length()==0) @@ -134,7 +134,7 @@ public class PageData { return id; } - private ExtensionData findExtension(String extensionId) { + public ExtensionData findExtension(String extensionId, boolean checkHidden) { for (int i=0; i<groups.size(); i++) { GroupData gdata = (GroupData)groups.get(i); ExtensionData ed = gdata.find(extensionId); @@ -142,7 +142,7 @@ public class PageData { return ed; } // check the hidden - if (hidden!=null) + if (checkHidden && hidden!=null) return hidden.find(extensionId); return null; } diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/UniversalIntroConfigurer.java b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/UniversalIntroConfigurer.java index 92f1341bb..8ebecc8aa 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/UniversalIntroConfigurer.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/internal/intro/universal/UniversalIntroConfigurer.java @@ -71,6 +71,25 @@ public class UniversalIntroConfigurer extends IntroConfigurer implements IShared return null; } + /* (non-Javadoc) + * @see org.eclipse.ui.intro.config.IntroConfigurer#getMixinStyle(java.lang.String) + */ + public String getMixinStyle(String pageId, String extensionId) { + if (introData.size()>0) { + // TODO getting the active product one only + // Eventually we should consult the data from all the products + IntroData idata = (IntroData) introData.get(0); + PageData pdata = idata.getPage(pageId); + if (pdata != null) { + ExtensionData ed = pdata.findExtension(extensionId, false); + int importance = ed.getImportance(); + if (importance!=ExtensionData.HIDDEN) + return ExtensionData.IMPORTANCE_STYLE_TABLE[importance]; + } + } + return null; + } + private String resolveVariable(Bundle bundle, String value) { if (value != null) { String path = null; diff --git a/org.eclipse.ui.intro/src/org/eclipse/ui/intro/config/IntroConfigurer.java b/org.eclipse.ui.intro/src/org/eclipse/ui/intro/config/IntroConfigurer.java index 4b5dca362..5f26db971 100644 --- a/org.eclipse.ui.intro/src/org/eclipse/ui/intro/config/IntroConfigurer.java +++ b/org.eclipse.ui.intro/src/org/eclipse/ui/intro/config/IntroConfigurer.java @@ -71,4 +71,20 @@ public abstract class IntroConfigurer { * <code>null</code> if the path cannot be resolved or the extension should be hidden. */ public abstract String resolvePath(String extensionId, String path); + + /** + * Returns the style value that will be mixed in with the original style of the extension. + * Themes can use this feature to render certain extensions differently. + * + * @param pageId + * the identifier of the target page that this extension + * is contributed into + * @param extensionId + * the identifier of the extension to provide the mixin style for. + * @return the style to add to the original extension style or <code>null</code> if no mixin + * style is found for this extension. + */ + public String getMixinStyle(String pageId, String extensionId) { + return null; + } }
\ No newline at end of file diff --git a/org.eclipse.ui.intro/themes/purpleMesh/html/shared.css b/org.eclipse.ui.intro/themes/purpleMesh/html/shared.css index c86f75625..10f5f14b4 100644 --- a/org.eclipse.ui.intro/themes/purpleMesh/html/shared.css +++ b/org.eclipse.ui.intro/themes/purpleMesh/html/shared.css @@ -74,6 +74,9 @@ html, body, div, h1, h4, p, a { margin : 0px; padding : 0px; } .intro-header H1 { padding-top : 10px; margin-left : 10px; } +.section { } +.section-body { display: none; padding : 0px; } + /* For regular div labels */ #page-content div H4 { padding : 10px; @@ -230,7 +233,7 @@ body, .page{ #navigation-links a#whatsnew:focus img, #navigation-links a#whatsnew:active img { background-image : url(../graphics/icons/ctool/whatsnew48.gif); } -#navigation-links a#workbench { position : absolute; right : 0px; top : 0px; text-align : right;} +#navigation-links a#workbench { position : absolute; right : 0px; top : -35px; text-align : right;} #navigation-links a#workbench .text { display : none; } #navigation-links a#workbench img { background-image : url(../graphics/icons/etool/wb48.gif); width : 53px; height : 53px;} #navigation-links a#workbench:hover img, @@ -265,26 +268,66 @@ h1, p { margin-left : 10px; } /* required in mozilla so the page description is #page-content #top-left { border: none; float: left; margin: 0; padding: 0; width: 50%; + /* background-color: #ffc0c0; + */ clear: left; } #page-content #top-right { border: none; float: right; margin: 0; padding: 0; width: 50%; + /* background-color: #c0ffc0; + */ clear: right; } +/* top-bottom divider - runs the entire width to ensure + * bottom boxes start at the same y + */ +#page-content #content-divider { + border: none; float: none; margin: 0; padding: 0; width: 100%; + /* + background-color: #c0c0c0; + */ + clear: both; +} + #page-content #bottom-left { border: none; float: left; margin: 0; padding: 0; width: 50%; - background-color: #ffc0c0; + /* + background-color: #ffffc0; + */ clear: left; } #page-content #bottom-right { border: none; float: right; margin: 0; padding: 0; width: 50%; - background-color: #c0ffc0; + /* + background-color: #c0ffff; + */ clear: right; } +/* + * Extension importance styles + */ +.importance-low { +} + +.importance-medium { + background-color: #ffdddd; +} + +.importance-high { + background-color: #ffffdd; +} + +.importance-new { +} + +.importance-callout { + background-color: #cccccc; +} + #page-content #content-header H4, .page-description { text-align : left; margin-right : 10px; diff --git a/org.eclipse.ui.intro/universal/introContent.xml b/org.eclipse.ui.intro/universal/introContent.xml index 5ef20769d..7dada35ee 100644 --- a/org.eclipse.ui.intro/universal/introContent.xml +++ b/org.eclipse.ui.intro/universal/introContent.xml @@ -49,6 +49,7 @@ <!-- Overview page --> <page id="overview" style="$theme$/html/overview.css" alt-style="$theme$/swt/overview.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -67,6 +68,7 @@ <text style-id="page-description" id="page-description">Eclipse is a kind of universal tool platform - an open extensible IDE for anything and nothing in particular. It provides a feature-rich development environment that allows the developer to efficiently create tools that integrate seamlessly into the Eclipse Platform.</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -74,7 +76,10 @@ <group id="extra-group3" filteredFrom="swt"><anchor id="anchor"/></group> <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + + <!-- Tutorials page --> <page id="tutorials" style="$theme$/html/tutorials.css" alt-style="$theme$/swt/tutorials.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -93,6 +98,7 @@ <text style-id="page-description" id="page-description">Learn how to be productive using Eclipse by completing end-to-end tutorials that will guide you along the way.</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -100,7 +106,10 @@ <group id="extra-group3" filteredFrom="swt"><anchor id="anchor"/></group> <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + + <!-- Samples page --> <page id="samples" style="$theme$/html/samples/samples.css" alt-style="$theme$/swt/samples.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -119,6 +128,7 @@ <text style-id="page-description" id="page-description">Explore Eclipse by installing prefabricated samples (may require Internet connection).</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -127,7 +137,9 @@ <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + <!-- What's New page --> <page id="whatsnew" style="$theme$/html/whatsnew.css" alt-style="$theme$/swt/whatsnew.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -145,6 +157,7 @@ <text style-id="page-title" id="page-title" filteredFrom="html">WHAT'S NEW</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -153,7 +166,9 @@ <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + <!-- First Steps page --> <page id="firststeps" style="$theme$/html/firststeps.css" alt-style="$theme$/swt/firststeps.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -171,6 +186,7 @@ <text style-id="page-title" id="page-title" filteredFrom="html">FIRST STEPS</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -179,7 +195,9 @@ <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + <!-- Web resources page --> <page id="webresources" style="$theme$/html/webresources.css" alt-style="$theme$/swt/webresources.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> </group> @@ -196,6 +214,7 @@ <text style-id="page-title" id="page-title" filteredFrom="html">WEB RESOURCE</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> @@ -204,7 +223,10 @@ <group id="extra-group4" filteredFrom="swt"><anchor id="anchor"/></group> </page> + + <!-- Migrate page --> <page id="migrate" style="$theme$/html/migrate.css" alt-style="$theme$/swt/migrate.properties" style-id="page"> + <title style-id="intro-header">$introTitle$</title> <group id="extra-group1" filteredFrom="swt"/> <group id="navigation-links" filteredFrom="swt"> <group id="page-links" computed="true"> @@ -222,6 +244,7 @@ <text style-id="page-title" id="page-title" filteredFrom="html">MIGRATE</text> <group id="top-left" computed="true"/> <group id="top-right" computed="true"/> + <group id="content-divider"/> <group id="bottom-left" computed="true"/> <group id="bottom-right" computed="true"/> </group> |