Bug 426397 - Provide an eclipse editor based on OrionEditorControl

Added support for HTML files in OrionEditor.

Change-Id: Icd2686a2ee11cfcaa2a45fa309529ae18e940db7
Signed-off-by: Leo Denault <ldena023@uottawa.ca>
diff --git a/bundles/org.eclipse.e4.tools.orion.editor/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.tools.orion.editor/META-INF/MANIFEST.MF
index fdf98eb..5c4ad17 100644
--- a/bundles/org.eclipse.e4.tools.orion.editor/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.tools.orion.editor/META-INF/MANIFEST.MF
@@ -13,6 +13,7 @@
  org.apache.commons.lang;bundle-version="2.6.0"
 Export-Package: org.eclipse.e4.tools.orion.editor.builder,
  org.eclipse.e4.tools.orion.editor.builder.css,
+ org.eclipse.e4.tools.orion.editor.builder.html,
  org.eclipse.e4.tools.orion.editor.builder.js,
  org.eclipse.e4.tools.orion.editor.internal,
  org.eclipse.e4.tools.orion.editor.swt
diff --git a/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLBuilder.java b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLBuilder.java
new file mode 100644
index 0000000..2238364
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLBuilder.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ *     Leo Denault <ldena023@uottawa.ca> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.e4.tools.orion.editor.builder.html;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.e4.tools.orion.editor.builder.AbstractHTMLBuilder;
+import org.eclipse.e4.tools.orion.editor.builder.IHTMLBuilder;
+
+/**
+ * {@link IHTMLBuilder} to build the Orion HTML editor for HTML mode.
+ * 
+ */
+public class HTMLBuilder extends AbstractHTMLBuilder {
+
+	/**
+	 * Constructor with {@link HTMLOptions}.
+	 * 
+	 * @param options
+	 *            the HTML options.
+	 */
+	public HTMLBuilder(HTMLOptions options) {
+		super(options);
+	}
+
+	/**
+	 * Constructor with file base dir.
+	 * 
+	 * @param baseDir
+	 *            base directory of the CSS and JS.
+	 */
+	public HTMLBuilder(File baseDir) {
+		this(new HTMLOptions(baseDir));
+	}
+
+	/**
+	 * Constructor to use only on OSGi context.
+	 * 
+	 * @throws IOException
+	 * 
+	 */
+	public HTMLBuilder() throws IOException {
+		this(new HTMLOptions());
+	}
+}
diff --git a/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLEdit.java b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLEdit.java
new file mode 100644
index 0000000..ad7060f
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLEdit.java
@@ -0,0 +1,29 @@
+package org.eclipse.e4.tools.orion.editor.builder.html;
+
+public class HTMLEdit
+{
+  protected static String nl;
+  public static synchronized HTMLEdit create(String lineSeparator)
+  {
+    nl = lineSeparator;
+    HTMLEdit result = new HTMLEdit();
+    nl = null;
+    return result;
+  }
+
+  public final String NL = nl == null ? (System.getProperties().getProperty("line.separator")) : nl;
+  protected final String TEXT_1 = " " + NL + "" + NL + "/*global define */" + NL + "" + NL + "define('examples/editor/swtContentAssist', [ //$NON-NLS-0$" + NL + "\t'orion/editor/templates' //$NON-NLS-0$" + NL + "], function(mTemplates) {" + NL + "" + NL + "\tvar colorValues = {" + NL + "\t\ttype: \"link\", //$NON-NLS-0$" + NL + "\t\tvalues: [" + NL + "\t\t\t\"COLOR_BLACK\", //$NON-NLS-0$" + NL + "\t\t\t\"COLOR_INFO_BACKGROUND\", //$NON-NLS-0$" + NL + "\t\t\t\"black\", //$NON-NLS-0$" + NL + "\t\t\t\"white\", //$NON-NLS-0$" + NL + "\t\t\t\"red\", //$NON-NLS-0$" + NL + "\t\t\t\"green\", //$NON-NLS-0$" + NL + "\t\t\t\"blue\", //$NON-NLS-0$" + NL + "\t\t\t\"magenta\", //$NON-NLS-0$" + NL + "\t\t\t\"yellow\", //$NON-NLS-0$" + NL + "\t\t\t\"cyan\", //$NON-NLS-0$" + NL + "\t\t\t\"grey\", //$NON-NLS-0$" + NL + "\t\t\t\"darkred\", //$NON-NLS-0$" + NL + "\t\t\t\"darkgreen\", //$NON-NLS-0$" + NL + "\t\t\t\"darkblue\", //$NON-NLS-0$" + NL + "\t\t\t\"darkmagenta\", //$NON-NLS-0$" + NL + "\t\t\t\"darkcyan\", //$NON-NLS-0$" + NL + "\t\t\t\"darkyellow\", //$NON-NLS-0$" + NL + "\t\t\t\"darkgray\", //$NON-NLS-0$" + NL + "\t\t\t\"lightgray\" //$NON-NLS-0$" + NL + "\t\t]" + NL + "\t};" + NL + "\tfunction fromJSON(o) {" + NL + "\t\treturn JSON.stringify(o).replace(\"}\", \"\\\\}\"); //$NON-NLS-1$ //$NON-NLS-0$" + NL + "\t}" + NL + "\tvar templates = [" + NL + "\t\t{" + NL + "\t\t\tprefix: \"swt-outer-keyline-color\", //$NON-NLS-0$" + NL + "\t\t\tdescription: \"ctab folder keyline - keyline color\", //$NON-NLS-0$" + NL + "\t\t\ttemplate: \"swt-outer-keyline-color: ${color:\" + fromJSON(colorValues) + \"};\" //$NON-NLS-1$ //$NON-NLS-0$" + NL + "\t\t}," + NL + "\t\t{" + NL + "\t\t\tprefix: \"frame-image\", //$NON-NLS-0$" + NL + "\t\t\tdescription: \"image - the frame image\", //$NON-NLS-0$" + NL + "\t\t\ttemplate: \"frame-image: url(\\\"${uri}\\\");\" //$NON-NLS-0$" + NL + "\t\t}" + NL + "\t];" + NL + "\tvar keywords = [" + NL + "\t\t";
+  protected final String TEXT_2 = NL + "\t];" + NL + "" + NL + "\tfunction SWTContentAssistProvider() {" + NL + "\t}" + NL + "\tSWTContentAssistProvider.prototype = new mTemplates.TemplateContentAssist(keywords, templates);" + NL + "\t" + NL + "\tSWTContentAssistProvider.prototype.getPrefix = function(buffer, offset, context) {" + NL + "\t\tvar index = offset;" + NL + "\t\twhile (index && /[A-Za-z\\-\\@]/.test(buffer.charAt(index - 1))) {" + NL + "\t\t\tindex--;" + NL + "\t\t}" + NL + "\t\treturn index ? buffer.substring(index, offset) : \"\";" + NL + "\t};" + NL + "" + NL + "\treturn {" + NL + "\t\tSWTContentAssistProvider: SWTContentAssistProvider" + NL + "\t};" + NL + "});" + NL + "" + NL + "/*globals require*/" + NL + "require([\"orion/editor/edit\", \"examples/editor/swtContentAssist\"], function(edit, mSWTContentAssist) {" + NL + "\tvar editor = edit({" + NL + "\t\tlang: \"css\"" + NL + "\t});" + NL + "\t//ADD THE SWT CONTENT ASSIST" + NL + "\tvar contentAssist = editor.getContentAssist ? editor.getContentAssist() : editor._contentAssist;" + NL + "\tcontentAssist.addEventListener(\"Activating\", function() { //$NON-NLS-0$" + NL + "\t\tcontentAssist.providers.push(new mSWTContentAssist.SWTContentAssistProvider());" + NL + "\t});" + NL + "\tsetOrionEditor(editor);" + NL + "\t//----------------" + NL + "});";
+  protected final String TEXT_3 = NL;
+
+  public String generate(Object argument)
+  {
+    final StringBuffer stringBuffer = new StringBuffer();
+     String keywords = (String)argument; 
+    stringBuffer.append(TEXT_1);
+    stringBuffer.append( keywords );
+    stringBuffer.append(TEXT_2);
+    stringBuffer.append(TEXT_3);
+    return stringBuffer.toString();
+  }
+}
diff --git a/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLOptions.java b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLOptions.java
new file mode 100644
index 0000000..239939f
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.orion.editor/src/org/eclipse/e4/tools/orion/editor/builder/html/HTMLOptions.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ *     Leo Denault <ldena023@uottawa.ca> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.e4.tools.orion.editor.builder.html;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.e4.tools.orion.editor.builder.EditorOptions;
+
+/**
+ * HTML Editor options.
+ * 
+ */
+public class HTMLOptions extends EditorOptions {
+
+	private static final String HTML_LANG = "html";
+
+	/**
+	 * Constructor of the editor options with URL of CSS and JS.
+	 * 
+	 * @param editorJsUrl
+	 *            the full URL of "built-editor.js".
+	 * @param editorCssUrl
+	 *            the full URL of "built-editor.css".
+	 */
+	public HTMLOptions(String editorJsUrl, String editorCssUrl) {
+		super(editorJsUrl, editorCssUrl, HTML_LANG);
+		createEditor();
+	}
+
+	/**
+	 * Constructor of the editor options with the base URL of CSS and JS.
+	 * 
+	 * @param baseURL
+	 *            base URL of the CSS and JS.
+	 */
+	public HTMLOptions(String baseURL) {
+		super(baseURL, HTML_LANG);
+		createEditor();
+	}
+
+	/**
+	 * Constructor of the editor options with the file base dir of CSS and JS.
+	 * 
+	 * @param baseDir
+	 *            file base directory of the CSS and JS.
+	 */
+	public HTMLOptions(File baseDir) {
+		super(baseDir, HTML_LANG);
+		createEditor();
+	}
+
+	/**
+	 * Constructor of the editor options to use only on OSGi context.
+	 * 
+	 * @throws IOException
+	 */
+	public HTMLOptions() throws IOException {
+		super(HTML_LANG);
+		createEditor();
+	}
+
+	/**
+	 * Create the Orion editor with edit function.
+	 * 
+	 */
+	private void createEditor() {
+		String htmlEdit = new HTMLEdit().generate(null);
+		super.addScript(htmlEdit);
+	}
+
+}
diff --git a/bundles/org.eclipse.e4.tools.orion.text.editor/plugin.xml b/bundles/org.eclipse.e4.tools.orion.text.editor/plugin.xml
index 3ca9dae..95d30e0 100644
--- a/bundles/org.eclipse.e4.tools.orion.text.editor/plugin.xml
+++ b/bundles/org.eclipse.e4.tools.orion.text.editor/plugin.xml
@@ -7,7 +7,7 @@
             class="org.eclipse.e4.tools.orion.text.editor.OrionEditor"
             contributorClass="org.eclipse.e4.tools.orion.text.editor.OrionEditorActionBarContributor"
             default="true"
