001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.core.builders;
011:
012: import java.io.IOException;
013: import java.io.PrintWriter;
014: import java.net.URL;
015: import java.util.Locale;
016:
017: import org.eclipse.core.runtime.FileLocator;
018: import org.eclipse.core.runtime.IProduct;
019: import org.eclipse.core.runtime.Platform;
020: import org.eclipse.pde.internal.core.PDECore;
021: import org.eclipse.pde.internal.core.ischema.IDocumentSection;
022: import org.eclipse.pde.internal.core.ischema.ISchema;
023: import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
024: import org.eclipse.pde.internal.core.ischema.ISchemaElement;
025: import org.eclipse.pde.internal.core.ischema.ISchemaInclude;
026: import org.eclipse.pde.internal.core.ischema.ISchemaRestriction;
027: import org.eclipse.pde.internal.core.ischema.ISchemaSimpleType;
028: import org.eclipse.pde.internal.core.schema.ChoiceRestriction;
029: import org.eclipse.pde.internal.core.schema.DocumentSection;
030: import org.eclipse.pde.internal.core.schema.SchemaRootElement;
031: import org.osgi.framework.Bundle;
032:
033: public class SchemaTransformer {
034:
035: private static final String PLATFORM_PLUGIN = "org.eclipse.platform"; //$NON-NLS-1$
036: private static final String PLATFORM_PLUGIN_DOC = "org.eclipse.platform.doc.isv"; //$NON-NLS-1$
037: private static final String SCHEMA_CSS = "schema.css"; //$NON-NLS-1$
038: private static final String PLATFORM_CSS = "book.css"; //$NON-NLS-1$
039:
040: public static final byte TEMP = 0x00;
041: public static final byte BUILD = 0x01;
042:
043: private byte fCssPurpose;
044: private PrintWriter fWriter;
045: private ISchema fSchema;
046: private URL fCssURL;
047:
048: public void transform(ISchema schema, PrintWriter out) {
049: transform(schema, out, null, TEMP);
050: }
051:
052: public void transform(ISchema schema, PrintWriter out, URL cssURL,
053: byte cssPurpose) {
054: fSchema = schema;
055: fWriter = out;
056: fCssPurpose = cssPurpose;
057: setCssURL(cssURL);
058: printHTMLContent();
059: }
060:
061: private void setCssURL(URL cssURL) {
062: try {
063: if (cssURL != null)
064: fCssURL = FileLocator.resolve(cssURL);
065: } catch (IOException e) {
066: }
067: if (fCssURL == null && fCssPurpose != BUILD)
068: fCssURL = getResourceURL(getProductPlugin(), PLATFORM_CSS);
069: if (fCssURL == null && fCssPurpose != BUILD)
070: fCssURL = getResourceURL(PDECore.PLUGIN_ID, PLATFORM_CSS);
071: }
072:
073: private String getCssURL() {
074: return (fCssURL != null) ? fCssURL.toString()
075: : "../../" + PLATFORM_CSS; //$NON-NLS-1$
076: }
077:
078: private String getSchemaCssURL() {
079: if (fCssPurpose == BUILD)
080: return "../../" + SCHEMA_CSS; //$NON-NLS-1$
081: URL url = getResourceURL(PLATFORM_PLUGIN_DOC, SCHEMA_CSS);
082: if (url == null) {
083: // this CSS file is last resort and is always there.
084: url = getResourceURL(PDECore.PLUGIN_ID, SCHEMA_CSS);
085: }
086: return url.toString();
087: }
088:
089: private void printHTMLContent() {
090: fWriter
091: .println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"); //$NON-NLS-1$
092: fWriter.println("<HTML>"); //$NON-NLS-1$
093: printHeader();
094: printBody();
095: fWriter.println("</HTML>"); //$NON-NLS-1$
096: }
097:
098: private void printHeader() {
099: fWriter.print("<HEAD>"); //$NON-NLS-1$
100: fWriter
101: .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">"); //$NON-NLS-1$
102: fWriter.println("<title>" + fSchema.getName() + "</title>"); //$NON-NLS-1$ //$NON-NLS-2$
103: printStyles();
104: fWriter.println("</HEAD>"); //$NON-NLS-1$
105: }
106:
107: private void printStyles() {
108: fWriter
109: .println("<style type=\"text/css\">@import url(\"" + getCssURL() + "\");</style>"); //$NON-NLS-1$ //$NON-NLS-2$
110: fWriter
111: .println("<style type=\"text/css\">@import url(\"" + getSchemaCssURL() + "\");</style>"); //$NON-NLS-1$ //$NON-NLS-2$
112: }
113:
114: private URL getResourceURL(String bundleID, String resourcePath) {
115: try {
116: Bundle bundle = Platform.getBundle(bundleID);
117: if (bundle != null) {
118: URL entry = bundle.getEntry(resourcePath);
119: if (entry != null)
120: return FileLocator.toFileURL(entry);
121: }
122: } catch (IOException e) {
123: }
124: return null;
125: }
126:
127: private void printBody() {
128: fWriter.println("<BODY>"); //$NON-NLS-1$
129: fWriter
130: .println("<H1 style=\"text-align:center\">" + fSchema.getName() + "</H1>"); //$NON-NLS-1$ //$NON-NLS-2$
131: if (fSchema.isDeperecated()) {
132: fWriter
133: .print("<div style=\"border: 1px solid #990000; padding: 5px; text-align: center; color: red;\">"); //$NON-NLS-1$
134: fWriter.print("This extension point is deprecated"); //$NON-NLS-1$
135: String suggestion = fSchema.getDeprecatedSuggestion();
136: if (suggestion != null)
137: fWriter
138: .print(", use <i>" + suggestion + "</i> as a replacement."); //$NON-NLS-1$ //$NON-NLS-2$
139: fWriter.println("</div>"); //$NON-NLS-1$
140: }
141: fWriter.println("<p></p>"); //$NON-NLS-1$
142: fWriter
143: .print("<h6 class=\"CaptionFigColumn SchemaHeader\">Identifier: </h6>"); //$NON-NLS-1$
144: fWriter.print(fSchema.getQualifiedPointId());
145: fWriter.println("<p></p>"); //$NON-NLS-1$
146: transformSection("Since:", IDocumentSection.SINCE); //$NON-NLS-1$
147: transformDescription();
148: fWriter
149: .println("<h6 class=\"CaptionFigColumn SchemaHeader\">Configuration Markup:</h6>"); //$NON-NLS-1$
150: transformMarkup();
151: transformSection("Examples:", IDocumentSection.EXAMPLES); //$NON-NLS-1$
152: transformSection("API Information:", IDocumentSection.API_INFO); //$NON-NLS-1$
153: transformSection(
154: "Supplied Implementation:", IDocumentSection.IMPLEMENTATION); //$NON-NLS-1$
155: fWriter.println("<br>"); //$NON-NLS-1$
156: fWriter.println("<p class=\"note SchemaCopyright\">"); //$NON-NLS-1$
157: transformSection(null, IDocumentSection.COPYRIGHT);
158: fWriter.println("</p>"); //$NON-NLS-1$
159: fWriter.println("</BODY>"); //$NON-NLS-1$
160: }
161:
162: private void transformSection(String title, String sectionId) {
163: IDocumentSection section = findSection(fSchema
164: .getDocumentSections(), sectionId);
165: if (section == null)
166: return;
167: String description = section.getDescription();
168: if (description == null || description.trim().length() == 0)
169: return;
170: if (title != null)
171: fWriter
172: .print("<h6 class=\"CaptionFigColumn SchemaHeader\">" + title + " </h6>"); //$NON-NLS-1$ //$NON-NLS-2$
173: transformText(description);
174: fWriter.println();
175: if (!sectionId.equals(IDocumentSection.COPYRIGHT))
176: fWriter.println("<p></p>"); //$NON-NLS-1$
177: fWriter.println();
178: }
179:
180: private DocumentSection findSection(IDocumentSection[] sections,
181: String sectionId) {
182: for (int i = 0; i < sections.length; i++) {
183: if (sections[i].getSectionId().equals(sectionId)) {
184: return (DocumentSection) sections[i];
185: }
186: }
187: return null;
188: }
189:
190: private void transformText(String text) {
191: if (text == null)
192: return;
193: boolean preformatted = false;
194: boolean inTag = false;
195: boolean inCstring = false;
196:
197: for (int i = 0; i < text.length(); i++) {
198: char c = text.charAt(i);
199: if (c == '<') {
200: if (isPreStart(text, i)) {
201: fWriter
202: .print("<pre class=\"Example\"><span class=\"code SchemaTag\">"); //$NON-NLS-1$
203: i += 4;
204: preformatted = true;
205: continue;
206: }
207: if (isPreEnd(text, i)) {
208: fWriter.print("</span></pre>"); //$NON-NLS-1$
209: i += 5;
210: preformatted = false;
211: inTag = false;
212: inCstring = false;
213: continue;
214: }
215: }
216: if (preformatted) {
217: switch (c) {
218: case '<':
219: inTag = true;
220: fWriter.print("<"); //$NON-NLS-1$
221: break;
222: case '>':
223: fWriter.print(">"); //$NON-NLS-1$
224: inTag = false;
225: inCstring = false;
226: break;
227: case '&':
228: fWriter.print("&"); //$NON-NLS-1$
229: break;
230: case '\'':
231: fWriter.print("'"); //$NON-NLS-1$
232: break;
233: case '\"':
234: if (inTag) {
235: if (inCstring) {
236: fWriter.print("""); //$NON-NLS-1$
237: fWriter
238: .print("</span><span class=\"code SchemaTag\">"); //$NON-NLS-1$
239: inCstring = false;
240: } else {
241: inCstring = true;
242: fWriter
243: .print("</span><span class=\"code SchemaCstring\">"); //$NON-NLS-1$
244: fWriter.print("""); //$NON-NLS-1$
245: }
246: } else {
247: fWriter.print("\""); //$NON-NLS-1$
248: }
249: break;
250: default:
251: fWriter.print(c);
252: }
253: } else
254: fWriter.print(c);
255: }
256: }
257:
258: private void transformDescription() {
259: fWriter
260: .print("<h6 class=\"CaptionFigColumn SchemaHeader\">Description: </h6>"); //$NON-NLS-1$
261: transformText(fSchema.getDescription());
262: ISchemaInclude[] includes = fSchema.getIncludes();
263: for (int i = 0; i < includes.length; i++) {
264: ISchema ischema = includes[i].getIncludedSchema();
265: if (ischema != null) {
266: fWriter.println("<p>"); //$NON-NLS-1$
267: transformText(ischema.getDescription());
268: }
269: }
270: fWriter.println("<p></p>"); //$NON-NLS-1$
271: }
272:
273: private void transformMarkup() {
274: fWriter.println("<p></p>"); //$NON-NLS-1$
275: ISchemaElement[] elements = fSchema.getResolvedElements();
276: for (int i = 0; i < elements.length; i++) {
277: transformElement(elements[i]);
278: }
279: }
280:
281: private void transformElement(ISchemaElement element) {
282: String name = element.getName();
283: String dtd = element.getDTDRepresentation(true);
284: String nameLink = "<a name=\"e." + name + "\">" + name + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
285:
286: if (element.isDeprecated()
287: && !(element instanceof SchemaRootElement))
288: fWriter
289: .print("<div style=\"color: red; font-style: italic;\">The <b>" + name + "</b> element is deprecated</div> "); //$NON-NLS-1$ //$NON-NLS-2$
290:
291: fWriter.print("<p class=\"code SchemaDtd\"><!ELEMENT " //$NON-NLS-1$
292: + nameLink + " " //$NON-NLS-1$
293: + dtd);
294: fWriter.println("></p>"); //$NON-NLS-1$
295:
296: ISchemaAttribute[] attributes = element.getAttributes();
297:
298: if (attributes.length > 0) {
299: fWriter.println("<p class=\"code SchemaDtd\"><!ATTLIST " //$NON-NLS-1$
300: + name + "</p>"); //$NON-NLS-1$
301: int maxWidth = calculateMaxAttributeWidth(element
302: .getAttributes());
303: for (int i = 0; i < attributes.length; i++) {
304: appendAttlist(attributes[i], maxWidth);
305: }
306: fWriter.println("></p>"); //$NON-NLS-1$
307:
308: }
309: fWriter.println("<p></p>"); //$NON-NLS-1$
310:
311: // inserted desc here for element
312: String description = element.getDescription();
313:
314: if (description != null && description.trim().length() > 0) {
315: String elementType = containsParagraph(description) ? "div" : "p"; //$NON-NLS-1$ //$NON-NLS-2$
316: fWriter
317: .println("<" + elementType + " class=\"ConfigMarkupElementDesc\">"); //$NON-NLS-1$ //$NON-NLS-2$
318: transformText(description);
319: fWriter.println("</" + elementType + ">"); //$NON-NLS-1$ //$NON-NLS-2$
320: }
321: // end of inserted desc for element
322: if (attributes.length == 0) {
323: fWriter.println("<br><br>"); //$NON-NLS-1$
324: return;
325: } else if (description != null
326: && description.trim().length() > 0) {
327: fWriter.println("<br>"); //$NON-NLS-1$
328: }
329:
330: fWriter.println("<ul class=\"ConfigMarkupAttlistDesc\">"); //$NON-NLS-1$
331: for (int i = 0; i < attributes.length; i++) {
332: ISchemaAttribute att = attributes[i];
333: if (name.equals("extension")) { //$NON-NLS-1$
334: if (att.getDescription() == null
335: || att.getDescription().trim().length() == 0) {
336: continue;
337: }
338: }
339: fWriter.print("<li>"); //$NON-NLS-1$
340: if (att.isDeprecated())
341: fWriter
342: .print("<i style=\"color: red;\">Deprecated</i> "); //$NON-NLS-1$
343: fWriter.print("<b>" + att.getName() + "</b> - "); //$NON-NLS-1$ //$NON-NLS-2$
344: transformText(att.getDescription());
345: fWriter.println("</li>"); //$NON-NLS-1$
346: }
347: fWriter.println("</ul>"); //$NON-NLS-1$
348: // adding spaces for new shifted view
349: fWriter.print("<br>"); //$NON-NLS-1$
350: }
351:
352: private boolean containsParagraph(String input) {
353: if (input.indexOf("<p>") != -1) //$NON-NLS-1$
354: return true;
355: if (input.indexOf("</p>") != -1) //$NON-NLS-1$
356: return true;
357: return false;
358: }
359:
360: private void appendAttlist(ISchemaAttribute att, int maxWidth) {
361: fWriter.print("<p class=\"code SchemaDtdAttlist\">"); //$NON-NLS-1$
362: // add name
363: fWriter.print(att.getName());
364: // fill spaces to align data type
365: int delta = maxWidth - att.getName().length();
366: for (int i = 0; i < delta + 1; i++) {
367: fWriter.print(" "); //$NON-NLS-1$
368: }
369: // add data type
370: ISchemaSimpleType type = att.getType();
371: ISchemaRestriction restriction = null;
372: boolean choices = false;
373: if (type != null)
374: restriction = type.getRestriction();
375: String typeName = type != null ? type.getName().toLowerCase(
376: Locale.ENGLISH) : "string"; //$NON-NLS-1$
377: if (typeName.equals("boolean")) { //$NON-NLS-1$
378: fWriter.print("(true | false) "); //$NON-NLS-1$
379: choices = true;
380: } else if (restriction != null) {
381: appendRestriction(restriction);
382: choices = true;
383: } else {
384: fWriter.print("CDATA "); //$NON-NLS-1$
385: }
386:
387: // add use
388: if (att.getUse() == ISchemaAttribute.REQUIRED) {
389: if (!choices)
390: fWriter.print("#REQUIRED"); //$NON-NLS-1$
391: } else if (att.getUse() == ISchemaAttribute.DEFAULT) {
392: fWriter.print("\"" + att.getValue() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
393: } else if (!choices)
394: fWriter.print("#IMPLIED"); //$NON-NLS-1$
395: }
396:
397: private void appendRestriction(ISchemaRestriction restriction) {
398: if (restriction instanceof ChoiceRestriction) {
399: String[] choices = ((ChoiceRestriction) restriction)
400: .getChoicesAsStrings();
401: fWriter.print("("); //$NON-NLS-1$
402: for (int i = 0; i < choices.length; i++) {
403: if (i > 0)
404: fWriter.print("|"); //$NON-NLS-1$
405: fWriter.print(choices[i]);
406: }
407: fWriter.print(") "); //$NON-NLS-1$
408: }
409: }
410:
411: private boolean isPreEnd(String text, int loc) {
412: if (loc + 5 >= text.length())
413: return false;
414: return (text.substring(loc, loc + 6)
415: .toLowerCase(Locale.ENGLISH).equals("</pre>")); //$NON-NLS-1$
416: }
417:
418: private boolean isPreStart(String text, int loc) {
419: if (loc + 4 >= text.length())
420: return false;
421: return (text.substring(loc, loc + 5)
422: .toLowerCase(Locale.ENGLISH).equals("<pre>")); //$NON-NLS-1$
423: }
424:
425: private int calculateMaxAttributeWidth(ISchemaAttribute[] attributes) {
426: int width = 0;
427: for (int i = 0; i < attributes.length; i++) {
428: width = Math.max(width, attributes[i].getName().length());
429: }
430: return width;
431: }
432:
433: private String getProductPlugin() {
434: IProduct product = Platform.getProduct();
435: if (product != null) {
436: Bundle plugin = product.getDefiningBundle();
437: if (plugin != null) {
438: return plugin.getSymbolicName();
439: }
440: }
441: return PLATFORM_PLUGIN;
442: }
443: }
|