-            extensions="css"
+            extensions="css,html,htm"
             id="org.eclipse.e4.tools.orion.text.editor"
             matchingStrategy="org.eclipse.e4.tools.orion.text.editor.OrionEditorMatchingStrategy"
             name="OrionEditor">
diff --git a/bundles/org.eclipse.e4.tools.orion.text.editor/src/org/eclipse/e4/tools/orion/text/editor/OrionEditor.java b/bundles/org.eclipse.e4.tools.orion.text.editor/src/org/eclipse/e4/tools/orion/text/editor/OrionEditor.java
index 789b97f..03f18dc 100755
--- a/bundles/org.eclipse.e4.tools.orion.text.editor/src/org/eclipse/e4/tools/orion/text/editor/OrionEditor.java
+++ b/bundles/org.eclipse.e4.tools.orion.text.editor/src/org/eclipse/e4/tools/orion/text/editor/OrionEditor.java
@@ -20,7 +20,9 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.tools.orion.editor.builder.IHTMLBuilder;
 import org.eclipse.e4.tools.orion.editor.builder.css.CSSBuilder;
+import org.eclipse.e4.tools.orion.editor.builder.html.HTMLBuilder;
 import org.eclipse.e4.tools.orion.editor.swt.IDirtyListener;
 import org.eclipse.e4.tools.orion.editor.swt.OrionEditorControl;
 import org.eclipse.swt.SWT;
@@ -34,8 +36,11 @@
 
 public class OrionEditor extends EditorPart implements IDirtyListener {
 
+	private static final String CSS_EXTENSION = "css";
+
 	private OrionEditorControl control;
 	private IFile source;
+	private IHTMLBuilder builder;
 
 	@Override
 	public void doSave(IProgressMonitor monitor) {
@@ -103,13 +108,23 @@
 	@Override
 	public void createPartControl(Composite parent) {
 		try {
-			control = new OrionEditorControl(parent, SWT.NONE, new CSSBuilder(
-					""));
-			control.addDirtyListener(this);
+			String text = "";
+			// Assume HTML context for files other than CSS and JS
+			builder = new HTMLBuilder();
 
 			if (source != null) {
-				control.setText(loadFile(source.getContents(), 1024));
+				String extension = source.getFileExtension();
+
+				if (extension.equals(CSS_EXTENSION)) {
+					builder = new CSSBuilder("");
+				}
+
+				text = loadFile(source.getContents(), 1024);
 			}
+
+			control = new OrionEditorControl(parent, SWT.NONE, builder);
+			control.addDirtyListener(this);
+			control.setText(text);
 		} catch (Exception e) {
 			Activator
 					.getDefault()
@@ -137,6 +152,10 @@
 		}
 	}
 
+	public IHTMLBuilder getBuilder() {
+		return builder;
+	}
+
 	/**
 	 * Loads the content of the given InputStream into a String and returns it.
 	 * 
diff --git a/tests/org.eclipse.e4.tools.orion.text.editor.test/src/org/eclipse/e4/tools/orion/text/editor/test/OrionEditorTest.java b/tests/org.eclipse.e4.tools.orion.text.editor.test/src/org/eclipse/e4/tools/orion/text/editor/test/OrionEditorTest.java
index af625b3..48e2b05 100644
--- a/tests/org.eclipse.e4.tools.orion.text.editor.test/src/org/eclipse/e4/tools/orion/text/editor/test/OrionEditorTest.java
+++ b/tests/org.eclipse.e4.tools.orion.text.editor.test/src/org/eclipse/e4/tools/orion/text/editor/test/OrionEditorTest.java
@@ -15,6 +15,8 @@
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.e4.tools.orion.editor.builder.css.CSSBuilder;
+import org.eclipse.e4.tools.orion.editor.builder.html.HTMLBuilder;
 import org.eclipse.e4.tools.orion.text.editor.OrionEditor;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IWorkbenchPage;
@@ -29,8 +31,7 @@
 
 public class OrionEditorTest extends UITestCase {
 
-	private static final String ORION_EDITOR_ID =
-			"org.eclipse.e4.tools.orion.text.editor"; //$NON-NLS-1$
+	private static final String ORION_EDITOR_ID = "org.eclipse.e4.tools.orion.text.editor"; //$NON-NLS-1$
 
 	private IWorkbenchPage fActivePage;
 
@@ -72,6 +73,30 @@
 		assertEquals(fActivePage.getActiveEditor(), editor);
 		assertEquals(editor.getSite().getId(), fWorkbench.getEditorRegistry()
 				.getDefaultEditor(file.getName()).getId());
+
+		// Now make sure that the correct builder is used
+		OrionEditor orionEditor = (OrionEditor) editor;
+		assertTrue(orionEditor.getBuilder() instanceof CSSBuilder);
+	}
+
+	public void testOpenEditorForEmptyHtmlFile() throws Throwable {
+		proj = FileUtil.createProject("testOpenEditor");
+
+		IFile file = FileUtil.createFile("test.html", proj);
+		// Check that the default editor for CSS files is the Orion Editor
+		assertEquals(ORION_EDITOR_ID, fWorkbench.getEditorRegistry()
+				.getDefaultEditor(file.getName()).getId());
+
+		// Then check if the OrionEditor automatically opens for CSS files.
+		IEditorPart editor = IDE.openEditor(fActivePage, file, true);
+		assertTrue(ArrayUtil.contains(fActivePage.getEditors(), editor));
+		assertEquals(fActivePage.getActiveEditor(), editor);
+		assertEquals(editor.getSite().getId(), fWorkbench.getEditorRegistry()
+				.getDefaultEditor(file.getName()).getId());
+
+		// Now make sure that the correct builder is used
+		OrionEditor orionEditor = (OrionEditor) editor;
+		assertTrue(orionEditor.getBuilder() instanceof HTMLBuilder);
 	}
 
 	public void testOpenEditorForNonEmptyCssFile() throws Throwable {
@@ -80,7 +105,8 @@
 
 		// Insert text into the CSS file
 		IFile file = FileUtil.createFile("test.css", proj);
-		InputStream in = new ByteArrayInputStream(fileContents.getBytes("UTF-8"));
+		InputStream in = new ByteArrayInputStream(
+				fileContents.getBytes("UTF-8"));
 		file.setContents(in, IFile.NONE, null);
 
 		// Make sure that the editor properly opens.
@@ -92,7 +118,32 @@
 
 		// Check that the OrionEditorControl contains the text
 		// that was in the CSS file.
-		OrionEditor orionEditor = (OrionEditor)editor;
+		OrionEditor orionEditor = (OrionEditor) editor;
+		assertEquals(fileContents, orionEditor.getContents());
+
+		FileUtil.delete(file);
+	}
+
+	public void testOpenEditorForNonEmptyHtmlFile() throws Throwable {
+		proj = FileUtil.createProject("testOpenEditor");
+		String fileContents = "<!DOCTYPE html><html><body><h1>Some File</h1></body></html>";
+
+		// Insert text into the CSS file
+		IFile file = FileUtil.createFile("test.htm", proj);
+		InputStream in = new ByteArrayInputStream(
+				fileContents.getBytes("UTF-8"));
+		file.setContents(in, IFile.NONE, null);
+
+		// Make sure that the editor properly opens.
+		IEditorPart editor = IDE.openEditor(fActivePage, file, true);
+		assertTrue(ArrayUtil.contains(fActivePage.getEditors(), editor));
+		assertEquals(fActivePage.getActiveEditor(), editor);
+		assertEquals(editor.getSite().getId(), fWorkbench.getEditorRegistry()
+				.getDefaultEditor(file.getName()).getId());
+
+		// Check that the OrionEditorControl contains the text
+		// that was in the CSS file.
+		OrionEditor orionEditor = (OrionEditor) editor;
 		assertEquals(fileContents, orionEditor.getContents());
 
 		FileUtil.delete(file);
@@ -112,11 +163,12 @@
 		assertEquals(editor.getSite().getId(), fWorkbench.getEditorRegistry()
 				.getDefaultEditor(file.getName()).getId());
 
-		OrionEditor orionEditor = (OrionEditor)editor;
+		OrionEditor orionEditor = (OrionEditor) editor;
 		orionEditor.setContents(fileContents);
 		assertTrue(orionEditor.isDirty());
 		editor.doSave(null);
-		assertEquals(fileContents, orionEditor.loadFile(file.getContents(), 1024));
+		assertEquals(fileContents,
+				orionEditor.loadFile(file.getContents(), 1024));
 	}
 
 	public void testIsDirtyReturnsFalseWhenOrionEditorControlIsNull() {
@@ -124,7 +176,8 @@
 		assertFalse(editor.isDirty());
 	}
 
-	public void testIsDirtyReturnsFalseWhenOrionEditorControlIsDisposed() throws Throwable {
+	public void testIsDirtyReturnsFalseWhenOrionEditorControlIsDisposed()
+			throws Throwable {
 		proj = FileUtil.createProject("testOpenEditor");
 		IFile file = FileUtil.createFile("test.css", proj);
 
@@ -144,7 +197,8 @@
 	@SuppressWarnings("restriction")
 	public void testInitThrowsExceptionWithNonFileEditorInput() {
 		try {
-			IEditorPart editor = IDE.openEditor(fActivePage, new NullEditorInput(), ORION_EDITOR_ID);
+			IEditorPart editor = IDE.openEditor(fActivePage,
+					new NullEditorInput(), ORION_EDITOR_ID);
 			assertTrue(editor instanceof ErrorEditorPart);
 		} catch (PartInitException e) {
 			fail("The PartInitException should be caught internally.");