Index: META-INF/MANIFEST.MF
===================================================================
--- META-INF/MANIFEST.MF	(revision 33273)
+++ META-INF/MANIFEST.MF	(working copy)
@@ -27,7 +27,9 @@
 Export-Package: freemarker.core,
  freemarker.template,
  org.jboss.ide.eclipse.freemarker,
+ org.jboss.ide.eclipse.freemarker.contentassist,
  org.jboss.ide.eclipse.freemarker.editor,
+ org.jboss.ide.eclipse.freemarker.editor.editorpart,
  org.jboss.ide.eclipse.freemarker.model,
  org.jboss.ide.eclipse.freemarker.outline,
  org.jboss.ide.eclipse.freemarker.preferences
Index: plugin.xml
===================================================================
--- plugin.xml	(revision 33273)
+++ plugin.xml	(working copy)
@@ -18,6 +18,11 @@
             class="org.jboss.ide.eclipse.freemarker.preferences.PreferencePage"
             id="org.jboss.ide.eclipse.freemarker.preferences.OutlinePreferencePage"
             name="%PreferencePage_FreeMarkerEditor"/>
+      <page
+	          category="org.jboss.ide.eclipse.freemarker.preferences.PreferencePage"
+	          class="org.jboss.ide.eclipse.freemarker.preferences.FreemarkerTemplatePreferencePage"
+	          id="org.jboss.ide.eclipse.freemarkerpreferences.FreemarkerTemplatePreferencePage"
+	          name="%freemarker.preferencePages.templates"/>       
    </extension>
    <extension
          point="org.eclipse.ui.popupMenus">
@@ -30,7 +35,7 @@
                class="org.jboss.ide.eclipse.freemarker.editor.actions.AddMacroLibrary"
                icon="icons/include.png"
                id="org.jboss.ide.eclipse.freemarker.AddMacroLibrary1"
-               label="Use as FreeMarker library"/>
+               label="%freemarker.library"/>
       </objectContribution>
       <objectContribution
             adaptable="false"
@@ -41,7 +46,7 @@
                class="org.jboss.ide.eclipse.freemarker.editor.actions.AddMacroLibrary"
                icon="icons/include.png"
                id="Freemarker-IDE.AddMacroLibrary2"
-               label="Use as FreeMarker library"/>
+               label="%freemarker.library"/>
       </objectContribution>
    </extension>
    <extension
@@ -60,4 +65,15 @@
             id="org.jboss.ide.eclipse.freemarker.linetracker.ConsoleLineTracker"
             processType="java"/>
    </extension>
+   <extension
+           id="org.jboss.ide.eclipse.freemarker.editor.templates"
+           name="%freemarker.templates"
+           point="org.eclipse.ui.editors.templates">
+        <contextType
+              class="org.jboss.ide.eclipse.freemarker.template.FreemarkerTemplateContextType"
+              id="org.jboss.ide.eclipse.freemarker.template.context"
+              name="%freemarker.template.type"/>
+        <include file="templates/templates.xml"/>
+	</extension>   
+   
 </plugin>
Index: templates/templates.xml
===================================================================
--- templates/templates.xml	(revision 0)
+++ templates/templates.xml	(revision 0)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.list" name="list" description="iterate over sequence" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">&lt;#list ${sequence} as ${item}&gt;
+	${line_selection}$${${item}${cursor}}	
+&lt;/#list&gt;
+</template>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.if" name="if" description="if" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">&lt;#if ${condition} >
+	${cursor}
+&lt;/#if&gt;
+</template>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.ifelse" name="ifelse" description="if-else" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">&lt;#if ${condition}&gt;
+	${cursor}
+&lt;#else&gt;
+
+&lt;/#if&gt;
+</template>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.if" name="elseif" description="elseif" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">&lt;#elseif ${condition} &gt;
+</template>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.assign" name="assign" description="assign" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">&lt;#assign ${name} = ${value} /&gt;
+</template>
+<template id="org.jboss.ide.eclipse.freemarker.templates.freemarker.expression" name="$" description="expression that can be evaluated as a string" context="org.jboss.ide.eclipse.freemarker.template.context" enabled="true" deleted="false" autoinsert="true">$${${line_selection}${cursor}}</template>
+</templates>  
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/configuration/context/AbstractContextValue.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/context/AbstractContextValue.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/context/AbstractContextValue.java	(revision 0)
@@ -0,0 +1,45 @@
+package org.jboss.ide.eclipse.freemarker.configuration.context;
+
+/**
+ * 
+ * Abstract class for manage context value.
+ * 
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public abstract class AbstractContextValue implements IContextValue {
+
+	private String name;
+	private IObjectContext[] objectContexts;
+	
+	protected AbstractContextValue(String name) {
+		this.name = name;
+		this.objectContexts = new IObjectContext[2];
+	}
+	
+	public String getName() {
+		return this.name;
+	}
+	
+    public IObjectContext[] getContexts() {
+    	return objectContexts;
+    }
+    
+    protected void setFirstObjectContext(IObjectContext objectContext) {
+    	objectContexts[0] = objectContext;
+    }
+    
+    public IObjectContext getFirstObjectContext() {
+    	return this.objectContexts[0];
+    }
+    
+    public IObjectContext getSecondObjectContext() {
+    	return this.objectContexts[1];
+    }    
+    
+    protected void setSecondObjectContext(IObjectContext objectContext) {
+    	objectContexts[1] = objectContext;
+    }    
+	
+}
Index: src/org/jboss/ide/eclipse/freemarker/configuration/context/ClassContextValue.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/context/ClassContextValue.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/context/ClassContextValue.java	(revision 0)
@@ -0,0 +1,43 @@
+package org.jboss.ide.eclipse.freemarker.configuration.context;
+
+/**
+ * Class context value.
+ *  
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class ClassContextValue extends AbstractContextValue {
+
+    public ClassContextValue(String name, Class objClass, Class singularClass)
+    {
+        super(name);
+        // Object class
+        setFirstObjectContext(new ClassObjectContext(objClass));
+        // Singular class
+        setSecondObjectContext(new ClassObjectContext(singularClass));
+    }
+    
+    public int getType() {
+    	return IContextValue.CLASS;
+    }
+	
+	public class ClassObjectContext implements IObjectContext {
+		
+		private Class objectClass;
+		
+		public ClassObjectContext(Class objectClass) {
+			this.objectClass = objectClass;
+		}
+		
+		public String getName() {
+	    	if (objectClass != null)
+	    		return objectClass.getName();
+	    	return null;
+		}
+		
+		public Object getObject() {
+			return this.objectClass;
+		}
+	}
+}
Index: src/org/jboss/ide/eclipse/freemarker/configuration/context/IContextValue.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/context/IContextValue.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/context/IContextValue.java	(revision 0)
@@ -0,0 +1,24 @@
+package org.jboss.ide.eclipse.freemarker.configuration.context;
+
+/**
+ * 
+ * Interface context value. 
+ * @version 1.0.0 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public interface IContextValue {
+
+	public final static int CLASS = 0;
+	public final static int STRING = 1;
+	public final static int XML = 2;
+	public final static int DTD = 3;
+	
+	public String getName();
+	public int getType();
+	public IObjectContext[] getContexts();
+	
+	public IObjectContext getFirstObjectContext();
+	public IObjectContext getSecondObjectContext();
+	
+}
Index: src/org/jboss/ide/eclipse/freemarker/configuration/context/IObjectContext.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/context/IObjectContext.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/context/IObjectContext.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.jboss.ide.eclipse.freemarker.configuration.context;
+
+public interface IObjectContext {
+
+	public String getName();
+	public Object getObject();
+}
Index: src/org/jboss/ide/eclipse/freemarker/configuration/context/XMLContextValue.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/context/XMLContextValue.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/context/XMLContextValue.java	(revision 0)
@@ -0,0 +1,43 @@
+package org.jboss.ide.eclipse.freemarker.configuration.context;
+
+import org.w3c.dom.Document;
+
+/**
+ * XML context value
+ *  
+ * @version 1.0.0 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class XMLContextValue extends AbstractContextValue  {
+	
+	
+	public XMLContextValue(String name, String xmlFile, Document document) {
+		super(name);
+		this.setFirstObjectContext(new XMLObjectContext(xmlFile, document));
+	}
+	
+	public int getType() {
+		return IContextValue.XML;
+	}
+	
+	public class XMLObjectContext implements IObjectContext {
+		
+		private String xmlFile;
+		private Document document;
+		
+		public XMLObjectContext(String xmlFile, Document document) {
+			this.xmlFile = xmlFile;
+			this.document = document;
+		}
+		
+		public String getName() {
+	    	return xmlFile;
+		}
+		
+		public Object getObject() {
+			return this.document;
+		}
+	}	
+	
+}
Index: src/org/jboss/ide/eclipse/freemarker/configuration/ConfigurationManager.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/configuration/ConfigurationManager.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/configuration/ConfigurationManager.java	(working copy)
@@ -46,6 +46,8 @@
 import org.eclipse.swt.widgets.Shell;
 import org.jboss.ide.eclipse.freemarker.Messages;
 import org.jboss.ide.eclipse.freemarker.Plugin;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.helper.ContextValueHelper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -180,7 +182,7 @@
         return map;
 	}
 
-	private IFile getFile (String path) {
+	public IFile getFile (String path) {
 		return project.getFile(path);
 	}
 
@@ -195,6 +197,7 @@
                     .getElementsByTagName("resource"); //$NON-NLS-1$
             for (int i = 0; i < nl.getLength(); i++) {
                 try {
+                    IContextValue contextValue = null;
                     Node n = nl.item(i);
                     String path = ((Element) n).getAttribute("path"); //$NON-NLS-1$
                     List contextValues = new ArrayList();
@@ -202,21 +205,39 @@
                             .getElementsByTagName("value"); //$NON-NLS-1$
                     for (int j = 0; j < nl2.getLength(); j++) {
                         Node n2 = nl2.item(j);
-                        String key = ((Element) n2).getAttribute("key"); //$NON-NLS-1$
-                        Class value = getClass(((Element) n2)
-                                .getAttribute("object-class")); //$NON-NLS-1$
-                        String singularName = ((Element) n2)
-                                .getAttribute("item-class"); //$NON-NLS-1$
-                        Class singularClass = null;
-                        if (null != singularName && singularName.trim().length()>0)
-                            singularClass = getClass(singularName);
-                        contextValues.add(new ContextValue(key, value,
-                                singularClass));
+                        String key = ((Element) n2).getAttribute("key");
+                        // Instanciate Context value switch class/xml or string
+                        String className = ((Element)n2).getAttribute("object-class");
+                        if (className != null && className.trim().length() > 0) {  
+                            // Class context
+                            String singularName = ((Element)n2).getAttribute("item-class");
+                            contextValue = getInstanceOfContextValue(IContextValue.CLASS, key, className, singularName);
+                        }
+                        else {
+                            String stringValue = ((Element)n2).getAttribute("string-value");
+                            if (stringValue != null && stringValue.trim().length() > 0) {
+                                // String context
+                                contextValue = getInstanceOfContextValue(IContextValue.STRING, key, stringValue, null);                     
+                            }
+                            else {
+                                String xmlFile = ((Element)n2).getAttribute("xml-file");
+                                if (xmlFile != null && xmlFile.trim().length() > 0) {
+                                    // XML context
+                                    contextValue = getInstanceOfContextValue(IContextValue.XML, key, xmlFile, null);          
+                                }
+                                else {
+                                    String dtdFile = ((Element)n2).getAttribute("dtd-file");
+                                    if (dtdFile != null && dtdFile.trim().length() > 0) {
+                                        // DTD context
+                                        contextValue = getInstanceOfContextValue(IContextValue.DTD, key, dtdFile, null);          
+                                    }
+                                }
+                            }
+                        }
+                        if (contextValue != null) 
+                            contextValues.add(contextValue);
                     }
-                    map.put(path,
-                            contextValues
-                                    .toArray(new ContextValue[contextValues
-                                            .size()]));
+                    map.put(path, ((Object) (contextValues.toArray(new IContextValue[contextValues.size()]))));
                 } catch (Exception e) {
                 	Plugin.log(e);
                 }
@@ -301,28 +322,57 @@
         for (Iterator i = contextValues.entrySet().iterator(); i.hasNext();) {
             Map.Entry entry = (Map.Entry) i.next();
             String fileName = (String) entry.getKey();
-            ContextValue[] values = (ContextValue[]) entry.getValue();
+            IContextValue[] values = (IContextValue[]) entry.getValue();
             if (null != values && values.length > 0) {
-                sb.append("\t\t<resource path=\"" + fileName + "\">\n");  //$NON-NLS-1$//$NON-NLS-2$
+                sb.append("\t\t<resource path=\"" + fileName + "\">\n");
                 for (int j = 0; j < values.length; j++) {
-                    sb
-							.append("\t\t\t<value key=\"" + values[j].name //$NON-NLS-1$
-									+ "\" object-class=\"" + values[j].objClass.getName() //$NON-NLS-1$
-									+ "\""); //$NON-NLS-1$
-                    if (null != values[j].singularClass)
-                        sb.append(" item-class=\"" //$NON-NLS-1$
-								+ values[j].singularClass.getName() + "\""); //$NON-NLS-1$
-					sb.append("/>\n"); //$NON-NLS-1$
+                    // Manage context value for XML, String or class
+                    IContextValue contextValue = values[j];
+                    String key = contextValue.getName();
+                    if (contextValue.getType() == IContextValue.CLASS) {
+                        // Class context
+                        String objClassName = contextValue.getFirstObjectContext().getName();
+                        String singularClassName = contextValue.getSecondObjectContext().getName();
+                        sb.append("\t\t\t<value key=\"" +key + "\" object-class=\"" + objClassName + "\"");
+                        if(singularClassName != null)
+                            sb.append(" item-class=\"" +singularClassName + "\"");
+                        sb.append("/>\n");
+                    }
+                    else {
+                        if (contextValue.getType() == IContextValue.STRING) {
+                            // String context
+                            /*String stringValue = contextValue.getFirstObjectContext().getName();
+                            sb.append("\t\t\t<value key=\"" +  key + "\" string-value=\"" + stringValue + "\"");
+                            sb.append("/>\n");
+                            */                      
+                        }
+                        else {
+                            if (contextValue.getType() == IContextValue.XML) {
+                                // XML context
+                                String xmlFile = contextValue.getFirstObjectContext().getName();
+                                sb.append("\t\t\t<value key=\"" +  key + "\" xml-file=\"" + xmlFile + "\"");
+                                sb.append("/>\n"); 
+                            }
+                            else {
+                                /*if (contextValue.getType() == IContextValue.DTD) {
+                                    // XML context
+                                    String dtdFile = contextValue.getFirstObjectContext().getName();
+                                    sb.append("\t\t\t<value key=\"" +  key + "\" dtd-file=\"" + dtdFile + "\"");
+                                    sb.append("/>\n"); 
+                                }*/
+                            }
+                        }
+                    }
                 }
-                sb.append("\t\t</resource>\n"); //$NON-NLS-1$
+                sb.append("\t\t</resource>\n");
             }
         }
     }
     
-    public ContextValue[] getContextValues(IResource resource, boolean recurse) {
+    public IContextValue[] getContextValues(IResource resource, boolean recurse) {
         Map newValues = new HashMap();
         addRootContextValues(resource, newValues, recurse);
-        return (ContextValue[]) newValues.values().toArray(new ContextValue[newValues.size()]);
+        return (IContextValue[]) newValues.values().toArray(new IContextValue[newValues.size()]);
     }
     
     private void addRootContextValues(IResource resource, Map newValues, boolean recurse) {
@@ -334,29 +384,29 @@
         else
 			key = ""; //$NON-NLS-1$
         if (null != resource.getProject()) {
-	        ContextValue[] values = (ContextValue[]) contextValues.get(key);
+        	IContextValue[] values = (IContextValue[]) contextValues.get(key);
 	        if (null != values) {
 	            for (int i=0; i<values.length; i++) {
-	                newValues.put(values[i].name, values[i]);
+	                newValues.put(values[i].getName(), values[i]);
 	            }
 	        }
         }
     }
 
-    public ContextValue getContextValue(String name, IResource resource, boolean recurse) {
-        ContextValue[] values = getContextValues(resource, recurse);
+    public IContextValue getContextValue(String name, IResource resource, boolean recurse) {
+    	IContextValue[] values = getContextValues(resource, recurse);
         for (int i = 0; i < values.length; i++) {
-            if (values[i].name.equals(name))
+            if (values[i].getName().equals(name))
                 return values[i];
         }
         return null;
     }
 
-    public void addContextValue(ContextValue contextValue, IResource resource) {
-        ContextValue[] contextValues = getContextValues(resource, false);
+    public void addContextValue(IContextValue contextValue, IResource resource) {
+        IContextValue[] contextValues = getContextValues(resource, false);
         boolean found = false;
         for (int i = 0; i < contextValues.length; i++) {
-            if (contextValues[i].name.equals(contextValue.name)) {
+            if (contextValues[i].getName().equals(contextValue.getName())) {
                 found = true;
                 contextValues[i] = contextValue;
                 this.contextValues.put(
@@ -366,7 +416,7 @@
             }
         }
         if (!found) {
-            ContextValue[] newContextValues = new ContextValue[contextValues.length + 1];
+            IContextValue[] newContextValues = new IContextValue[contextValues.length + 1];
             int index = 0;
             while (index < contextValues.length) {
                 newContextValues[index] = contextValues[index++];
@@ -377,21 +427,21 @@
         save();
     }
 
-    public void updateContextValue(ContextValue contextValue, IFile file) {
+    public void updateContextValue(IContextValue contextValue, IFile file) {
         addContextValue(contextValue, file);
     }
 
     public void removeContextValue(String name, IResource resource) {
-        ContextValue[] values = getContextValues(resource, false);
+        IContextValue[] values = getContextValues(resource, false);
         int index = -1;
         for (int i = 0; i < values.length; i++) {
-            if (values[i].name.equals(name)) {
+            if (values[i].getName().equals(name)) {
                 index = i;
                 break;
             }
         }
         if (index >= 0) {
-            ContextValue[] newValues = new ContextValue[values.length - 1];
+            IContextValue[] newValues = new IContextValue[values.length - 1];
             int j = 0;
             for (int i = 0; i < values.length; i++) {
                 if (i != index)
@@ -401,4 +451,21 @@
             save();
         }
     }
+    
+    /**
+     * Return an instance of context value swith contextType (CLASS, XML, ...)
+     * @param contextType
+     * @param name
+     * @param context1
+     * @param context2
+     * @return
+     * @throws Exception
+     */
+    public IContextValue getInstanceOfContextValue(int contextType,  String name, 
+            String context1, String context2) throws Exception
+    {
+        return ContextValueHelper.getInstanceOfContextValue(this, contextType, name, context1,
+                context2);
+    }
+    
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/dialogs/ContextValueDialog.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/dialogs/ContextValueDialog.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/dialogs/ContextValueDialog.java	(working copy)
@@ -1,40 +1,24 @@
-/*
- * JBoss by Red Hat
- * Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
 package org.jboss.ide.eclipse.freemarker.dialogs;
 
 
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.StatusDialog;
 import org.eclipse.jface.window.ApplicationWindow;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.MouseEvent;
 import org.eclipse.swt.events.MouseListener;
 import org.eclipse.swt.graphics.Color;
@@ -43,29 +27,48 @@
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ContainerSelectionDialog;
 import org.eclipse.ui.dialogs.SelectionDialog;
-import org.jboss.ide.eclipse.freemarker.Messages;
+import org.jboss.ide.eclipse.freemarker.FreemarkerMessages;
+import org.jboss.ide.eclipse.freemarker.Plugin;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IObjectContext;
 
 /**
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
  */
-public class ContextValueDialog extends Dialog {
+public class ContextValueDialog extends StatusDialog {
 
+	private static final int NO_CONTEXT_SELECTED = -1;
+	
 	private IResource resource;
-	private ContextValue contextValue;
+	private IContextValue contextValue;
 
 	private Text keyText;
+	
+	private Label labelText;
 	private Text valueText;
+	private Button browse;
+	
 	private Text singleValueText;
 	private Label singleLabel;
 	private Button singleBrowse;
 	
-	public ContextValueDialog(Shell parentShell, ContextValue contextValue, IResource resource) {
+    // Manage radio button to select a context type 
+	// (Class, String, XML, DTD) 	
+    private Button classRadioButton;
+    private Button stringRadioButton;
+    private Button xmlRadioButton;
+    private Button dtdRadioButton;
+    
+	public ContextValueDialog(Shell parentShell, IContextValue contextValue, IResource resource) {
 		super(parentShell);
 		this.resource = resource;
 		this.contextValue = contextValue;
@@ -75,7 +78,7 @@
 	 * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
 	 */
 	protected void configureShell(Shell newShell) {
-		newShell.setText(Messages.ContextValueDialog_SHELL_CONTEXT_VALUE_CONFIG);
+		newShell.setText(FreemarkerMessages.getString("ContextValueDialog.title"));
 		super.configureShell(newShell);
 	}
 
@@ -84,72 +87,195 @@
 		Composite composite = new Composite(parent, SWT.NULL);
 		composite.setLayout(new GridLayout(3, false));
 
-		Label label = new Label(composite, SWT.NULL);
-		label.setText(Messages.ContextValueDialog_LABEL_NAME);
+        // Coded added by AZ : create Radio Group 
+        // for manage context type Class, String and XML
+        Label label = new Label(composite, 0);
+        label.setText(FreemarkerMessages.getString("ContextValueDialog.contextType.label"));      
+        final Group group = new Group(composite, SWT.NONE);
+		final GridLayout gridLayout = new GridLayout();
+		gridLayout.numColumns = 4;
+		group.setLayout(gridLayout);
+
+        classRadioButton = new Button(group, SWT.RADIO);
+        classRadioButton.setText("Class");
+        classRadioButton.addListener(SWT.Selection, new Listener() {
+            public void handleEvent(Event event) {
+            	handleRadioButon(true);
+            }
+          });
+        stringRadioButton = new Button(group, SWT.RADIO);
+        stringRadioButton.setText("String");
+        stringRadioButton.addListener(SWT.Selection, new Listener() {
+            public void handleEvent(Event event) {
+            	handleRadioButon(true);
+            }
+          });
+        xmlRadioButton = new Button(group, SWT.RADIO);
+        xmlRadioButton.setText("Xml");
+        xmlRadioButton.addListener(SWT.Selection, new Listener() {
+            public void handleEvent(Event event) {
+            	handleRadioButon(true);
+            }
+          });
+        dtdRadioButton = new Button(group, SWT.RADIO);
+        dtdRadioButton.setText("dtd");
+        dtdRadioButton.addListener(SWT.Selection, new Listener() {
+            public void handleEvent(Event event) {
+            	handleRadioButon(true);
+            }
+          });        
+        GridData gd = new GridData(768);
+        gd.horizontalSpan = 2;
+        gd.widthHint = 200;
+        group.setLayoutData(gd);
+        
+        // Select radio swith context type
+        if(contextValue != null) {     
+        	if (contextValue.getType() == IContextValue.CLASS)
+        		classRadioButton.setSelection(true);
+        	else {
+        		if (contextValue.getType() == IContextValue.STRING)
+            		stringRadioButton.setSelection(true);
+            	else {
+            		if (contextValue.getType() == IContextValue.XML)
+                		xmlRadioButton.setSelection(true);
+            		else {
+            			if (contextValue.getType() == IContextValue.DTD)
+                    		dtdRadioButton.setSelection(true);
+            		}
+            	}
+        	}
+        }
+        else {
+            // By default class is selected
+        	classRadioButton.setSelection(true);
+        }
+        
+		label = new Label(composite, SWT.NULL);
+		label.setText(FreemarkerMessages.getString("ContextValueDialog.key.label"));
 		keyText = new Text(composite, SWT.BORDER);
 		if (null != contextValue) {
-			keyText.setText(contextValue.name);
+			keyText.setText(contextValue.getName());
 			keyText.setEnabled(false);
 		}
-		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		gd = new GridData(GridData.FILL_HORIZONTAL);
 		gd.horizontalSpan = 2;
 		gd.widthHint = 200;
 		keyText.setLayoutData(gd);
-
-		label = new Label(composite, SWT.NULL);
-		label.setText(Messages.ContextValueDialog_LABEL_TYPE);
+		keyText.addModifyListener(new ModifyListener() {
+			public void modifyText(ModifyEvent e) {
+				dialogChanged();
+			}
+		});
+		
+		labelText = new Label(composite, SWT.NULL);
 		valueText = new Text(composite, SWT.BORDER);
 		valueText.setEnabled(false);
 		valueText.setBackground(new Color(null, 255, 255, 255));
 		gd = new GridData(GridData.FILL_HORIZONTAL);
 		gd.widthHint = 250;
 		valueText.setLayoutData(gd);
-		if (null != contextValue && null != contextValue.objClass) valueText.setText(contextValue.objClass.getName());
-        Button browse = new Button(composite, 8);
-        browse.setText(Messages.ContextValueDialog_BUTTON_BROWSE);
+        // Manage context value for XML, String or class
+        if(contextValue != null) {     
+    		IObjectContext objClass = contextValue.getFirstObjectContext();
+    		if(objClass != null) {
+    			String objectClassName = objClass.getName();
+    			if (objectClassName != null)
+    				valueText.setText(objectClassName);
+    		}
+
+        }
+		valueText.addModifyListener(new ModifyListener() {
+			public void modifyText(ModifyEvent e) {
+				dialogChanged();
+			}
+		});
+		
+		browse = new Button(composite, 8);
+        browse.setText("Browse");
         browse.addMouseListener(new MouseListener() {
             public void mouseDown(MouseEvent e)
             {
                 try {
-                    IJavaProject javaProject = JavaCore.create(resource.getProject());
-                    if(javaProject != null)
-                    {
-                        org.eclipse.jdt.core.search.IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
-                        SelectionDialog sd = JavaUI.createTypeDialog(getShell(), new ApplicationWindow(getShell()), searchScope, 2, false);
-                        sd.open();
-                        Object objects[] = sd.getResult();
-                        if(objects != null && objects.length > 0)
-                        {
-                            IType type = (IType)objects[0];
-                            String fullyQualifiedName = type.getFullyQualifiedName('.');
-                            valueText.setText(type.getFullyQualifiedName());
-                            String[] interfaces = type.getSuperInterfaceNames();
-                            boolean isList = false;
-                            if ("java.lang.Object".equals(fullyQualifiedName)) isList = true; //$NON-NLS-1$
-                            else {
-	                            for (int i=0; i<interfaces.length; i++) {
-	                                if (interfaces[i].equals("java.util.Collection") || interfaces[i].equals("java.util.List") || interfaces[i].equals("java.util.Set")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                	int contextType = getContextTypeSelected();
+                	if (contextType == IContextValue.CLASS) {
+                		// Context type selected is CLASS, open dialog in order
+                		// to display classes availables.
+	                    IJavaProject javaProject = JavaCore.create(resource.getProject());
+	                    if(javaProject != null)
+	                    {
+	                        IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[] {
+	                            javaProject
+	                        });
+	                        SelectionDialog sd = JavaUI.createTypeDialog(getShell(), new ApplicationWindow(getShell()), searchScope, 2, false);
+	                        sd.open();
+	                        Object objects[] = sd.getResult();
+	                        if(objects != null && objects.length > 0)
+	                        {
+	                            IType type = (IType)objects[0];
+	                            String fullyQualifiedName = type.getFullyQualifiedName();
+	                            valueText.setText(type.getFullyQualifiedName());
+	                            String interfaces[] = type.getSuperInterfaceNames();
+	                            boolean isList = false;
+	                            if("java.lang.Object".equals(fullyQualifiedName))
+	                            {
+	                                isList = true;
+	                            } else
+	                            {
+	                                for(int i = 0; i < interfaces.length; i++)
+	                                {
+	                                    if(!interfaces[i].equals("java.util.Collection") && !interfaces[i].equals("java.util.List") && !interfaces[i].equals("java.util.Set"))
+	                                        continue;
 	                                    isList = true;
 	                                    break;
 	                                }
+	
 	                            }
-                            }
-                            if (isList) {
-                                singleBrowse.setEnabled(true);
-                                singleLabel.setEnabled(true);
-                                singleValueText.setEnabled(true);
-                            }
-                            else {
-                                singleBrowse.setEnabled(false);
-                                singleLabel.setEnabled(false);
-                                singleValueText.setEnabled(false);
-                                singleValueText.setText(""); //$NON-NLS-1$
-                            }
-                        }
-                    }
-                    else {
-                        MessageDialog.openError(getShell(), Messages.ContextValueDialog_JAVA_PROJECT_ERROR, Messages.ContextValueDialog_MUST_BE_JAVA_PROJECT);
-                    }
+	                            if(isList)
+	                            {
+	                                singleBrowse.setEnabled(true);
+	                                singleLabel.setEnabled(true);
+	                                singleValueText.setEnabled(true);
+	                            } else
+	                            {
+	                                singleBrowse.setEnabled(false);
+	                                singleLabel.setEnabled(false);
+	                                singleValueText.setEnabled(false);
+	                                singleValueText.setText("");
+	                            }
+	                        }
+	                    } else
+	                    {
+	                        MessageDialog.openError(getShell(), "Java Project Error", "The project must be a java project.");
+	                    }
+                	}
+                	else {
+                		if (contextType == IContextValue.XML ||
+                			contextType == IContextValue.DTD) {
+                       		// Context type selected is XML, open dialog in order
+                    		// to display XML files availables.
+                			OpenResourceDialog  dialog =
+                				new OpenResourceDialog  (getShell(), resource.getProject());
+                				//dialog.setInitialSelections(selectedResources);
+                			if (dialog.open() == ContainerSelectionDialog.OK)
+                			{
+                				Object[] result = dialog.getResult();
+                				if (result.length == 1)
+                				{
+                					IFile xmlFile = (IFile)(result[0]);
+                					if (xmlFile != null) {
+                						//IFile file = resource.getProject().getFile(xmlFile);
+                						valueText.setText(xmlFile.getProjectRelativePath().toString());
+                						// Load XML file into DOM
+                						
+                						
+                						//MessageDialog.openError(getShell(), "Java Project Error", "XML file is not valid.");
+                						
+                					}
+                				}
+                			}
+                		}
+                	}	                    
                 }
                 catch(JavaModelException _ex) { }
             }
@@ -165,20 +291,27 @@
         });
 
         boolean enabled = false;
-        if (null != contextValue && null != contextValue.singularClass) enabled = true;
+        String singularClassName = null;
+        // Manage context value for XML, String or class
+        if (contextValue != null) {
+        	IObjectContext singularClass = contextValue.getSecondObjectContext();
+        	if(singularClass != null) {
+    			singularClassName = singularClass.getName();
+        	}
+        }
 		singleLabel = new Label(composite, SWT.NULL);
 		singleLabel.setEnabled(enabled);
-		singleLabel.setText(Messages.ContextValueDialog_LABEL_LIST_ENTRY_TYPE);
+		singleLabel.setText("List Entry Type:");
 		singleValueText = new Text(composite, SWT.BORDER);
 		singleValueText.setEnabled(enabled);
 		singleValueText.setBackground(new Color(null, 255, 255, 255));
 		gd = new GridData(GridData.FILL_HORIZONTAL);
 		gd.widthHint = 250;
 		singleValueText.setLayoutData(gd);
-		if (enabled) singleValueText.setText(contextValue.singularClass.getName());
+		if (enabled) singleValueText.setText(singularClassName);
         singleBrowse = new Button(composite, 8);
         singleBrowse.setEnabled(enabled);
-        singleBrowse.setText(Messages.ContextValueDialog_BUTTON_BROWSE);
+        singleBrowse.setText("Browse");
         singleBrowse.addMouseListener(new MouseListener() {
             public void mouseDown(MouseEvent e)
             {
@@ -186,7 +319,7 @@
                     IJavaProject javaProject = JavaCore.create(resource.getProject());
                     if(javaProject != null)
                     {
-                        org.eclipse.jdt.core.search.IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
+                        IJavaSearchScope searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
                         SelectionDialog sd = JavaUI.createTypeDialog(getShell(), new ApplicationWindow(getShell()), searchScope, 2, false);
                         sd.open();
                         Object objects[] = sd.getResult();
@@ -197,7 +330,7 @@
                         }
                     }
                     else {
-                        MessageDialog.openError(getShell(), Messages.ContextValueDialog_JAVA_PROJECT_ERROR, Messages.ContextValueDialog_MUST_BE_JAVA_PROJECT);
+                        MessageDialog.openError(getShell(), "Java Project Error", "The project must be a java project.");
                     }
                 }
                 catch(JavaModelException _ex) { }
@@ -212,29 +345,154 @@
             }
 
         });
+        // Manage disable/enable for radio button
+        handleRadioButon(false);
+        // dialogChanged();
 		return parent;
 	}
 
 	protected void okPressed() {
 	    try {
 		    String name = keyText.getText().trim();
-		    while (name.startsWith("$")) name = name.substring(1, name.length()); //$NON-NLS-1$
-		    if (name.length() == 0) MessageDialog.openError(getShell(), Messages.ContextValueDialog_ERROR, Messages.ContextValueDialog_MUST_CHOOSE_REFERENCE);
+		    while (name.startsWith("$")) name = name.substring(1, name.length());
 		    String className = valueText.getText().trim();
-		    if (className.length() == 0) MessageDialog.openError(getShell(), Messages.ContextValueDialog_ERROR, Messages.ContextValueDialog_MUST_CHOOSE_CLASS);
-		    String singularClassName = singleValueText.getText().trim();
-		    Class singularClass = null;
-		    if (null != singularClassName && singularClassName.trim().length() > 0) singularClass = ConfigurationManager.getInstance(resource.getProject()).getClass(singularClassName);
-		    if (className.length() == 0) singularClassName = null;
-	        contextValue = new ContextValue(
-	                name,
-	                ConfigurationManager.getInstance(resource.getProject()).getClass(className),
-	                singularClass);
-	        ConfigurationManager.getInstance(resource.getProject()).addContextValue(contextValue, resource);
+            String singularClassName = singleValueText.getText().trim();
+            // Coded added by AZ : 
+            // Manage context value for XML, String or class
+            // Get context type
+            int contextType = getContextTypeSelected();
+            IContextValue contextValue = ConfigurationManager.getInstance(resource.getProject()).
+            		getInstanceOfContextValue(contextType, name, className, singularClassName);
+            if (contextValue != null)
+            	ConfigurationManager.getInstance(resource.getProject()).addContextValue(contextValue, resource);
 	    }
 	    catch (Exception e) {
-	        MessageDialog.openError(getShell(), Messages.ContextValueDialog_ERROR, e.getMessage());
+	        MessageDialog.openError(getShell(), "Error", e.getMessage());
 	    }
 		super.okPressed();
 	}
+	
+	 private void handleRadioButon(boolean initialize) {
+    	// 1. manage Key text 
+    	// It is enable ONLY if there is not exist context value
+    	keyText.setEnabled(contextValue == null);
+    	if (initialize) {
+    		singleValueText.setEnabled(false);
+    		singleBrowse.setEnabled(false);
+    		singleLabel.setEnabled(false);
+    	}
+    	boolean selected = classRadioButton.getSelection();
+        if (selected) {
+        	// Class radio button is selected
+        	valueText.setEnabled(false);
+        	browse.setEnabled(true);
+        	labelText.setText("Class:");
+        }
+        else {
+        	selected = stringRadioButton.getSelection();
+        	if (selected) {
+        		// String radio button is selected
+        		valueText.setEnabled(true);
+        		valueText.setFocus();
+        		browse.setEnabled(false);
+        		singleBrowse.setEnabled(false);
+        		labelText.setText("Value:");
+        	}
+        	else {
+        		selected = xmlRadioButton.getSelection();
+            	if (selected) {
+            		// XML radio button is selected
+            		valueText.setEnabled(false);
+            		browse.setEnabled(true);
+            		singleBrowse.setEnabled(false);
+            		labelText.setText("XML:");
+            	}
+            	else {
+            		selected = dtdRadioButton.getSelection();
+                	if (selected) {
+                		// DTD radio button is selected
+                		valueText.setEnabled(false);
+                		browse.setEnabled(true);
+                		singleBrowse.setEnabled(false);
+                		labelText.setText("DTD:");
+                	}
+            	}
+        	}
+        }
+        if (selected && initialize) {
+        	valueText.setText("");
+        	singleValueText.setText("");
+        }
+        String key = keyText.getText();
+		if (keyText.isEnabled() && 
+			key == null || key.trim().length() < 1) {
+    			keyText.setFocus();
+    	}        
+    }
+	    
+    private int getContextTypeSelected() {
+    	if ( classRadioButton.getSelection())
+    		return IContextValue.CLASS;
+    	if ( stringRadioButton.getSelection())
+    		return IContextValue.STRING;
+    	if ( xmlRadioButton.getSelection())
+    		return IContextValue.XML;
+    	if ( dtdRadioButton.getSelection())
+    		return IContextValue.DTD;
+    	return NO_CONTEXT_SELECTED;
+    }
+    
+    private void dialogChanged() {
+    	// Key validation
+    	String name = keyText.getText().trim();
+	    while (name.startsWith("$")) name = name.substring(1, name.length());
+	    if (name.length() == 0) {
+	    	updateMessageStatus("Choose the reference name!");
+	    	return;
+	    }
+	    
+	    // Value validation
+	    String className = valueText.getText().trim();
+        if(className.length() == 0) {
+        	String errorMessage = "";
+        	int contexType = getContextTypeSelected();
+        	if (contexType == IContextValue.CLASS) {
+        		errorMessage = "Choose the class name by using Browse button!";
+        	}
+        	else {
+        		if (contexType == IContextValue.STRING) {
+            		errorMessage = "Select a value for the string!";
+        		}
+            	else {
+            		if (contexType == IContextValue.XML) {
+                		errorMessage = "Choose a XML file by using Browse button!";
+            		}
+            		else {
+                		if (contexType == IContextValue.DTD) {
+                    		errorMessage = "Choose a DTD file by using Browse button!";
+                		}
+            		}
+            	}
+        	}
+        	updateMessageStatus(errorMessage);
+	    	return;
+        }	    
+    	updateMessageStatus(null);
+    }
+    
+    private void updateMessageStatus(String message) {
+    	IStatus status = null;
+    	if (message != null) {
+    		status = new Status(IStatus.ERROR, Plugin.ID, IStatus.ERROR, message, null);
+    	}
+    	else {
+    		status = new Status(IStatus.INFO, Plugin.ID, IStatus.OK, "Click OK to save your context.", null);
+    	}
+    	super.updateStatus(status);
+	}    
+	
+    public void create() {
+		super.create();
+		dialogChanged();
+	}    
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/dialogs/OpenResourceDialog.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/dialogs/OpenResourceDialog.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/dialogs/OpenResourceDialog.java	(revision 0)
@@ -0,0 +1,28 @@
+package org.jboss.ide.eclipse.freemarker.dialogs;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ResourceListSelectionDialog;
+import org.jboss.ide.eclipse.freemarker.FreemarkerMessages;
+
+public class OpenResourceDialog extends ResourceListSelectionDialog {
+
+    /**
+     * Creates a new instance of the class.
+     * 
+     * @param parentShell the parent shell
+     * @param container the container
+     * @param typesMask the types mask
+     */
+    public OpenResourceDialog(Shell parentShell, IContainer container) {
+        super(parentShell, container, IResource.FILE);
+        setTitle(FreemarkerMessages.getString("OpenResourceDialog.title"));
+        PlatformUI.getWorkbench().getHelpSystem()
+                .setHelp(parentShell, FreemarkerMessages.getString("OpenResourceDialog.help")
+                        );
+        setAllowUserToToggleDerived(false);
+        setShowDerived(true);  
+    }
+}
Index: src/org/jboss/ide/eclipse/freemarker/model/ListDirective.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/ListDirective.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/ListDirective.java	(working copy)
@@ -86,8 +86,8 @@
 		String[] contents = splitContents();
 		if (contents.length == 4) {
 			String key = contents[3];
-			CompletionInterpolation completionInterpolation = new CompletionInterpolation("${" + contents[1], 0, getItemSet(), getResource()); //$NON-NLS-1$
-			context.put(key, completionInterpolation.getSingularReturnClass(context));
+			CompletionInterpolation completionInterpolation = new CompletionInterpolation("${" + contents[1], 0, getItemSet(), getResource());
+			context.put(key, completionInterpolation.getSingularReturnObject(context));
 		}
 	}
 
Index: src/org/jboss/ide/eclipse/freemarker/model/AssignmentDirective.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/AssignmentDirective.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/AssignmentDirective.java	(working copy)
@@ -84,18 +84,18 @@
 			String value = null;
 			if (values.length >= 2) key = values[1];
 			if (values.length >= 4) value = values[3];
-			Class valueClass = null;
+			Object valueObject = null;
 			if (null != value && value.length() > 0) {
-				if (value.charAt(0) == '\"') valueClass = String.class;
-				else if (Character.isDigit(value.charAt(0))) valueClass = Number.class;
+				if (value.charAt(0) == '\"') valueObject = String.class;
+				else if (Character.isDigit(value.charAt(0))) valueObject = Number.class;
 				else {
 					CompletionInterpolation completionInterpolation =
-						new CompletionInterpolation("${" + value, 2, getItemSet(), getResource()); //$NON-NLS-1$
-					valueClass = completionInterpolation.getReturnClass(context);
+						new CompletionInterpolation("${" + value, 2, getItemSet(), getResource());
+                    valueObject = completionInterpolation.getReturnObject(context);
 				}
 			}
 			if (null != key) {
-				context.put(key, valueClass);
+				context.put(key, valueObject);
 			}
 		}
 		super.addToContext(context);
Index: src/org/jboss/ide/eclipse/freemarker/model/Interpolation.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/Interpolation.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/Interpolation.java	(working copy)
@@ -34,6 +34,7 @@
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.jboss.ide.eclipse.freemarker.model.interpolation.BuiltInFragment;
 import org.jboss.ide.eclipse.freemarker.model.interpolation.Fragment;
+import org.jboss.ide.eclipse.freemarker.model.interpolation.IndexedParametersFragment;
 import org.jboss.ide.eclipse.freemarker.model.interpolation.NameFragment;
 import org.jboss.ide.eclipse.freemarker.model.interpolation.NullFragment;
 import org.jboss.ide.eclipse.freemarker.model.interpolation.ParametersFragment;
@@ -93,15 +94,15 @@
 			else break;
 		}
 		if (null != fragment) {
-			// find the parent class
-			Class parentClass = null;
-			for (Iterator i = fragments.iterator(); i.hasNext(); ) {
-				Fragment fragmentSub = (Fragment) i.next();
-				if (fragmentSub.equals(fragment)) break;
-				else parentClass = fragmentSub.getReturnClass(parentClass, fragments, context, getResource(), getResource().getProject());
-			}
-			return fragment.getCompletionProposals(
-				subOffset - fragment.getOffset(), offset, parentClass, fragments, getViewer(), context, getResource(), getResource().getProject());
+		    // find the parent object
+            Object parentObject = null;
+            for (Iterator i = fragments.iterator(); i.hasNext(); ) {
+                Fragment fragmentSub = (Fragment) i.next();
+                if (fragmentSub.equals(fragment)) break;
+                else parentObject = fragmentSub.getReturnObject(parentObject, fragments, context, getResource(), getResource().getProject());
+            }
+            return fragment.getCompletionProposals(
+                subOffset - fragment.getOffset(), offset, parentObject, fragments, getViewer(), context, getResource(), getResource().getProject());
 		}
 		else if (getContents().length() == 0 && subOffset == 0) {
 			return new NullFragment().getCompletionProposals(
@@ -122,13 +123,14 @@
 		boolean inBuiltIn = false;
 		boolean inNameFragment = false;
 		boolean inParameters = false;
+        boolean inIndexedParameters = false;
 		boolean escape = false;
 		boolean doEscape = false;
 		int offset = getOffset();
 		for (int i=0; i<contents.length(); i++) {
 			doEscape = false;
 			char c = contents.charAt(i);
-			if (Character.isLetterOrDigit(c) && !inString && !inBuiltIn && !inNameFragment && !inParameters)
+			if (Character.isLetterOrDigit(c) && !inString && !inBuiltIn && !inNameFragment && !inParameters && !inIndexedParameters)
 				inNameFragment = true;
 			if (inNameFragment) {
 				if (c == '?') {
@@ -159,6 +161,21 @@
 					sb.delete(0, sb.length());
 					inNameFragment = false;
 				}
+                else if (c == '[') {
+                    // for now, forget about the stack
+                    fragments.add(new NameFragment(offsetStart, sb.toString()));
+                    offsetStart = i;
+                    sb.delete(0, sb.length());
+                    inNameFragment = false;
+                    inIndexedParameters = true;
+                }
+                else if (c == ']') {
+                    // for now, forget about the stack
+                    fragments.add(new NameFragment(offsetStart, sb.toString()));
+                    offsetStart = i+1;
+                    sb.delete(0, sb.length());
+                    inNameFragment = false;
+                }
 				else sb.append(c);
 			}
 			else if (inBuiltIn) {
@@ -192,6 +209,21 @@
 				}
 				else sb.append(c);
 			}
+            else if (inIndexedParameters) {
+                if (inString) if (!escape && c == '\"') inString = false;
+                if (!inString && c == ']') {
+                    fragments.add(new IndexedParametersFragment(offsetStart, sb.toString()));
+                    offsetStart = i+1;
+                    sb.delete(0, sb.length());
+                }
+                else  {
+                    if (c == '.') { 
+                        inIndexedParameters = false;
+                        inNameFragment = true;
+                    }
+                    sb.append(c);
+                }
+            }
 			else if (inString) {
 				if (escape) sb.append(c);
 				else if (c == '\"') {
@@ -233,6 +265,18 @@
 					sb.delete(0, sb.length());
 				}
 			}
+            else if (c == '[') {
+                if (fragments.size() == 0) {
+                    // for now, forget about the stack
+                }
+                else {
+                    if (sb.length() > 0 && !inBuiltIn)
+                        fragments.add(new NameFragment(offsetStart, sb.toString()));
+                    inIndexedParameters = true;
+                    offsetStart = i;
+                    sb.delete(0, sb.length());
+                }
+            }
 			else if (c == '"') {
 				if (sb.length() > 0) fragments.add(new NameFragment(offsetStart, sb.toString()));
 				inString = true;
@@ -257,26 +301,26 @@
 		return false;
 	}
 
-	public Class getReturnClass (Map context) {
+    public Object getReturnObject (Map context) {
+        initFragments();
+        Object returnObject = null;
+        for (Iterator i=fragments.iterator(); i.hasNext(); ) {
+            Fragment fragment = (Fragment) i.next();
+            returnObject = fragment.getReturnObject(returnObject, fragments, context, getResource(), getResource().getProject());
+        }
+        return returnObject;
+    }
+    
+	public Object getSingularReturnObject (Map context) {
 		initFragments();
-		Class returnClass = null;
+		Object returnObject = null;
 		for (Iterator i=fragments.iterator(); i.hasNext(); ) {
 			Fragment fragment = (Fragment) i.next();
-			returnClass = fragment.getReturnClass(returnClass, fragments, context, getResource(), getResource().getProject());
+            if (i.hasNext())
+                returnObject = fragment.getReturnObject(returnObject, fragments, context, getResource(), getResource().getProject());
+            else
+                returnObject = fragment.getSingularReturnObject(returnObject, fragments, context, getResource(), getResource().getProject());
 		}
-		return returnClass;
-	}
-
-	public Class getSingularReturnClass (Map context) {
-		initFragments();
-		Class returnClass = null;
-		for (Iterator i=fragments.iterator(); i.hasNext(); ) {
-			Fragment fragment = (Fragment) i.next();
-			if (i.hasNext())
-				returnClass = fragment.getReturnClass(returnClass, fragments, context, getResource(), getResource().getProject());
-			else
-				returnClass = fragment.getSingularReturnClass(returnClass, fragments, context, getResource(), getResource().getProject());
-		}
-		return returnClass;
+		return returnObject;
 	}
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/model/AbstractItem.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/AbstractItem.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/AbstractItem.java	(working copy)
@@ -153,6 +153,7 @@
 		boolean doAppend = true;
 		boolean encounteredSpace = false;
 		boolean nextCharSpace = false;
+        boolean encounteredEscapeVariableName = false; // true for doc["fffff
 		for (int i=0; i<s.length(); i++) {
 			encounteredSpace = false;
 			char c = s.charAt(i);
@@ -226,8 +227,33 @@
 				}
 			}
 			if (doAppend) {
-				current.append(c);
-				offsetCount++;
+                boolean doAppendSpecialCharacter = false;
+                if (c == '\"') {
+                    // current character is "
+                    // if s=doc["hibernate-mapping"]. ...
+                    // doc.hibernate-mapping. must be returned
+                    if (i > 2 && s.charAt(i-1) == '[') {
+                        char lastChar = s.charAt(i-2);
+                        if (lastChar != ' ' && lastChar != '=') {
+                            encounteredEscapeVariableName = true;
+                            doAppendSpecialCharacter = true;
+                            current.append('.');
+                            offsetCount++;
+                        }
+                    }
+                    else {
+                        if (s.length() > i + 2&& s.charAt(i+1) == ']') {
+                            char nextChar = s.charAt(i+2);
+                            if (encounteredEscapeVariableName == true)
+                                doAppendSpecialCharacter = true;
+                            encounteredEscapeVariableName = false;
+                        }
+                    }
+                }
+                if (!doAppendSpecialCharacter) {
+                    current.append(c);
+                    offsetCount++;
+                }
 			}
 			escape = doEscape;
 			doEscape = false;
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/StringFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/StringFragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/StringFragment.java	(working copy)
@@ -38,11 +38,11 @@
 		super(offset, content);
 	}
 
-	public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project) {
-		return parentClass;
+	public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project) {
+		return parentObject;
 	}
 
-	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
+	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Object parentObject,
 			List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
 		return null;
 	}
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/Fragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/Fragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/Fragment.java	(working copy)
@@ -34,10 +34,10 @@
  */
 public interface Fragment {
 
-	public int getOffset();
-	public int getLength();
-	public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project);
-	public Class getSingularReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project);
-	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
-			List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project);
+    public int getOffset();
+    public int getLength();
+    public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project);
+    public Object getSingularReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project);
+    public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Object parentObject,
+            List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project);
 }
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/IndexedParametersFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/IndexedParametersFragment.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/IndexedParametersFragment.java	(revision 0)
@@ -0,0 +1,42 @@
+package org.jboss.ide.eclipse.freemarker.model.interpolation;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+
+/**
+ *  
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class IndexedParametersFragment extends NameFragment {
+
+	public IndexedParametersFragment(int offset, String content) {
+		super(offset, content);
+	}
+
+	public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project) {
+		return super.getReturnObject(parentObject, fragments, context, resource, project);
+	}
+
+	public String getContent() {
+		String content = super.getContent();
+		if (content.startsWith("\""))
+			content = content.substring(1, content.length());
+		if (content.endsWith("\""))
+			content = content.substring(0, content.length() -1);
+		return content;
+	}
+	
+	public boolean isStartFragment () {
+		return false;
+	}
+	
+	public int getLength() {
+		return  getContent().length();
+	}
+	
+}
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/NameFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/NameFragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/NameFragment.java	(working copy)
@@ -42,7 +42,9 @@
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.helper.CompletionProposalHelper;
+import org.jboss.ide.eclipse.freemarker.helper.ContextValueHelper;
 
 /**
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
@@ -53,97 +55,149 @@
 		super(offset, content);
 	}
 
-	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
+	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Object parentObject,
 			List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
-		if (isStartFragment()) {
-			// pull from context
-			String prefix = getContent().substring(0, subOffset);
-			List proposals = new ArrayList();
-			for (Iterator i=context.keySet().iterator(); i.hasNext(); ) {
-				String key = (String) i.next();
-				if (key.startsWith(prefix)) proposals.add(getCompletionProposal(
-						offset, subOffset, key, getContent()));
-			}
-			return completionProposals(proposals);
-		}
-		else {
-			if (null == parentClass) return null;
-			return getMethodCompletionProposals (subOffset, offset, parentClass, file);
-		}
+        String content = getContent();
+        if (ContextValueHelper.isStartFragment(content)) {
+            // pull from context
+            String prefix = getContent().substring(0, subOffset);
+            List proposals = new ArrayList();
+            for (Iterator i=context.keySet().iterator(); i.hasNext(); ) {
+                String key = (String) i.next();
+                if (key.startsWith(prefix)) proposals.add(getCompletionProposal(
+                        offset, subOffset, key, content));
+            }
+            return CompletionProposalHelper.completionProposals(proposals);
+        }
+        else {
+            if (null == parentObject) return null;
+            return CompletionProposalHelper.
+                getProposalsForParentObject(content, subOffset, offset, parentObject, file);
+        }
 	}
 
-	private Class returnClass;
-	public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project){
-		if (null == returnClass) {
+    private Object returnObject;
+    public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project){
+        if (null == returnObject) {
 			String content = getContent();
-			if (isStartFragment()) {
-				returnClass = (Class) context.get(content);
-			}
-			else {
-				if (null == parentClass) {
-					returnClass = Object.class;
-				}
-				else {
-					content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
-					String getcontent = "get" + content; //$NON-NLS-1$
-					for (int i=0; i<parentClass.getMethods().length; i++) {
-						Method m = parentClass.getMethods()[i];
-						if (m.getName().equals(content) || m.getName().equals(getcontent)) {
-							returnClass = m.getReturnType();
-							break;
-						}
-					}
-				}
-			}
-		}
-		return returnClass;
-	}
+            // Test type of context 
+            Object objectContext = context.get(content);
+            if (ContextValueHelper.isStringContextValue(objectContext)) {
+                // It's String context
+                // Completion must be stopped.
+                return null;
+            }
+            
+            if (objectContext != null && 
+                ContextValueHelper.isStartFragment(content)) {
+                return objectContext;
+            }
+            
+            if ((ContextValueHelper.isXMLContextValue(objectContext) ||
+                 ContextValueHelper.isXMLContextValue(parentObject))) {
+                // It's XML context
+                String eltcontent = content; 
+                if (content.startsWith("."))
+                    eltcontent = content.substring(1, content.length());
+                return ContextValueHelper.getChildNode(parentObject, eltcontent);
+            }            
 
-	private Class singulaReturnClass;
-	public Class getSingularReturnClass(Class parentClass, List fragments, Map context, IResource resource, IProject project) {
-		if (null == singulaReturnClass) {
-			String content = getContent();
-			if (isStartFragment()) {
-				ContextValue contextValue = ConfigurationManager.getInstance(project).getContextValue(content, resource, true);
-				if (null == contextValue || null == contextValue.singularClass)
-					singulaReturnClass = Object.class;
-				else
-					singulaReturnClass = contextValue.singularClass;
-			}
-			else {
-				if (null == parentClass) {
-					singulaReturnClass = Object.class;
-				}
-				else {
-					content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
-					String getcontent = "get" + content; //$NON-NLS-1$
-					for (int i=0; i<parentClass.getMethods().length; i++) {
-						Method m = parentClass.getMethods()[i];
-						if (m.getName().equals(content) || m.getName().equals(getcontent)) {
-							Type type = m.getGenericReturnType();
-							if (type instanceof ParameterizedType) {
-								ParameterizedType pType = (ParameterizedType) type;
-								if (pType.getActualTypeArguments().length > 0) {
-									singulaReturnClass = (Class) pType.getActualTypeArguments()[0];
-									break;
-								}
-							}
-							singulaReturnClass = Object.class;
-							break;
-						}
-					}
-				}
-			}
+           /* if ((ContextValueHelper.isDTDContextValue(objectContext) ||
+                 ContextValueHelper.isDTDContextValue(parentObject))) {
+                // It's DTD context
+                String eltcontent = content; 
+                if (content.startsWith("."))
+                    eltcontent = content.substring(1, content.length());
+                return ContextValueHelper.getChildDTDElement(parentObject, eltcontent);
+            }*/  
+            if ((ContextValueHelper.isClassContextValue(parentObject))) {
+                Class parentClass = (Class)parentObject;
+                content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
+                String getcontent = "get" + content;
+                for (int i=0; i<parentClass.getMethods().length; i++) {
+                    Method m = parentClass.getMethods()[i];
+                    if (m.getName().equals(content) || m.getName().equals(getcontent)) {
+                        return m.getReturnType();
+                    }
+                }
+            }
+            if (null == parentObject) {
+                return Object.class;
+            }
 		}
-		return singulaReturnClass;
+		return returnObject;
 	}
 
-	public boolean isStartFragment () {
-		return !getContent().startsWith("."); //$NON-NLS-1$
+    private Object singulaReturnObject;
+    public Object getSingularReturnObject(Object parentObject, List fragments, Map context, IResource resource, IProject project) {
+        if (null == singulaReturnObject) {
+            String content = getContent(); 
+            if (ContextValueHelper.isStartFragment(content)) {
+                IContextValue contextValue = ConfigurationManager.getInstance(project).getContextValue(content, resource, true);
+                if (contextValue != null) {
+                    int contexType = contextValue.getType();
+                    if(contexType == IContextValue.CLASS) {
+                        Class singularClass = null;
+                        if (contextValue != null) 
+                            singularClass = (Class)contextValue.getSecondObjectContext().getObject();
+                        
+                        if (singularClass == null)
+                            singulaReturnObject = Object.class;
+                        else
+                            singulaReturnObject = singularClass;
+                    }
+                }
+            }
+            else {
+                if (parentObject != null) {
+                    if (ContextValueHelper.isXMLContextValue(parentObject)) {
+                        // Its' XML context
+                        String eltcontent = content; //.substring(1, content.length());
+                        if (content.startsWith("."))
+                            eltcontent = content.substring(1, content.length());
+                        return ContextValueHelper.getChildNode(parentObject, eltcontent);
+                    }
+                    else {
+                       /* if ((ContextValueHelper.isDTDContextValue(parentObject) ||
+                             ContextValueHelper.isDTDContextValue(parentObject))) {
+                            // It's DTD context
+                            String eltcontent = content; 
+                            if (content.startsWith("."))
+                                eltcontent = content.substring(1, content.length());
+                            return ContextValueHelper.getChildDTDElement(parentObject, eltcontent);
+                         } 
+                        */
+                        
+                        if (ContextValueHelper.isClassContextValue(parentObject)) {
+                            Class parentClass = (Class)parentObject;
+                            if (content.length() > 2) {
+                                content = Character.toUpperCase(content.charAt(1)) + content.substring(2, getContent().length());
+                                String getcontent = "get" + content;
+                                for (int i=0; i<parentClass.getMethods().length; i++) {
+                                    Method m = parentClass.getMethods()[i];
+                                    if (m.getName().equals(content) || m.getName().equals(getcontent)) {
+                                        Type type = m.getGenericReturnType();
+                                        if (type instanceof ParameterizedType) {
+                                            ParameterizedType pType = (ParameterizedType) type;
+                                            if (pType.getActualTypeArguments().length > 0) {
+                                                singulaReturnObject = (Class) pType.getActualTypeArguments()[0];
+                                                break;
+                                            }
+                                        }
+                                        return Object.class;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return singulaReturnObject;
 	}
 
-	public static final String[] invalidMethods = {
-		"clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
+    public static final String[] invalidMethods = {
+		"clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait"};
 	public ICompletionProposal[] getMethodCompletionProposals (int subOffset, int offset, Class parentClass, IResource file) {
 		if (instanceOf(parentClass, String.class)
 				|| instanceOf(parentClass, Number.class)
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/BuiltInFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/BuiltInFragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/BuiltInFragment.java	(working copy)
@@ -164,7 +164,7 @@
 	}
 
 	private String subContent = null;
-	public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project) {
+    public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project) {
 		if (null == subContent) {
 			subContent = getContent();
 			int index = subContent.indexOf("("); //$NON-NLS-1$
@@ -182,24 +182,28 @@
 		else return null;
 	}
 
-	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
+	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Object parentObject,
 			List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
-		if (instanceOf(parentClass, String.class)) {
-			return getCompletionProposals(subOffset, offset, STRING_BUILT_INS);
-		}
-		else if (instanceOf(parentClass, Number.class)) {
-			return getCompletionProposals(subOffset, offset, NUMBER_BUILT_INS);
-		}
-		else if (instanceOf(parentClass, Date.class)) {
-			return getCompletionProposals(subOffset, offset, DATE_BUILT_INS);
-		}
-		else if (instanceOf(parentClass, Collection.class) || instanceOf(parentClass, List.class)) {
-			return getCompletionProposals(subOffset, offset, LIST_BUILT_INS);
-		}
-		else if (instanceOf(parentClass, Map.class)) {
-			return getCompletionProposals(subOffset, offset, MAP_BUILT_INS);
-		}
-		else return getCompletionProposals(subOffset, offset, OBJECT_BUILT_INS);
+        if (parentObject instanceof Class) {
+            Class parentClass = (Class)parentObject;
+            if (instanceOf(parentClass, String.class)) {
+                return getCompletionProposals(subOffset, offset, STRING_BUILT_INS);
+            }
+            else if (instanceOf(parentClass, Number.class)) {
+                return getCompletionProposals(subOffset, offset, NUMBER_BUILT_INS);
+            }
+            else if (instanceOf(parentClass, Date.class)) {
+                return getCompletionProposals(subOffset, offset, DATE_BUILT_INS);
+            }
+            else if (instanceOf(parentClass, Collection.class) || 
+                    instanceOf(parentClass, List.class)) {
+                return getCompletionProposals(subOffset, offset, LIST_BUILT_INS);
+            }
+            else if (instanceOf(parentClass, Map.class)) {
+                return getCompletionProposals(subOffset, offset, MAP_BUILT_INS);
+            }
+        }  
+        return getCompletionProposals(subOffset, offset, OBJECT_BUILT_INS);
 	}
 
 	private ICompletionProposal[] getCompletionProposals(int subOffset, int offset, Map values) {
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/AbstractFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/AbstractFragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/AbstractFragment.java	(working copy)
@@ -30,6 +30,7 @@
 import org.eclipse.core.resources.IResource;
 import org.eclipse.jface.text.contentassist.CompletionProposal;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.jboss.ide.eclipse.freemarker.helper.ClassHelper;
 
 /**
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
@@ -70,15 +71,7 @@
 	}
 
 	protected boolean instanceOf (Class test, Class base) {
-		if (null == test || null == base) return false;
-		while (null != test) {
-			for (int i=0; i<test.getInterfaces().length; i++) {
-				if (test.getInterfaces()[i].getClass().getName().equals(base.getName())) return true;
-			}
-			if (test.getName().equals(base.getName())) return true;
-			test = test.getSuperclass();
-		}
-		return false;
+		return ClassHelper.instanceOf(test, base);
 	}
 
 	public class CompletionProposalComparator implements Comparator {
@@ -87,7 +80,7 @@
 		}
 	}
 
-	public Class getSingularReturnClass(Class parentClass, List fragments, Map context, IResource resource, IProject project) {
-		return Object.class;
-	}
+    public Object getSingularReturnObject(Object parentObject, List fragments, Map context, IResource resource, IProject project) {
+        return null;
+    }
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/model/interpolation/ParametersFragment.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/model/interpolation/ParametersFragment.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/model/interpolation/ParametersFragment.java	(working copy)
@@ -34,16 +34,16 @@
  */
 public class ParametersFragment extends AbstractFragment {
 
-	public ParametersFragment(int offset, String content) {
-		super(offset, content);
-	}
+    public ParametersFragment(int offset, String content) {
+        super(offset, content);
+    }
 
-	public Class getReturnClass (Class parentClass, List fragments, Map context, IResource resource, IProject project) {
-		return parentClass;
-	}
+    public Object getReturnObject (Object parentObject, List fragments, Map context, IResource resource, IProject project) {
+        return parentObject;
+    }
 
-	public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Class parentClass,
-			List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
-		return null;
-	}
+    public ICompletionProposal[] getCompletionProposals (int subOffset, int offset, Object parentClass,
+            List fragments, ISourceViewer sourceViewer, Map context, IResource file, IProject project) {
+        return null;
+    }
 }
Index: src/org/jboss/ide/eclipse/freemarker/resources.properties
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/resources.properties	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/resources.properties	(working copy)
@@ -0,0 +1,29 @@
+# OpenResourceDialog Dialog Widget
+OpenResourceDialog.title=Select a XML file.
+OpenResourceDialog.help=XML file selected will be used into your context.
+
+# ContextValueDialog dialog Widget
+ContextValueDialog.title=Context Value Configuration
+ContextValueDialog.contextType.label=Context type:
+ContextValueDialog.key.label=Name:
+ContextValueDialog.classRadioButton.text=Class
+ContextValueDialog.xmlRadioButton.text=XML
+ContextValueDialog.browseButton.text=Browse
+ContextValueDialog.labelText.CLASS=Class:
+ContextValueDialog.labelText.XML=XML:
+
+# ContextValueDialog dialog messages
+ContextValueDialog.context.message=Click OK to save your context.
+ContextValueDialog.context.name.required=Choose the reference name!
+ContextValueDialog.context.CLASS.required=Choose the class name by using Browse button!
+ContextValueDialog.context.XML.required=Choose a XML file by using Browse button!
+
+# ContextProperties Property Page
+ContextProperties.description=Create pre-determined Velocity context variables for all files under this resource
+
+# OutlinePage
+OutlinePage.text=Set context class entry
+
+# Global Messages 
+Context.confirm.title=Confirmation
+Context.confirm.message=Are you sure you want to delete this context value?
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/Plugin.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/Plugin.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/Plugin.java	(working copy)
@@ -21,6 +21,7 @@
  */
 package org.jboss.ide.eclipse.freemarker;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.net.MalformedURLException;
@@ -40,9 +41,14 @@
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.text.templates.ContextTypeRegistry;
+import org.eclipse.jface.text.templates.persistence.TemplateStore;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
+import org.eclipse.ui.editors.text.templates.ContributionTemplateStore;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.jboss.ide.eclipse.freemarker.template.FreemarkerTemplateContextType;
 import org.osgi.framework.Bundle;
 
 /**
@@ -167,4 +173,34 @@
 		}
 		return null;
 	}
+	
+	private TemplateStore fStore;
+	
+	private ContributionContextTypeRegistry fRegistry;
+	
+	public ContextTypeRegistry getContextTypeRegistry(){
+        if(fRegistry == null) {
+            fRegistry = new ContributionContextTypeRegistry();
+            fRegistry.addContextType(FreemarkerTemplateContextType.FREEMARKER_CONTEXT_TYPE);
+        }
+        return fRegistry;
+    }
+	
+	 public TemplateStore getTemplateStore()
+	     {
+	         if(fStore == null)
+	         {
+	             fStore = new ContributionTemplateStore(getContextTypeRegistry(), getDefault().getPreferenceStore(), 
+	                     "org.jboss.ide.eclipse.freemarker.templates");
+	             try
+	             {
+	                 fStore.load();
+	             }
+	             catch(IOException e)
+	             {
+	                 log(e);
+	             }
+	         }
+	         return fStore;
+	     }   
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/FreemarkerMessages.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/FreemarkerMessages.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/FreemarkerMessages.java	(revision 0)
@@ -0,0 +1,53 @@
+package org.jboss.ide.eclipse.freemarker;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * 
+ * Freemarker Messages (see resources.properties).
+ *  
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class FreemarkerMessages {
+	
+	private static final String BUNDLE_NAME = "org.jboss.ide.eclipse.freemarker.resources";
+
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(BUNDLE_NAME);
+
+	private FreemarkerMessages() {
+	}
+
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+	
+	public static String getString(String key, String arg0) {
+		String[] args = {arg0};
+		return getString(key, args);
+	}
+	
+	public static String getString(String key, String arg0, String arg1) {
+		String[] args = {arg0, arg1};
+		return getString(key, args);
+	}
+	
+	public static String getString(String key, String[] args) {
+		if (args == null)
+			return getString(key);
+		try {
+			return MessageFormat.format(getString(key), args);
+		}
+		catch(Exception e) {
+			return '!' + key + '!';
+		}
+	}	
+}
Index: src/org/jboss/ide/eclipse/freemarker/outline/OutlineContentProvider.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/outline/OutlineContentProvider.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/outline/OutlineContentProvider.java	(working copy)
@@ -27,7 +27,8 @@
 
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.Viewer;
-import org.jboss.ide.eclipse.freemarker.editor.Editor;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
 import org.jboss.ide.eclipse.freemarker.model.Item;
 import org.jboss.ide.eclipse.freemarker.model.ItemSet;
 import org.jboss.ide.eclipse.freemarker.model.MacroDirective;
@@ -36,9 +37,9 @@
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
  */
 public class OutlineContentProvider implements ITreeContentProvider {
-	private Editor fEditor;
+	private SourceEditor fEditor;
 
-	public OutlineContentProvider(Editor anEditor) {
+	public OutlineContentProvider(SourceEditor anEditor) {
 		fEditor = anEditor;
 	}
 
Index: src/org/jboss/ide/eclipse/freemarker/outline/OutlinePage.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/outline/OutlinePage.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/outline/OutlinePage.java	(working copy)
@@ -49,8 +49,8 @@
 import org.jboss.ide.eclipse.freemarker.Messages;
 import org.jboss.ide.eclipse.freemarker.Plugin;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
-import org.jboss.ide.eclipse.freemarker.editor.Editor;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
 import org.jboss.ide.eclipse.freemarker.model.Interpolation;
 import org.jboss.ide.eclipse.freemarker.model.Item;
 import org.jboss.ide.eclipse.freemarker.model.ItemSet;
@@ -60,11 +60,11 @@
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
  */
 public class OutlinePage extends ContentOutlinePage implements IDoubleClickListener {
-	private Editor fEditor;
+	private SourceEditor fEditor;
 	private Object fInput;
 	private OutlineLabelProvider fLabelProvider;
 
-	public OutlinePage(Editor anEditor) {
+	public OutlinePage(SourceEditor anEditor) {
 		fEditor = anEditor;
 	}
 
@@ -184,11 +184,13 @@
 							ConfigurationManager configuration = ConfigurationManager.getInstance(interpolation.getResource().getProject());
 							IType type = (IType) objects[0];
 							try {
-								configuration.addContextValue(
-										new ContextValue(interpolation.getFirstToken(), 
-												configuration.getClass(type.getFullyQualifiedName()), null), interpolation.getResource());
+							    // TODO : manage other context type (like XML, ...)
+                                int contextType = IContextValue.CLASS; 
+                                IContextValue contextValue = configuration.getInstanceOfContextValue(contextType, interpolation.getFirstToken(), 
+                                        type.getFullyQualifiedName(), null);
+                                configuration.addContextValue(contextValue, interpolation.getResource());
 							}
-							catch (ClassNotFoundException e) {
+							catch (Exception e) {
 								Plugin.log(e);
 							}
 						}
Index: src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditor.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditor.java	(revision 0)
@@ -0,0 +1,155 @@
+package org.jboss.ide.eclipse.freemarker.editor.editorpart;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.EditorPart;
+import org.jboss.ide.eclipse.freemarker.Plugin;
+import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.w3c.dom.Document;
+
+import freemarker.ext.dom.NodeModel;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+/**
+ * 
+ * Preview Editor for the ftl template.  
+ * 
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class PreviewEditor extends EditorPart  {
+
+    private IEditorSite site;
+    private PreviewEditorInput previewEditorInput;
+    private StyledText text;
+    private Configuration freemarkerConfiguration;
+    
+    public PreviewEditor() {
+        this.freemarkerConfiguration = new Configuration();
+    }
+    
+    public void doSave(IProgressMonitor arg0) {  
+    }
+
+    public void doSaveAs() {
+    }
+
+    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+        this.site = site;
+        previewEditorInput = (PreviewEditorInput)input;
+    }
+
+    public boolean isDirty() {
+        return false;
+    }
+
+    public boolean isSaveAsAllowed() {
+        return false;
+    }
+
+    public void createPartControl(Composite composite) {
+        FillLayout layout = new FillLayout();
+        composite.setLayout(layout);
+        text = new StyledText(composite, SWT.H_SCROLL | SWT.V_SCROLL);
+        text.setEditable(false);
+    }
+
+    public void setFocus() {
+        preview();
+    }
+    
+    public IWorkbenchPartSite getSite() {
+        return site;
+    }
+    
+    private void preview() {
+        text.setText("");
+        IDocument sourceDocument = previewEditorInput.getSourceDocument();
+        IFile contextValuesFile = previewEditorInput.getContextValuesFile();
+        String pageContents = sourceDocument.get();
+        try {
+            IProject project = contextValuesFile.getProject();
+            /* Prepare Freemarker template with Source tab */ 
+            Reader reader = new StringReader(pageContents);
+            Template template = new Template("preview.ftl", reader, this.freemarkerConfiguration);
+            reader.close();     
+            
+            /* Prepare Model */ 
+            Map model = new HashMap();
+            IContextValue[] contextValues = ConfigurationManager.getInstance(
+                    project).getContextValues(contextValuesFile, false);
+            if (contextValues != null) {
+                for (int i = 0; i < contextValues.length; i++) {
+                    IContextValue contextValue = contextValues[i];
+                    String contextName = contextValue.getName();
+                    if (IContextValue.STRING == contextValue.getType()) {
+                        String stringValue = (String)contextValue.getFirstObjectContext().getObject();
+                        model.put(contextName , stringValue);
+                    }
+                    else {
+                        if (IContextValue.XML == contextValue.getType()) {
+                            Document document = (Document)contextValue.getFirstObjectContext().getObject();
+                            NodeModel nodeModel = NodeModel.wrap(document);
+                            model.put(contextName , nodeModel);
+                        }
+                        else {
+                            if (IContextValue.CLASS == contextValue.getType()) {
+                                Class objectClass = (Class)contextValue.getFirstObjectContext().getObject();
+                                try {
+                                    Object objectInstance = objectClass.newInstance();
+                                    model.put(contextName , objectInstance);
+                                }
+                                catch (Exception e) {
+                                    Plugin.log(e);
+                                }
+                            }
+                        }
+                    }
+                    
+                }
+            }
+            
+             /* Merge data model with template */
+            StringWriter out = new StringWriter();
+            template.process(model, out);
+            out.flush();    
+            
+            text.setText(out.toString());
+            
+        } catch (TemplateException e) {
+            StringWriter out = new StringWriter();
+            PrintWriter print = new PrintWriter(out);
+            e.printStackTrace(print);
+            out.flush();    
+            text.setText(out.toString());
+            Plugin.log(e);
+        }
+        catch (IOException e) {
+            Plugin.log(e);
+        }   
+    }
+
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditorInput.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditorInput.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/editor/editorpart/PreviewEditorInput.java	(revision 0)
@@ -0,0 +1,56 @@
+package org.jboss.ide.eclipse.freemarker.editor.editorpart;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+
+/**
+ * 
+ * Description : 
+ * @version 1.0.0 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class PreviewEditorInput implements IEditorInput {
+
+    private IDocument sourceDocument;
+    private IFile contextValuesFile;
+    
+    public PreviewEditorInput(IFile contextValuesFile, IDocument sourceDocument) {
+        this.sourceDocument = sourceDocument;
+        this.contextValuesFile = contextValuesFile;
+    }
+    
+    public Object getAdapter(Class arg0) {
+        return null;
+    }
+
+    public boolean exists() {
+        return false;
+    }
+
+    public ImageDescriptor getImageDescriptor() {
+        return null;
+    }
+
+    public String getName() {
+        return "PrevEd";
+    }
+
+    public IPersistableElement getPersistable() {
+        return null;
+    }
+
+    public String getToolTipText() {
+        return null;
+    }
+    public IDocument getSourceDocument() {
+        return sourceDocument;
+    }
+    public IFile getContextValuesFile() {
+        return contextValuesFile;
+    }
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/editor/editorpart/SourceEditor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/editorpart/SourceEditor.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/editor/editorpart/SourceEditor.java	(revision 0)
@@ -0,0 +1,502 @@
+/*
+ * JBoss, a division of Red Hat
+ * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ide.eclipse.freemarker.editor.editorpart;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.internal.ui.javaeditor.JarEntryEditorInput;
+import org.eclipse.jdt.internal.ui.text.JavaPairMatcher;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewerExtension2;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.MatchingCharacterPainter;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ContentAssistAction;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+import org.eclipse.ui.texteditor.MarkerUtilities;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.jboss.ide.eclipse.freemarker.Constants;
+import org.jboss.ide.eclipse.freemarker.Plugin;
+import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
+import org.jboss.ide.eclipse.freemarker.editor.ColorManager;
+import org.jboss.ide.eclipse.freemarker.editor.DocumentProvider;
+import org.jboss.ide.eclipse.freemarker.model.Item;
+import org.jboss.ide.eclipse.freemarker.model.ItemSet;
+import org.jboss.ide.eclipse.freemarker.outline.OutlinePage;
+
+import freemarker.core.ParseException;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+
+/**
+ * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
+ */
+public class SourceEditor extends TextEditor implements KeyListener, MouseListener {
+
+	private OutlinePage fOutlinePage;
+	private org.jboss.ide.eclipse.freemarker.editor.Configuration configuration;
+	private ColorManager colorManager = new ColorManager();
+
+	private ItemSet itemSet;
+	private Item selectedItem;
+	private Item[] relatedItems;
+	private static final char[] VALIDATION_TOKENS = new char[]{'\"', '[', ']', ',', '.', '\n', '4'};
+	private boolean readOnly = false;
+
+	private boolean mouseDown = false;
+	private boolean ctrlDown = false;
+	private boolean shiftDown = false;
+
+	public SourceEditor() {
+		super();
+		configuration = new org.jboss.ide.eclipse.freemarker.editor.Configuration(getPreferenceStore(), colorManager, this);
+		setSourceViewerConfiguration(configuration);
+		setDocumentProvider(new DocumentProvider());
+	}
+	
+	
+	
+	public void dispose() {
+		ConfigurationManager.getInstance(getProject()).reload();
+		super.dispose();
+		if(matchingCharacterPainter!=null) {
+			matchingCharacterPainter.dispose();
+		}
+	}
+
+	public Object getAdapter(Class aClass) {
+	    Object adapter;
+		if (aClass.equals(IContentOutlinePage.class)) {
+			if (fOutlinePage == null) {
+			    fOutlinePage = new OutlinePage(this);
+				if (getEditorInput() != null) {
+					fOutlinePage.setInput(getEditorInput());
+				}
+			}
+			adapter = fOutlinePage;
+		} else {
+		    adapter = super.getAdapter(aClass);
+		}
+		return adapter;
+	}
+
+	protected static final char[] BRACKETS= {'{', '}', '(', ')', '[', ']', '<', '>' };
+	private MatchingCharacterPainter matchingCharacterPainter;
+	public void createPartControl(Composite parent) {
+		super.createPartControl(parent);
+		 getSourceViewer().getTextWidget().addKeyListener(this);
+		 getSourceViewer().getTextWidget().addMouseListener(this);
+		 //matchingCharacterPainter = new MatchingCharacterPainter(
+			//	 getSourceViewer(),
+				// new JavaPairMatcher(BRACKETS));
+		//((SourceViewer) getSourceViewer()).addPainter(matchingCharacterPainter);
+	}
+
+	protected void createActions() {
+		super.createActions();
+		// Add content assist propsal action
+		ContentAssistAction action = new ContentAssistAction(
+				Plugin.getDefault().getResourceBundle(),
+				"FreemarkerEditor.ContentAssist", this);
+		action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
+		setAction("FreemarkerEditor.ContentAssist", action);
+		action.setEnabled(true);
+	}
+
+	protected void handleCursorPositionChanged() {
+		super.handleCursorPositionChanged();
+		if (!mouseDown) {
+			int offset = getCaretOffset();
+			Item item = getItemSet().getSelectedItem(offset);
+			if (null == item && offset > 0) item = getItemSet().getSelectedItem(offset-1);
+			if (Plugin.getInstance().getPreferenceStore().getBoolean(
+					Constants.HIGHLIGHT_RELATED_ITEMS)) {
+				if (null != item && null != item.getRelatedItems() && item.getRelatedItems().length > 0) {
+					highlightRelatedRegions(item.getRelatedItems(), item);
+				}
+				else {
+					highlightRelatedRegions(null, item);
+				}
+			}
+			if (null == item) {
+				item = getItemSet().getContextItem(getCaretOffset());
+			}
+			if (null != fOutlinePage)
+				fOutlinePage.update(item);
+		}
+	}
+	public void mouseDoubleClick(MouseEvent e) {
+	}
+	public void mouseDown(MouseEvent e) {
+		mouseDown = true;
+	}
+	public void mouseUp(MouseEvent e) {
+		mouseDown = false;
+		handleCursorPositionChanged();
+	}
+
+	public void select (Item item) {
+		selectAndReveal(item.getRegion().getOffset(), item.getRegion().getLength());
+	}
+
+	public IDocument getDocument() {
+		ISourceViewer viewer = getSourceViewer();
+		if (viewer != null) {
+			return viewer.getDocument();
+		}
+		return null;
+	}
+
+	public void addProblemMarker(String aMessage, int aLine) {
+		IFile file = ((IFileEditorInput)getEditorInput()).getFile(); 
+		try {
+			Map attributes = new HashMap(5);
+			attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
+			attributes.put(IMarker.LINE_NUMBER, new Integer(aLine));
+			attributes.put(IMarker.MESSAGE, aMessage);
+			attributes.put(IMarker.TEXT, aMessage);
+			MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
+		} catch (Exception e) {
+			
+		}
+	}
+
+	private synchronized void highlightRelatedRegions (Item[] items, Item selectedItem) {
+		if (null == items || items.length == 0) {
+			if (null != relatedItems && relatedItems.length > 0) {
+				for (int i=0; i<relatedItems.length; i++) {
+					if (getDocument().getLength() >= relatedItems[i].getRegion().getOffset() + relatedItems[i].getRegion().getLength()) {
+						if (null == this.selectedItem || !relatedItems[i].equals(this.selectedItem))
+							resetRange(relatedItems[i].getRegion());
+					}
+				}
+			}
+			relatedItems = null;
+		}
+		if (null != relatedItems) {
+			for (int i=0; i<relatedItems.length; i++) {
+				if (getDocument().getLength() >= relatedItems[i].getRegion().getOffset() + relatedItems[i].getRegion().getLength()) {
+					if (null == this.selectedItem || !relatedItems[i].equals(this.selectedItem))
+						resetRange(relatedItems[i].getRegion());
+				}
+			}
+		}
+		if (null != items && items.length > 0) {
+			for (int i=0; i<items.length; i++) {
+				if (getDocument().getLength() >= items[i].getRegion().getOffset() + items[i].getRegion().getLength()
+						&& !items[i].equals(selectedItem)) {
+					ITypedRegion region = items[i].getRegion();
+					getSourceViewer().getTextWidget().setStyleRange(
+							new StyleRange(region.getOffset(),
+									region.getLength(), null, 
+									colorManager.getColor(
+											Constants.COLOR_RELATED_ITEM)));
+				}
+			}
+		}
+		relatedItems = items;
+		this.selectedItem = selectedItem;
+	}
+
+	private void resetRange (ITypedRegion region) {
+		if (getSourceViewer() instanceof ITextViewerExtension2)
+			((ITextViewerExtension2) getSourceViewer()).invalidateTextPresentation(region.getOffset(), region.getLength());
+		else
+			getSourceViewer().invalidateTextPresentation();
+	}
+
+	public Item getSelectedItem (boolean allowFudge) {
+		int caretOffset = getCaretOffset();
+		Item item = getItemSet().getSelectedItem(getCaretOffset());
+		if (null == item && caretOffset > 0) item = getItemSet().getSelectedItem(caretOffset - 1);
+		return item;
+	}
+
+	public Item getSelectedItem () {
+		return getItemSet().getSelectedItem(getCaretOffset());
+	}
+
+	public int getCaretOffset () {
+		return getSourceViewer().getTextWidget().getCaretOffset();
+	}
+
+	public void clearCache () {
+		this.itemSet = null;
+	}
+
+	public ItemSet getItemSet () {
+		if (null == this.itemSet) {
+			IResource resource = null;
+			if (getEditorInput() instanceof IFileEditorInput) {
+				resource = ((IFileEditorInput) getEditorInput()).getFile();
+			}
+			else if (getEditorInput() instanceof JarEntryEditorInput) {
+				resource = null;
+			}
+			
+			this.itemSet = new ItemSet(
+					getSourceViewer(), resource);
+		}
+		return this.itemSet;
+			
+	}
+	public OutlinePage getOutlinePage() {
+		return fOutlinePage;
+	}
+
+	public void keyPressed(KeyEvent e) {
+		if (e.keyCode == SWT.CTRL) {
+			ctrlDown = true;
+		}
+		if (e.keyCode == SWT.SHIFT) {
+			shiftDown = true;
+		}
+		if (e.keyCode == ']') {
+			try {
+				char c = getDocument().getChar(getCaretOffset());
+				if (c == ']') {
+					// remove this
+					getDocument().replace(getCaretOffset(), 1, "");
+				}
+			}
+			catch (BadLocationException e1) {}
+		}
+		else if (e.keyCode == '}') {
+			try {
+				char c = getDocument().getChar(getCaretOffset());
+				if (c == '}') {
+					// remove this
+					getDocument().replace(getCaretOffset(), 1, "}");
+				}
+			}
+			catch (BadLocationException e1) {}
+		}
+	}
+
+	public void keyReleased(KeyEvent e) {
+		if (e.keyCode == SWT.CTRL) {
+			ctrlDown = false;
+		}
+		else if (e.keyCode == SWT.SHIFT) {
+			shiftDown = false;
+		}
+		try {
+			if (shiftDown && (e.keyCode == '3' || e.keyCode == '2')) {
+				int offset = getCaretOffset();
+				char c = getSourceViewer().getDocument().getChar(offset-2);
+				if (c == '[' || c == '<') {
+					// directive
+					char endChar = Character.MIN_VALUE;
+					if (c == '[') endChar = ']'; else endChar = '>';
+					if (getSourceViewer().getDocument().getLength() > offset) {
+						if (offset > 0) {
+							for (int i=offset+1; i<getSourceViewer().getDocument().getLength(); i++) {
+								char c2 = getSourceViewer().getDocument().getChar(i);
+								if (i == endChar) return;
+								else if (i == '\n') break;
+							}
+							getSourceViewer().getDocument().replace(offset, 0, new String(new char[]{endChar}));
+						}
+					}
+					else {
+						getSourceViewer().getDocument().replace(offset, 0, new String(new char[]{endChar}));
+					}
+				}
+			}
+			else if (shiftDown && e.keyCode == '[') {
+				int offset = getCaretOffset();
+				char c = getSourceViewer().getDocument().getChar(offset-2);
+				if (c == '$') {
+					// interpolation
+					if (getSourceViewer().getDocument().getLength() > offset) {
+						if (offset > 0) {
+							for (int i=offset+1; i<getSourceViewer().getDocument().getLength(); i++) {
+								char c2 = getSourceViewer().getDocument().getChar(i);
+								if (i == '}') return;
+								else if (i == '\n') break;
+							}
+							getSourceViewer().getDocument().replace(offset, 0, "}");
+						}
+					}
+					else {
+						getSourceViewer().getDocument().replace(offset, 0, "}");
+					}
+				}
+			}
+		}
+		catch (BadLocationException exc) {
+			// do nothing
+		}
+
+		boolean stale = false;
+		if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS) {
+			stale = true;
+		}
+		else if (null != getSelectedItem(true)) {
+			stale = true;
+		}
+		else {
+			char c = (char) e.keyCode;
+			for (int j=0; j<VALIDATION_TOKENS.length; j++) {
+				if (c == VALIDATION_TOKENS[j]) {
+					stale = true;
+					break;
+				}
+			}
+			if (ctrlDown && (e.keyCode == 'v' || e.keyCode == 'x')) {
+				stale = true;
+			}
+		}
+		if (stale) {
+			int offset = getCaretOffset();
+			Item item = getItemSet().getSelectedItem(offset);
+			if (null == item && offset > 0) item = getItemSet().getSelectedItem(offset-1);
+			if (Plugin.getInstance().getPreferenceStore().getBoolean(
+					Constants.HIGHLIGHT_RELATED_ITEMS)) {
+				if (null != item && null != item.getRelatedItems() && item.getRelatedItems().length > 0) {
+					highlightRelatedRegions(item.getRelatedItems(), item);
+				}
+				else {
+					highlightRelatedRegions(null, item);
+				}
+			}
+			clearCache();
+			validateContents();
+			if (null != fOutlinePage)
+				fOutlinePage.update(getSelectedItem());
+		}
+	}
+
+	private void showMessage (String text) {
+		MessageDialog.openError(
+				getSourceViewer().getTextWidget().getShell(),
+				"message",
+				text);
+	}
+
+	public static Validator VALIDATOR;
+	public synchronized void validateContents () {
+		if (null == VALIDATOR) {
+			VALIDATOR = new Validator(this);
+			VALIDATOR.start();
+		}
+	}
+
+	public IProject getProject () {
+		return ((IFileEditorInput) getEditorInput()).getFile().getProject();
+	}
+
+	public IFile getFile () {
+		return (null != getEditorInput()) ? 
+				((IFileEditorInput) getEditorInput()).getFile() : null;
+	}
+
+	private Configuration fmConfiguration;
+	public class Validator extends Thread {
+		SourceEditor editor;
+		public Validator (SourceEditor editor) {
+			this.editor = editor;
+		}
+		public void run () {
+			try {
+				if (null != getFile()) {
+					if (null == fmConfiguration) {
+						fmConfiguration = new Configuration();
+						fmConfiguration.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX); 
+					}
+					getFile().deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
+					String pageContents = getDocument().get();
+					Reader reader = new StringReader(pageContents);
+					new Template(getFile().getName(), reader, fmConfiguration);
+					reader.close();
+				}
+			}
+			catch (ParseException e) {
+				if (e.getMessage() != null) {
+					String errorStr = e.getMessage();
+					int errorLine = 0;
+					try {
+						errorLine = e.getLineNumber();
+						if (errorLine == 0) {
+							// sometimes they forget to put it in
+							int index = e.getMessage().indexOf("line: ");
+							if (index > 0) {
+								int index2 = e.getMessage().indexOf(" ", index+6);
+								int index3 = e.getMessage().indexOf(",", index+6);
+								if (index3 < index2 && index3 > 0) index2 = index3;
+								String s = e.getMessage().substring(index+6, index2);
+								try {
+									errorLine = Integer.parseInt(s);
+								}
+								catch (Exception e2) {}
+							}
+						}
+					} catch (NullPointerException npe) {
+						errorLine = 0;
+					}
+					editor.addProblemMarker(errorStr, errorLine);
+				}
+			}
+			catch (Exception e) {
+				Plugin.log(e);
+			}
+			finally {
+				editor.VALIDATOR = null;
+			}
+		}
+	}
+
+	protected void editorSaved() {
+		super.editorSaved();
+		validateContents();
+	}
+
+	public boolean isEditorInputReadOnly() {
+		return readOnly;
+	}
+	public void setReadOnly(boolean readOnly) {
+		this.readOnly = readOnly;
+	}
+	
+	public ISourceViewer getInternalSourceViewer() {
+		return super.getSourceViewer();
+	}
+}
Index: src/org/jboss/ide/eclipse/freemarker/editor/Configuration.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/Configuration.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/editor/Configuration.java	(working copy)
@@ -36,6 +36,8 @@
 import org.eclipse.jface.text.source.ISourceViewer;
 import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
 import org.jboss.ide.eclipse.freemarker.Constants;
+import org.jboss.ide.eclipse.freemarker.contentassist.CompletionProcessor;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
 
 /**
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
@@ -44,9 +46,9 @@
 	private ColorManager colorManager;
 	private XMLTagScanner xmlTagScanner;
 	private DirectiveScanner directiveScanner;
-	private Editor editor;
+	private SourceEditor editor;
 
-	public Configuration(IPreferenceStore preferenceStore, ColorManager colorManager, Editor editor) {
+	public Configuration(IPreferenceStore preferenceStore, ColorManager colorManager, SourceEditor editor) {
 		super(preferenceStore);
 		this.editor = editor;
 		this.colorManager = colorManager;
Index: src/org/jboss/ide/eclipse/freemarker/editor/CompletionProcessor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/CompletionProcessor.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/editor/CompletionProcessor.java	(working copy)
@@ -1,189 +0,0 @@
-/*
- * JBoss by Red Hat
- * Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.ide.eclipse.freemarker.editor;
-
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.core.resources.IResource;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.ITextViewer;
-import org.eclipse.jface.text.contentassist.CompletionProposal;
-import org.eclipse.jface.text.contentassist.ICompletionProposal;
-import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
-import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.text.templates.Template;
-import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
-import org.eclipse.jface.text.templates.TemplateContextType;
-import org.eclipse.swt.graphics.Image;
-import org.jboss.ide.eclipse.freemarker.Plugin;
-import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
-import org.jboss.ide.eclipse.freemarker.model.CompletionDirective;
-import org.jboss.ide.eclipse.freemarker.model.CompletionInterpolation;
-import org.jboss.ide.eclipse.freemarker.model.CompletionMacroInstance;
-import org.jboss.ide.eclipse.freemarker.model.Item;
-import org.jboss.ide.eclipse.freemarker.model.ItemSet;
-import org.jboss.ide.eclipse.freemarker.model.MacroInstance;
-
-/**
- * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
- */
-public class CompletionProcessor extends TemplateCompletionProcessor implements IContentAssistProcessor {
-
-	private Editor editor;
-	
-	private static final ICompletionProposal[] NO_COMPLETIONS = new ICompletionProposal[0];
-	
-	public CompletionProcessor (Editor editor) {
-		this.editor = editor;
-	}
-	
-	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
-		try {
-			ItemSet directiveSet = editor.getItemSet();
-	
-			Map context = new HashMap();
-			ContextValue[] values = ConfigurationManager.getInstance(editor.getProject()).getContextValues(editor.getFile(), true);
-			for (int i=0; i<values.length; i++) {
-				context.put(values[i].name, values[i].objClass);
-			}
-			
-			Item directive = directiveSet.getSelectedItem(offset);
-			if (null != directive) {
-				return directive.getCompletionProposals(offset, context);
-			}
-			else {
-				// we might be starting something
-				Item item = editor.getItemSet().getPreviousItem(offset);
-				int topOffset = 0;
-				if (null != item) topOffset = item.getRegion().getOffset() + item.getRegion().getLength();
-				// check for directives and macro calls
-				try {
-					for (int i=offset-1; i>=topOffset; i--) {
-						char c = editor.getDocument().getChar(i);
-						if (c == '>' || c == ']') break;
-						if (c == '<' || c == '[') {
-							if (editor.getDocument().getLength() > i) {
-								char c2 = editor.getDocument().getChar(i+1);
-								if (c2 == '#') {
-									CompletionDirective completionDirective = new CompletionDirective(
-											i, offset - i, editor.getItemSet(), (ISourceViewer) viewer, (IResource) editor.getFile());
-									completionDirective.setItemSet(editor.getItemSet());
-									return completionDirective.getCompletionProposals(offset, context);
-								}
-								else if (c2 == '@') {
-									CompletionMacroInstance completionMacroInstance = new CompletionMacroInstance(
-											editor.getDocument().get(i, offset - i), i, editor.getItemSet(), editor.getFile());
-									completionMacroInstance.setItemSet(editor.getItemSet());
-									return completionMacroInstance.getCompletionProposals(offset, context);
-								}
-								else if (c2 == '/') {
-									if (editor.getDocument().getLength() < i+3
-											|| editor.getDocument().getChar(i+2) == ' '
-												|| editor.getDocument().getChar(i+2) == '\r'
-													|| editor.getDocument().getChar(i+2) == '\n') {
-										Item stackItem = editor.getItemSet().getPreviousStartItem(offset);
-										StringBuffer value = new StringBuffer();
-										if (null != stackItem && stackItem instanceof MacroInstance)
-											value.append("@"); //$NON-NLS-1$
-										else
-											value.append("#"); //$NON-NLS-1$
-										String name = null;
-										if (null != stackItem) name = stackItem.getFirstToken();
-										if (null != name)
-											value.append(name);
-										if (c == '<')
-											value.append('>');
-										else 
-											value.append(']');
-										ICompletionProposal completionProposal = new CompletionProposal(
-												value.toString(), offset, 0, offset+value.toString().length());
-										return new ICompletionProposal[]{completionProposal};
-									}
-								}
-								else {
-									return NO_COMPLETIONS;
-								}
-							}
-						}
-					}
-				}
-				catch (BadLocationException e) {
-					return NO_COMPLETIONS;
-				}
-				// check for interpolations
-				try {
-					for (int i=offset-1; i>=topOffset; i--) {
-						char c = editor.getDocument().getChar(i);
-						if (c == '\n') break;
-						else if (c == '$') {
-							if (editor.getDocument().getLength() > i) {
-								char c2 = editor.getDocument().getChar(i+1);
-								if (c2 == '{') {
-									int j = offset;
-									while (editor.getDocument().getLength() > j) {
-										char c3 = editor.getDocument().getChar(j);
-										if (Character.isWhitespace(c3) || c3 == '(' || c3 == '.' || c3 == ')' || c3 == '}' || c3 == '?') {
-											// j = j-1;
-											break;
-										}
-										j++;
-									}
-									CompletionInterpolation interpolation = new CompletionInterpolation(
-											editor.getDocument().get(i, j - i), i, editor.getItemSet(), editor.getFile());
-									interpolation.setParentItem(editor.getItemSet().getPreviousStartItem(offset));
-									return interpolation.getCompletionProposals(offset, context);
-								}
-							}
-						}
-					}
-				}
-				catch (BadLocationException e) {
-					return NO_COMPLETIONS;
-				}
-			}
-		}
-		catch (Exception e) {
-			Plugin.log(e);
-		}
-		return NO_COMPLETIONS;
-	}
-
-	protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) {
-		return null;
-	}
-
-	protected Image getImage(Template template) {
-		return null;
-	}
-
-	protected Template[] getTemplates(String contextTypeId) {
-		return null;
-	}
-
-	public char[] getCompletionProposalAutoActivationCharacters() {
-		return new char[]{'.', '$', '#', '@', '/', '?', '{'};
-	}
-}
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/editor/MacroHyperlinkDetector.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/MacroHyperlinkDetector.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/editor/MacroHyperlinkDetector.java	(working copy)
@@ -31,14 +31,15 @@
 import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
 import org.jboss.ide.eclipse.freemarker.configuration.MacroLibrary;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
 import org.jboss.ide.eclipse.freemarker.model.Item;
 import org.jboss.ide.eclipse.freemarker.model.MacroDirective;
 import org.jboss.ide.eclipse.freemarker.model.MacroInstance;
 
 public class MacroHyperlinkDetector implements IHyperlinkDetector {
 
-	private Editor editor;
-	public MacroHyperlinkDetector(ITextViewer textViewer, Editor editor) {
+	private SourceEditor editor;
+	public MacroHyperlinkDetector(ITextViewer textViewer, SourceEditor editor) {
 		this.editor = editor;
 	}
 
Index: src/org/jboss/ide/eclipse/freemarker/editor/Editor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/Editor.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/editor/Editor.java	(working copy)
@@ -1,492 +0,0 @@
-/*
- * JBoss by Red Hat
- * Copyright 2006-2009, Red Hat Middleware, LLC, and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.ide.eclipse.freemarker.editor;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.jdt.internal.ui.javaeditor.JarEntryEditorInput;
-import org.eclipse.jdt.internal.ui.text.JavaPairMatcher;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.ITextViewer;
-import org.eclipse.jface.text.ITextViewerExtension2;
-import org.eclipse.jface.text.ITypedRegion;
-import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.text.source.MatchingCharacterPainter;
-import org.eclipse.jface.text.source.SourceViewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.StyleRange;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.KeyListener;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.MouseListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.editors.text.TextEditor;
-import org.eclipse.ui.texteditor.ContentAssistAction;
-import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
-import org.eclipse.ui.texteditor.MarkerUtilities;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
-import org.jboss.ide.eclipse.freemarker.Constants;
-import org.jboss.ide.eclipse.freemarker.Messages;
-import org.jboss.ide.eclipse.freemarker.Plugin;
-import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.model.Item;
-import org.jboss.ide.eclipse.freemarker.model.ItemSet;
-import org.jboss.ide.eclipse.freemarker.outline.OutlinePage;
-
-import freemarker.core.ParseException;
-import freemarker.template.Configuration;
-import freemarker.template.Template;
-
-/**
- * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
- */
-public class Editor extends TextEditor implements KeyListener, MouseListener {
-
-	private OutlinePage fOutlinePage;
-	private org.jboss.ide.eclipse.freemarker.editor.Configuration configuration;
-	private ColorManager colorManager = new ColorManager();
-
-	private ItemSet itemSet;
-	private Item selectedItem;
-	private Item[] relatedItems;
-	private static final char[] VALIDATION_TOKENS = new char[]{'\"', '[', ']', ',', '.', '\n', '4'};
-	private boolean readOnly = false;
-
-	private boolean mouseDown = false;
-	private boolean ctrlDown = false;
-	private boolean shiftDown = false;
-
-	public Editor() {
-		super();
-		configuration = new org.jboss.ide.eclipse.freemarker.editor.Configuration(getPreferenceStore(), colorManager, this);
-		setSourceViewerConfiguration(configuration);
-		setDocumentProvider(new DocumentProvider());
-	}
-	public void dispose() {
-		ConfigurationManager.getInstance(getProject()).reload();
-		super.dispose();
-		if(matchingCharacterPainter!=null) {
-			matchingCharacterPainter.dispose();
-		}
-	}
-
-	public Object getAdapter(Class aClass) {
-	    Object adapter;
-		if (aClass.equals(IContentOutlinePage.class)) {
-			if (fOutlinePage == null) {
-			    fOutlinePage = new OutlinePage(this);
-				if (getEditorInput() != null) {
-					fOutlinePage.setInput(getEditorInput());
-				}
-			}
-			adapter = fOutlinePage;
-		} else {
-		    adapter = super.getAdapter(aClass);
-		}
-		return adapter;
-	}
-
-	protected static final char[] BRACKETS= {'{', '}', '(', ')', '[', ']', '<', '>' };
-	private MatchingCharacterPainter matchingCharacterPainter;
-	public void createPartControl(Composite parent) {
-		super.createPartControl(parent);
-		 getSourceViewer().getTextWidget().addKeyListener(this);
-		 getSourceViewer().getTextWidget().addMouseListener(this);
-		 //matchingCharacterPainter = new MatchingCharacterPainter(
-			//	 getSourceViewer(),
-				// new JavaPairMatcher(BRACKETS));
-		//((SourceViewer) getSourceViewer()).addPainter(matchingCharacterPainter);
-	}
-
-	protected void createActions() {
-		super.createActions();
-		// Add content assist propsal action
-		ContentAssistAction action = new ContentAssistAction(
-				Plugin.getDefault().getResourceBundle(),
-				"FreemarkerEditor.ContentAssist", this); //$NON-NLS-1$
-		action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
-		setAction("FreemarkerEditor.ContentAssist", action); //$NON-NLS-1$
-		action.setEnabled(true);
-	}
-
-	protected void handleCursorPositionChanged() {
-		super.handleCursorPositionChanged();
-		if (!mouseDown) {
-			int offset = getCaretOffset();
-			Item item = getItemSet().getSelectedItem(offset);
-			if (null == item && offset > 0) item = getItemSet().getSelectedItem(offset-1);
-			if (Plugin.getInstance().getPreferenceStore().getBoolean(
-					Constants.HIGHLIGHT_RELATED_ITEMS)) {
-				if (null != item && null != item.getRelatedItems() && item.getRelatedItems().length > 0) {
-					highlightRelatedRegions(item.getRelatedItems(), item);
-				}
-				else {
-					highlightRelatedRegions(null, item);
-				}
-			}
-			if (null == item) {
-				item = getItemSet().getContextItem(getCaretOffset());
-			}
-			if (null != fOutlinePage)
-				fOutlinePage.update(item);
-		}
-	}
-	public void mouseDoubleClick(MouseEvent e) {
-	}
-	public void mouseDown(MouseEvent e) {
-		mouseDown = true;
-	}
-	public void mouseUp(MouseEvent e) {
-		mouseDown = false;
-		handleCursorPositionChanged();
-	}
-
-	public void select (Item item) {
-		selectAndReveal(item.getRegion().getOffset(), item.getRegion().getLength());
-	}
-
-	public IDocument getDocument() {
-		ISourceViewer viewer = getSourceViewer();
-		if (viewer != null) {
-			return viewer.getDocument();
-		}
-		return null;
-	}
-
-	public ITextViewer getTextViewer() {
-		return getSourceViewer();
-	}
-	
-	public void addProblemMarker(String aMessage, int aLine) {
-		IFile file = ((IFileEditorInput)getEditorInput()).getFile(); 
-		try {
-			Map attributes = new HashMap(5);
-			attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
-			attributes.put(IMarker.LINE_NUMBER, new Integer(aLine));
-			attributes.put(IMarker.MESSAGE, aMessage);
-			attributes.put(IMarker.TEXT, aMessage);
-			MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
-		} catch (Exception e) {
-			
-		}
-	}
-
-	private synchronized void highlightRelatedRegions (Item[] items, Item selectedItem) {
-		if (null == items || items.length == 0) {
-			if (null != relatedItems && relatedItems.length > 0) {
-				for (int i=0; i<relatedItems.length; i++) {
-					if (getDocument().getLength() >= relatedItems[i].getRegion().getOffset() + relatedItems[i].getRegion().getLength()) {
-						if (null == this.selectedItem || !relatedItems[i].equals(this.selectedItem))
-							resetRange(relatedItems[i].getRegion());
-					}
-				}
-			}
-			relatedItems = null;
-		}
-		if (null != relatedItems) {
-			for (int i=0; i<relatedItems.length; i++) {
-				if (getDocument().getLength() >= relatedItems[i].getRegion().getOffset() + relatedItems[i].getRegion().getLength()) {
-					if (null == this.selectedItem || !relatedItems[i].equals(this.selectedItem))
-						resetRange(relatedItems[i].getRegion());
-				}
-			}
-		}
-		if (null != items && items.length > 0) {
-			for (int i=0; i<items.length; i++) {
-				if (getDocument().getLength() >= items[i].getRegion().getOffset() + items[i].getRegion().getLength()
-						&& !items[i].equals(selectedItem)) {
-					ITypedRegion region = items[i].getRegion();
-					getSourceViewer().getTextWidget().setStyleRange(
-							new StyleRange(region.getOffset(),
-									region.getLength(), null, 
-									colorManager.getColor(
-											Constants.COLOR_RELATED_ITEM)));
-				}
-			}
-		}
-		relatedItems = items;
-		this.selectedItem = selectedItem;
-	}
-
-	private void resetRange (ITypedRegion region) {
-		if (getSourceViewer() instanceof ITextViewerExtension2)
-			((ITextViewerExtension2) getSourceViewer()).invalidateTextPresentation(region.getOffset(), region.getLength());
-		else
-			getSourceViewer().invalidateTextPresentation();
-	}
-
-	public Item getSelectedItem (boolean allowFudge) {
-		int caretOffset = getCaretOffset();
-		Item item = getItemSet().getSelectedItem(getCaretOffset());
-		if (null == item && caretOffset > 0) item = getItemSet().getSelectedItem(caretOffset - 1);
-		return item;
-	}
-
-	public Item getSelectedItem () {
-		return getItemSet().getSelectedItem(getCaretOffset());
-	}
-
-	public int getCaretOffset () {
-		return getSourceViewer().getTextWidget().getCaretOffset();
-	}
-
-	private void clearCache () {
-		this.itemSet = null;
-	}
-
-	public ItemSet getItemSet () {
-		if (null == this.itemSet) {
-			IResource resource = null;
-			if (getEditorInput() instanceof IFileEditorInput) {
-				resource = ((IFileEditorInput) getEditorInput()).getFile();
-			}
-			else if (getEditorInput() instanceof JarEntryEditorInput) {
-				resource = null;
-			}
-			
-			this.itemSet = new ItemSet(
-					getSourceViewer(), resource);
-		}
-		return this.itemSet;
-			
-	}
-	public OutlinePage getOutlinePage() {
-		return fOutlinePage;
-	}
-
-	public void keyPressed(KeyEvent e) {
-		if (e.keyCode == SWT.CTRL) {
-			ctrlDown = true;
-		}
-		if (e.keyCode == SWT.SHIFT) {
-			shiftDown = true;
-		}
-		if (e.keyCode == ']') {
-			try {
-				char c = getDocument().getChar(getCaretOffset());
-				if (c == ']') {
-					// remove this
-					getDocument().replace(getCaretOffset(), 1, ""); //$NON-NLS-1$
-				}
-			}
-			catch (BadLocationException e1) {}
-		}
-		else if (e.keyCode == '}') {
-			try {
-				char c = getDocument().getChar(getCaretOffset());
-				if (c == '}') {
-					// remove this
-					getDocument().replace(getCaretOffset(), 1, "}"); //$NON-NLS-1$
-				}
-			}
-			catch (BadLocationException e1) {}
-		}
-	}
-
-	public void keyReleased(KeyEvent e) {
-		if (e.keyCode == SWT.CTRL) {
-			ctrlDown = false;
-		}
-		else if (e.keyCode == SWT.SHIFT) {
-			shiftDown = false;
-		}
-		try {
-			if (shiftDown && (e.keyCode == '3' || e.keyCode == '2')) {
-				int offset = getCaretOffset();
-				char c = getSourceViewer().getDocument().getChar(offset-2);
-				if (c == '[' || c == '<') {
-					// directive
-					char endChar = Character.MIN_VALUE;
-					if (c == '[') endChar = ']'; else endChar = '>';
-					if (getSourceViewer().getDocument().getLength() > offset) {
-						if (offset > 0) {
-							for (int i=offset+1; i<getSourceViewer().getDocument().getLength(); i++) {
-								char c2 = getSourceViewer().getDocument().getChar(i);
-								if (i == endChar) return;
-								else if (i == '\n') break;
-							}
-							getSourceViewer().getDocument().replace(offset, 0, new String(new char[]{endChar}));
-						}
-					}
-					else {
-						getSourceViewer().getDocument().replace(offset, 0, new String(new char[]{endChar}));
-					}
-				}
-			}
-			else if (shiftDown && e.keyCode == '[') {
-				int offset = getCaretOffset();
-				char c = getSourceViewer().getDocument().getChar(offset-2);
-				if (c == '$') {
-					// interpolation
-					if (getSourceViewer().getDocument().getLength() > offset) {
-						if (offset > 0) {
-							for (int i=offset+1; i<getSourceViewer().getDocument().getLength(); i++) {
-								char c2 = getSourceViewer().getDocument().getChar(i);
-								if (i == '}') return;
-								else if (i == '\n') break;
-							}
-							getSourceViewer().getDocument().replace(offset, 0, "}"); //$NON-NLS-1$
-						}
-					}
-					else {
-						getSourceViewer().getDocument().replace(offset, 0, "}"); //$NON-NLS-1$
-					}
-				}
-			}
-		}
-		catch (BadLocationException exc) {
-			// do nothing
-		}
-
-		boolean stale = false;
-		if (e.keyCode == SWT.DEL || e.keyCode == SWT.BS) {
-			stale = true;
-		}
-		else if (null != getSelectedItem(true)) {
-			stale = true;
-		}
-		else {
-			char c = (char) e.keyCode;
-			for (int j=0; j<VALIDATION_TOKENS.length; j++) {
-				if (c == VALIDATION_TOKENS[j]) {
-					stale = true;
-					break;
-				}
-			}
-			if (ctrlDown && (e.keyCode == 'v' || e.keyCode == 'x')) {
-				stale = true;
-			}
-		}
-		if (stale) {
-			int offset = getCaretOffset();
-			Item item = getItemSet().getSelectedItem(offset);
-			if (null == item && offset > 0) item = getItemSet().getSelectedItem(offset-1);
-			if (Plugin.getInstance().getPreferenceStore().getBoolean(
-					Constants.HIGHLIGHT_RELATED_ITEMS)) {
-				if (null != item && null != item.getRelatedItems() && item.getRelatedItems().length > 0) {
-					highlightRelatedRegions(item.getRelatedItems(), item);
-				}
-				else {
-					highlightRelatedRegions(null, item);
-				}
-			}
-			clearCache();
-			validateContents();
-			if (null != fOutlinePage)
-				fOutlinePage.update(getSelectedItem());
-		}
-	}
-
-	public static Validator VALIDATOR;
-	public synchronized void validateContents () {
-		if (null == VALIDATOR) {
-			VALIDATOR = new Validator(this);
-			VALIDATOR.start();
-		}
-	}
-
-	public IProject getProject () {
-		return ((IFileEditorInput) getEditorInput()).getFile().getProject();
-	}
-
-	public IFile getFile () {
-		return (null != getEditorInput()) ? 
-				((IFileEditorInput) getEditorInput()).getFile() : null;
-	}
-
-	private Configuration fmConfiguration;
-	public class Validator extends Thread {
-		Editor editor;
-		public Validator (Editor editor) {
-			this.editor = editor;
-		}
-		public void run () {
-			try {
-				if (null != getFile()) {
-					if (null == fmConfiguration) {
-						fmConfiguration = new Configuration();
-						fmConfiguration.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX); 
-					}
-					getFile().deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
-					String pageContents = getDocument().get();
-					Reader reader = new StringReader(pageContents);
-					new Template(getFile().getName(), reader, fmConfiguration);
-					reader.close();
-				}
-			}
-			catch (ParseException e) {
-				if (e.getMessage() != null) {
-					String errorStr = e.getMessage();
-					int errorLine = 0;
-					try {
-						errorLine = e.getLineNumber();
-						if (errorLine == 0) {
-							// sometimes they forget to put it in
-							int index = e.getMessage().indexOf("line: "); //$NON-NLS-1$
-							if (index > 0) {
-								int index2 = e.getMessage().indexOf(" ", index+6); //$NON-NLS-1$
-								int index3 = e.getMessage().indexOf(",", index+6); //$NON-NLS-1$
-								if (index3 < index2 && index3 > 0) index2 = index3;
-								String s = e.getMessage().substring(index+6, index2);
-								try {
-									errorLine = Integer.parseInt(s);
-								}
-								catch (Exception e2) {}
-							}
-						}
-					} catch (NullPointerException npe) {
-						errorLine = 0;
-					}
-					editor.addProblemMarker(errorStr, errorLine);
-				}
-			}
-			catch (Exception e) {
-				Plugin.log(e);
-			}
-			finally {
-				editor.VALIDATOR = null;
-			}
-		}
-	}
-
-	protected void editorSaved() {
-		super.editorSaved();
-		validateContents();
-	}
-
-	public boolean isEditorInputReadOnly() {
-		return readOnly;
-	}
-	public void setReadOnly(boolean readOnly) {
-		this.readOnly = readOnly;
-	}
-}
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/editor/FreemarkerMultiPageEditor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/editor/FreemarkerMultiPageEditor.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/editor/FreemarkerMultiPageEditor.java	(working copy)
@@ -67,8 +67,11 @@
 import org.jboss.ide.eclipse.freemarker.Messages;
 import org.jboss.ide.eclipse.freemarker.Plugin;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
 import org.jboss.ide.eclipse.freemarker.dialogs.ContextValueDialog;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.PreviewEditor;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.PreviewEditorInput;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
 
 /**
  * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
@@ -77,7 +80,7 @@
 
 	public static final String ID = "org.jboss.ide.eclipse.freemarker.editor.FreemarkerEditor"; //$NON-NLS-1$
 	                                 
-    private Editor vEditor;
+    private SourceEditor vEditor;
     private String text;
     private boolean readOnly = false;
 
@@ -87,15 +90,20 @@
 
     protected void createPages()
     {
-        createPage0();
+        createSourcePage();
         if (!vEditor.isEditorInputReadOnly())
         	createContextPage();
+        createPreviewPage();
     }
 
-    void createPage0()
+    /**
+     * Create Source Page
+     *
+     */
+    void createSourcePage()
     {
         try {
-            vEditor = new Editor();
+            vEditor = new SourceEditor();
             vEditor.init(getEditorSite(), getEditorInput());
             if (readOnly) vEditor.setReadOnly(readOnly);
             int index = addPage(vEditor, getEditorInput());
@@ -107,7 +115,22 @@
         }
     }
 
-    public Editor getEditor () {
+    /**
+     * Create Preview Page
+     *
+     */
+    private void createPreviewPage() {
+        try {
+            int index = addPage(new PreviewEditor(), 
+                    new PreviewEditorInput(vEditor.getFile(), vEditor.getDocument()));
+            setPageText(index, "preview");
+         }
+        catch (PartInitException e) {
+            ErrorDialog.openError(getSite().getShell(), "Error creating nested Preview Editor", null, e.getStatus());
+        }
+    }
+    
+    public SourceEditor getEditor () {
     	return vEditor;
     }
 
@@ -204,11 +227,12 @@
 	public void reloadContextValues () {
 		try {
 			contextValuesTable.removeAll();
-			ContextValue[] values = ConfigurationManager.getInstance(
+			IContextValue[] values = ConfigurationManager.getInstance(
 					vEditor.getFile().getProject()).getContextValues(vEditor.getFile(), false);
 			for (int i=0; i<values.length; i++) {
-				TableItem item = new TableItem(contextValuesTable, SWT.NULL);
-				String[] arr = {values[i].name, values[i].objClass.getName()};
+                IContextValue contextValue = values[i];
+                TableItem item = new TableItem(contextValuesTable, SWT.NULL);
+                String[] arr = {contextValue.getName(),  contextValue.getFirstObjectContext().getName()};
 				item.setText(arr);
 			}
 			editContextValueButton.setEnabled(false);
@@ -254,7 +278,7 @@
 			int index = contextValuesTable.getSelectionIndex();
 			if (index >= 0) {
 				String key = contextValuesTable.getSelection()[0].getText(0);
-				ContextValue value = ConfigurationManager.getInstance(vEditor.getFile().getProject()).getContextValue(key, vEditor.getFile(), false);
+				IContextValue value = ConfigurationManager.getInstance(vEditor.getFile().getProject()).getContextValue(key, vEditor.getFile(), false);
 				ContextValueDialog dialog = new ContextValueDialog(new Shell(), value, vEditor.getFile());
 				if (IDialogConstants.OK_ID == dialog.open()) {
 					reloadContextValues();
@@ -282,8 +306,8 @@
 					boolean confirm = MessageDialog.openConfirm(new Shell(), Messages.FreemarkerMultiPageEditor_CONFIRMATION_TITLE, Messages.FreemarkerMultiPageEditor_CONFIRMATION_TO_DELETE_MESSAGE);
 					if (confirm) {
 						String key = contextValuesTable.getSelection()[0].getText(0);
-						ContextValue value = ConfigurationManager.getInstance(vEditor.getFile().getProject()).getContextValue(key, vEditor.getFile(), false);
-						ConfigurationManager.getInstance(vEditor.getFile().getProject()).removeContextValue(value.name, vEditor.getFile());
+						IContextValue value = ConfigurationManager.getInstance(vEditor.getFile().getProject()).getContextValue(key, vEditor.getFile(), false);
+						ConfigurationManager.getInstance(vEditor.getFile().getProject()).removeContextValue(value.getName(), vEditor.getFile());
 						reloadContextValues();
 					}
 				}
Index: src/org/jboss/ide/eclipse/freemarker/helper/ClassHelper.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/helper/ClassHelper.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/helper/ClassHelper.java	(revision 0)
@@ -0,0 +1,31 @@
+package org.jboss.ide.eclipse.freemarker.helper;
+
+/**
+ * 
+ * Class Helper 
+ *  
+ * @version 1.0.4 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class ClassHelper {
+
+    /**
+     * Return true if class test extends Class base and false otherwise
+     * @param test
+     * @param base
+     * @return
+     */
+    public static boolean instanceOf (Class test, Class base) {
+        if (null == test || null == base) return false;
+        while (null != test) {
+            for (int i=0; i<test.getInterfaces().length; i++) {
+                if (test.getInterfaces()[i].getClass().getName().equals(base.getName())) return true;
+            }
+            if (test.getName().equals(base.getName())) return true;
+            test = test.getSuperclass();
+        }
+        return false;
+    }
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalComparator.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalComparator.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalComparator.java	(revision 0)
@@ -0,0 +1,13 @@
+package org.jboss.ide.eclipse.freemarker.helper;
+
+import java.util.Comparator;
+
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+
+public class CompletionProposalComparator implements Comparator {
+    
+    public int compare(Object arg0, Object arg1) {
+        return ((ICompletionProposal) arg0).getDisplayString().compareTo(((ICompletionProposal) arg1).getDisplayString());
+    }
+}   
+
Index: src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalHelper.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalHelper.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/helper/CompletionProposalHelper.java	(revision 0)
@@ -0,0 +1,243 @@
+package org.jboss.ide.eclipse.freemarker.helper;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.jboss.ide.eclipse.freemarker.contentassist.SubCompletionProposal;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+public class CompletionProposalHelper {
+
+    public static ICompletionProposal[] completionProposals (List l) {
+        Collections.sort(l, new CompletionProposalComparator());
+        return (ICompletionProposal[]) l.toArray(new ICompletionProposal[l.size()]);
+    }
+    
+    public static ICompletionProposal[] getProposalsForParentObject (String content, int subOffset, int offset, Object parentObject, IResource file) {
+        if (ContextValueHelper.isClassContextValue(parentObject)) {
+            // Class context
+            Class parentClass = (Class)parentObject;
+            return completionProposals(
+                getMethodCompletionProposals (content, subOffset, offset, parentClass, file));
+        }
+        if (ContextValueHelper.isXMLContextValue(parentObject)) {
+            // XML context
+            Node parentNode = (Node)parentObject;
+            return completionProposals(
+                    getXMLChildrenCompletionProposals (content, subOffset, offset, parentNode, file));
+        }
+        /*if (ContextValueHelper.isDTDContextValue(parentObject)) {
+            // DTD context
+            return completionProposals(
+                    getDTDChildrenCompletionProposals (content, subOffset, offset, parentObject, file));
+        }*/
+        return null;
+    }
+    
+    /* -------------- Class context helper -------------*/
+    
+    private static List getMethodCompletionProposals (String content, int subOffset, int offset, Class parentClass, IResource file) {
+        if (ClassHelper.instanceOf(parentClass, String.class)
+                || ClassHelper.instanceOf(parentClass, Number.class)
+                || ClassHelper.instanceOf(parentClass, Date.class)
+                || ClassHelper.instanceOf(parentClass, Collection.class)
+                || ClassHelper.instanceOf(parentClass, List.class)
+                || ClassHelper.instanceOf(parentClass, Map.class))
+            return null;
+        String prefix = content.substring(1, subOffset);
+        List proposals = new ArrayList();
+        String pUpper = prefix.toUpperCase();
+        try {
+            BeanInfo bi = Introspector.getBeanInfo(parentClass);
+            PropertyDescriptor[] pds = bi.getPropertyDescriptors();
+            for (int i=0; i<pds.length; i++) {
+                PropertyDescriptor pd = pds[i];
+                String propertyName = pd.getName();
+                if (!propertyName.equals("class") && propertyName.toUpperCase().startsWith(pUpper)) {
+                    proposals.add(new CompletionProposal(
+                            propertyName,
+                            offset - subOffset + 1,
+                            content.length()-1,
+                            propertyName.length(),
+                            null, propertyName + " - " + pd.getReadMethod().getReturnType().getName(), null, null));
+                }
+            }
+            for (int i=0; i<parentClass.getMethods().length; i++) {
+                Method m = parentClass.getMethods()[i];
+                String mName = m.getName();
+                if (m.getParameterTypes().length > 0 && mName.startsWith("get") && mName.toUpperCase().startsWith(pUpper)) {
+                    StringBuffer display = new StringBuffer();
+                    display.append(mName);
+                    display.append("(");
+                    for (int j=0; j<m.getParameterTypes().length; j++) {
+                        if (j > 0) display.append(", ");
+                        display.append(m.getParameterTypes()[j].getName());
+                    }
+                    display.append(")");
+                    String actual = mName + "()";
+                    int tLength = actual.length();
+                    if (m.getParameterTypes().length > 0) tLength--;
+                    proposals.add(new CompletionProposal(actual,
+                            offset - subOffset + 1, content.length()-1, tLength,
+                            null, display.toString() + " - " + m.getReturnType().getName(), null, null));
+                }
+            }
+            return proposals;
+        }
+        catch (IntrospectionException e) {
+            return null;
+        }
+    }
+    
+    /* -------------- XML context helper -------------*/
+    
+    private static List getXMLChildrenCompletionProposals (String content, int subOffset, int offset, Node parentNode, IResource file) {
+        List proposals = new ArrayList();
+        try {
+            Element element = null;
+            if (parentNode instanceof Document) {
+                Document document = (Document)parentNode;
+                element = document.getDocumentElement();
+                String elementName = element.getNodeName();
+                proposals.add(getCompletionProposalForElement
+                        (content, subOffset, offset, elementName, "XML Root Element"));             
+            }
+            else {      
+                // Attribute 
+                NamedNodeMap attributes = parentNode.getAttributes();
+                int attributeLength = attributes.getLength();
+                for (int j = 0; j < attributeLength; j++) {
+                    Node attribute = attributes.item(j);
+                    String attributeName = attribute.getNodeName();
+                    attributeName = "@" + attributeName;
+                    proposals.add(new CompletionProposal(
+                            attributeName,
+                            offset - subOffset + 1,
+                            content.length()-1,
+                            attributeName.length(),
+                            null, attributeName + " - XML Attribute" , null, null));
+                }               
+                
+                //Element children
+                NodeList nodeList = parentNode.getChildNodes();
+                int length = nodeList.getLength();
+                Map elementsMap = new HashMap();
+                for (int i=0; i<length; i++) {
+                    Node currentNode = nodeList.item(i);
+                    if (Node.ELEMENT_NODE == currentNode.getNodeType()) {
+                        Element currentElement = (Element)currentNode;
+                        String elementName = currentElement.getNodeName();
+                        if (elementsMap.get(elementName) == null) {
+                            // Element must be added
+                            proposals.add(getCompletionProposalForElement
+                                    (content, subOffset, offset, elementName, "XML Element"));
+                            elementsMap.put(elementName, elementName);
+                   
+                        }
+                    }
+                }
+            }     
+            return proposals;
+        }
+        catch(Exception e) {
+            return null;
+        }
+    }
+    
+    private static ICompletionProposal getCompletionProposalForElement(String content, int subOffset, int offset, String elementName, String description) {
+        boolean removeLeftDot = false;
+        String replacementString = elementName;
+        int replacementOffset = offset - subOffset;
+        if (replacementString.indexOf("-") != -1) {
+            replacementString = "[\"" + replacementString + "\"]";
+            removeLeftDot = true;
+        } 
+        else {
+            replacementOffset++;
+        }
+        return new SubCompletionProposal(
+                replacementString,
+                replacementOffset,
+                content.length()-1,
+                replacementString.length(),
+                null, elementName + " - " + description , null, null, removeLeftDot);
+    }   
+    
+    /* -------------- DTD context helper -------------*/
+    
+    /*private static List getDTDChildrenCompletionProposals (String content, int subOffset, int offset, Object parentObject, IResource file) {
+        List proposals = new ArrayList();
+        try {
+            if (parentObject instanceof DocType) {
+                DocType docType = (DocType)parentObject;
+                for(Enumeration eleList = docType.getRootElements(); eleList.hasMoreElements();)
+                {
+                    String elementName = (String)eleList.nextElement();
+                    proposals.add(getCompletionProposalForElement
+                            (content, subOffset, offset, elementName, "DTD Root Element"));                                 
+                }   
+            }
+            else {      
+                ElementType parentElementType = (ElementType)parentObject; 
+                // Attribute 
+                String[] attributeNames = parentElementType.getAttributeNames();
+                if (attributeNames != null) {
+                    int attributeLength = attributeNames.length;
+                    for (int j = 0; j < attributeLength; j++) {
+                        String attributeName = attributeNames[j];
+                        attributeName = "@" + attributeName;
+                        proposals.add(new CompletionProposal(
+                                attributeName,
+                                offset - subOffset + 1,
+                                content.length()-1,
+                                attributeName.length(),
+                                null, attributeName + " - DTD Attribute" , null, null));
+                    }   
+                }
+                
+                //Element children
+                ElementType[] elementTypes  = parentElementType.getChildren();
+                if (elementTypes != null) {
+                    Map elementsMap = new HashMap();
+                    int length = elementTypes.length;
+                    for (int i=0; i<length; i++) {
+                        ElementType currentDTDElement = elementTypes[i];
+                        String elementName = currentDTDElement.getName();
+                        if (elementsMap.get(elementName) == null) {
+                            // Element must be added
+                            proposals.add(getCompletionProposalForElement
+                                    (content, subOffset, offset, elementName, "DTD Element"));
+                            elementsMap.put(elementName, elementName);
+                   
+                        }
+                    }
+                }
+                
+            }     
+            return proposals;
+        }
+        catch(Exception e) {
+            return null;
+        }
+    }
+    */
+}
Index: src/org/jboss/ide/eclipse/freemarker/helper/ContextValueHelper.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/helper/ContextValueHelper.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/helper/ContextValueHelper.java	(revision 0)
@@ -0,0 +1,198 @@
+package org.jboss.ide.eclipse.freemarker.helper;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.JavaModelException;
+import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
+import org.jboss.ide.eclipse.freemarker.configuration.context.ClassContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.XMLContextValue;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * 
+ * Helper for manage context value (Class, String, XML or DTD). 
+ * 
+ * @version 0.9.15
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class ContextValueHelper {
+    
+    /**
+     * Return true if objectContext is Class and false otherwise.
+     * @param objectContext
+     * @return
+     */
+    public static boolean isClassContextValue(Object objectContext) {
+        return (objectContext != null && 
+                objectContext instanceof Class);
+    }
+    
+    /**
+     * Return true if objectContext is String and false otherwise.
+     * @param objectContext
+     * @return
+     */ 
+    public static boolean isStringContextValue(Object objectContext) {
+        return (objectContext != null && 
+        objectContext instanceof java.lang.String);
+    }
+    
+    /**
+     * Return true if objectContext is XML and false otherwise.
+     * @param objectContext
+     * @return
+     */
+    public static boolean isXMLContextValue(Object objectContext) {
+        return (objectContext != null && objectContext instanceof Node);
+    }
+    
+    /**
+     * Return true if objectContext is DTD and false otherwise.
+     * @param objectContext
+     * @return
+     */
+    /*public static boolean isDTDContextValue(Object objectContext) {
+        return (objectContext != null && 
+            (objectContext instanceof ElementType ||
+             objectContext instanceof DocType));
+    }*/
+    
+    /**
+     * Return child Node Element of parentObject Node with name elementName.
+     * @param parentObject
+     * @param elementName
+     * @return
+     */
+    public static Node getChildNode(Object parentObject, String elementName) {
+        Node parentNode = (Node)parentObject;
+        if (parentNode.getNodeName().equals(elementName))
+            return parentNode;
+        NodeList nodeList = parentNode.getChildNodes();
+        int length = nodeList.getLength();
+        for (int i=0; i<length; i++) {
+            Node currentNode = nodeList.item(i);
+            if (Node.ELEMENT_NODE == currentNode.getNodeType()) {
+                Element currentElement = (Element)currentNode;
+                String currentElementName = currentElement.getNodeName();
+                if (elementName.equals(currentElementName)) {
+                    return currentElement;
+                }
+            }
+        }
+        return null;
+    }
+    
+    /*public static ElementType getChildDTDElement(Object parentObject, String elementName) {
+        if (parentObject instanceof DocType) {
+            DocType docType = (DocType)parentObject;
+            return docType.getElementType(elementName);
+        }
+        if (parentObject instanceof ElementType) {
+            ElementType elementType = (ElementType)parentObject;
+            
+            ElementType[] elementTypes  = elementType.getChildren();
+            if (elementTypes != null) {
+                int length = elementTypes.length;
+                for (int i=0; i<length; i++) {
+                    ElementType currentDTDElement = elementTypes[i];
+                    String currentElementName = currentDTDElement.getName();
+                    if (elementName.equals(currentElementName)) {
+                        return currentDTDElement;
+                    }
+                }
+            }
+        }
+        return null;
+    }*/
+    
+    
+    public static IContextValue getInstanceOfContextValue(ConfigurationManager configurationManager, 
+            int contextType,  String name, 
+            String context1, String context2) throws ClassNotFoundException, JavaModelException, 
+            ParserConfigurationException, SAXException, IOException, CoreException
+    {
+        if (contextType == IContextValue.CLASS) {
+            // Class context value
+            Class objectClass = null;
+            if (context1 != null && context1.length() > 0) {
+                context1 = context1.trim();
+                if (context1.length() > 0) {
+                    objectClass = configurationManager.
+                        getClass(context1);
+                }
+            }
+            if (objectClass == null)
+                return null;
+            Class singularClass = null;
+            if (context2 != null && context2.length() > 0) {
+                context2 = context2.trim();
+                if (context2.length() > 0) {
+                    singularClass = configurationManager.getClass(context2);
+                }
+            }             
+            return new ClassContextValue(name, objectClass, singularClass);
+        }
+        else {
+            if (contextType == IContextValue.STRING) {
+                // String context value
+                return null;
+                //return new StringContextValue(name, context1);
+            }
+            else {
+                if (contextType == IContextValue.XML) {
+                    // XML context value
+                    // 1. Get file ressource
+                    IFile file = configurationManager.getFile(context1);
+                    // 2. Load XML document
+                    Document document = DocumentBuilderFactory.newInstance().
+                        newDocumentBuilder().parse(file.getContents());
+                    return new XMLContextValue(name, context1, document);
+                }
+                else {
+                    /*if (contextType == IContextValue.DTD) {
+                        
+                        // DTD context value
+                        // 1. Get file ressource
+                        IFile file = configurationManager.getFile(context1);
+                        if (!file.exists()) {
+                            throw new FileNotFoundException(context1);
+                        }
+                        
+                        // 2. Load DTD DocType
+                        DTDSource dtdSource = new DTDFileInputStream(context1, file.getContents());
+                        DTDParser parser = new DTDParser();
+                        parser.parse(dtdSource);
+
+                        DocType doctype = parser.getDocType();
+                        return new DTDContextValue(name, context1, doctype);
+                    }*/
+                }
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Return true if content is start fragment and false otherwise.
+     * eg : if content=doc return true and 
+     * if content=doc.hibernate-mapping return false.
+     * @param content
+     * @return
+     */
+    public static boolean isStartFragment (String content) {
+        return !content.startsWith(".");
+    }    
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/ImageManager.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/ImageManager.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/ImageManager.java	(working copy)
@@ -21,6 +21,10 @@
  */
 package org.jboss.ide.eclipse.freemarker;
 
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.swt.graphics.Image;
 
 /**
@@ -38,4 +42,15 @@
 		return Plugin.getDefault().getImage(filename);
 	}
 	
+	public static ImageDescriptor getImageDescriptor(String filename) {
+		if (filename != null)  {
+			try {
+				URL url = new URL(Plugin.getInstance().getDescriptor().getInstallURL(),
+	                  "icons/" + filename);
+	                  return ImageDescriptor.createFromURL(url);
+			} catch (MalformedURLException mue) {
+			}
+		}
+		return null;
+	}
 }
\ No newline at end of file
Index: src/org/jboss/ide/eclipse/freemarker/contentassist/CompletionProcessor.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/contentassist/CompletionProcessor.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/contentassist/CompletionProcessor.java	(revision 0)
@@ -0,0 +1,295 @@
+/*
+ * JBoss, a division of Red Hat
+ * Copyright 2006, Red Hat Middleware, LLC, and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ide.eclipse.freemarker.contentassist;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.templates.Template;
+import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
+import org.eclipse.jface.text.templates.TemplateContext;
+import org.eclipse.jface.text.templates.TemplateContextType;
+import org.eclipse.jface.text.templates.TemplateException;
+import org.eclipse.swt.graphics.Image;
+import org.jboss.ide.eclipse.freemarker.Plugin;
+import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
+import org.jboss.ide.eclipse.freemarker.model.CompletionDirective;
+import org.jboss.ide.eclipse.freemarker.model.CompletionInterpolation;
+import org.jboss.ide.eclipse.freemarker.model.CompletionMacroInstance;
+import org.jboss.ide.eclipse.freemarker.model.Item;
+import org.jboss.ide.eclipse.freemarker.model.ItemSet;
+import org.jboss.ide.eclipse.freemarker.model.MacroInstance;
+import org.jboss.ide.eclipse.freemarker.template.FreemarkerTemplateContextType;
+import org.jboss.ide.eclipse.freemarker.template.FreemarkerTemplateProposal;
+
+/**
+ * @author <a href="mailto:joe@binamics.com">Joe Hudson</a>
+ */
+public class CompletionProcessor extends TemplateCompletionProcessor implements IContentAssistProcessor {
+
+	private SourceEditor editor;
+	
+	
+	public CompletionProcessor (SourceEditor editor) {
+		this.editor = editor;
+	}
+	
+	public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+        // Completion proposal for context
+        ICompletionProposal[] result = computeContextCompletionProposals(viewer, offset);
+        // Completion proposal for defined template
+        ICompletionProposal templates[] = templateComputeCompletionProposals(viewer, offset);
+        if(result == null)
+            return templates;
+        if(templates == null)
+        {
+            return result;
+        } else
+        {
+            ICompletionProposal all[] = new ICompletionProposal[result.length + templates.length];
+            System.arraycopy(templates, 0, all, 0, templates.length);
+            System.arraycopy(result, 0, all, templates.length, result.length);
+            return all;
+        }        
+	}
+
+    protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) {
+        return Plugin.getDefault().
+                    getContextTypeRegistry().
+                    getContextType(FreemarkerTemplateContextType.FREEMARKER_CONTEXT_TYPE);
+    }
+
+	protected Image getImage(Template template) {
+		return null;
+	}
+
+	public char[] getCompletionProposalAutoActivationCharacters() {
+		return new char[]{'.', '$', '#', '@', '/', '?', '{'};
+	}
+    
+    /**
+     * Completion proposal for context.
+     * @param viewer
+     * @param offset
+     * @return
+     */
+    private ICompletionProposal[] computeContextCompletionProposals(ITextViewer viewer, int offset) {
+        try {
+            ItemSet directiveSet = editor.getItemSet();
+    
+            Map context = new HashMap();
+            IContextValue[] values = ConfigurationManager.getInstance(editor.getProject()).getContextValues(editor.getFile(), true);
+            for (int i=0; i<values.length; i++) {
+                context.put(values[i].getName(), values[i].getFirstObjectContext().getObject());
+            }
+            
+            Item directive = directiveSet.getSelectedItem(offset);
+            if (null != directive) {
+                return directive.getCompletionProposals(offset, context);
+            }
+            else {
+                // we might be starting something
+                Item item = editor.getItemSet().getPreviousItem(offset);
+                int topOffset = 0;
+                if (null != item) topOffset = item.getRegion().getOffset() + item.getRegion().getLength();
+                // check for directives and macro calls
+                try {
+                    for (int i=offset-1; i>=topOffset; i--) {
+                        char c = editor.getDocument().getChar(i);
+                        if (c == '>' || c == ']') break;
+                        if (c == '<' || c == '[') {
+                            if (editor.getDocument().getLength() > i) {
+                                char c2 = editor.getDocument().getChar(i+1);
+                                if (c2 == '#') {
+                                    CompletionDirective completionDirective = new CompletionDirective(
+                                            i, offset - i, editor.getItemSet(), (ISourceViewer) viewer, (IResource) editor.getFile());
+                                    completionDirective.setItemSet(editor.getItemSet());
+                                    return completionDirective.getCompletionProposals(offset, context);
+                                }
+                                else if (c2 == '@') {
+                                    CompletionMacroInstance completionMacroInstance = new CompletionMacroInstance(
+                                            editor.getDocument().get(i, offset - i), i, editor.getItemSet(), editor.getFile());
+                                    completionMacroInstance.setItemSet(editor.getItemSet());
+                                    return completionMacroInstance.getCompletionProposals(offset, context);
+                                }
+                                else if (c2 == '/') {
+                                    if (editor.getDocument().getLength() < i+3
+                                            || editor.getDocument().getChar(i+2) == ' '
+                                                || editor.getDocument().getChar(i+2) == '\r'
+                                                    || editor.getDocument().getChar(i+2) == '\n') {
+                                        Item stackItem = editor.getItemSet().getPreviousStartItem(offset);
+                                        StringBuffer value = new StringBuffer();
+                                        if (null != stackItem && stackItem instanceof MacroInstance)
+                                            value.append("@");
+                                        else
+                                            value.append("#");
+                                        String name = null;
+                                        if (null != stackItem) name = stackItem.getFirstToken();
+                                        if (null != name)
+                                            value.append(name);
+                                        if (c == '<')
+                                            value.append('>');
+                                        else 
+                                            value.append(']');
+                                        ICompletionProposal completionProposal = new CompletionProposal(
+                                                value.toString(), offset, 0, offset+value.toString().length());
+                                        return new ICompletionProposal[]{completionProposal};
+                                    }
+                                }
+                                else {
+                                    return null;
+                                }
+                            }
+                        }
+                    }
+                }
+                catch (BadLocationException e) {
+                    return null;
+                }
+                // check for interpolations
+                try {
+                    for (int i=offset-1; i>=topOffset; i--) {
+                        char c = editor.getDocument().getChar(i);
+                        if (c == '\n') break;
+                        else if (c == '$') {
+                            if (editor.getDocument().getLength() > i) {
+                                char c2 = editor.getDocument().getChar(i+1);
+                                if (c2 == '{') {
+                                    int j = offset;
+                                    while (editor.getDocument().getLength() > j) {
+                                        char c3 = editor.getDocument().getChar(j);
+                                        if (Character.isWhitespace(c3) || c3 == '(' || c3 == '.' || c3 == ')' || c3 == '}' || c3 == '?') {
+                                            // j = j-1;
+                                            break;
+                                        }
+                                        j++;
+                                    }
+                                    CompletionInterpolation interpolation = new CompletionInterpolation(
+                                            editor.getDocument().get(i, j - i), i, editor.getItemSet(), editor.getFile());
+                                    interpolation.setParentItem(editor.getItemSet().getPreviousStartItem(offset));
+                                    return interpolation.getCompletionProposals(offset, context);
+                                }
+                            }
+                        }
+                    }
+                }
+                catch (BadLocationException e) {
+                    return null;
+                }
+            }
+        }
+        catch (Exception e) {
+            Plugin.log(e);
+        }
+        return null;        
+    }
+    
+    /**
+     * Completion proposal for defined template 
+     * @param viewer
+     * @param offset
+     * @return
+     */
+    private ICompletionProposal[] templateComputeCompletionProposals(ITextViewer viewer, int offset)
+    {
+        ITextSelection selection = (ITextSelection)viewer.getSelectionProvider().getSelection();
+        if(selection.getOffset() == offset)
+            offset = selection.getOffset() + selection.getLength();
+        String prefix = extractPrefix(viewer, offset);
+        if(prefix == null || prefix.length() < 1) 
+            return new ICompletionProposal[0];
+        String indent = ""; //extractIndent(viewer, offset - prefix.length());
+        Region region = new Region(offset - prefix.length(), prefix.length());
+        TemplateContext context = createContext(viewer, region);
+        if(context == null)
+            return new ICompletionProposal[0];
+        context.setVariable("selection", selection.getText());
+        Template templates[] = getTemplates(context.getContextType().getId());
+        if (templates == null)
+            return new ICompletionProposal[0];
+        List matches = new ArrayList();
+        for(int i = 0; i < templates.length; i++)
+        {
+            Template template = prepareTemplate(templates[i], indent);
+            try
+            {
+                context.getContextType().validate(template.getPattern());
+            }
+            catch(TemplateException _ex)
+            {
+                continue;
+            }
+            if(template.getName().startsWith(prefix))
+                matches.add(createFreemarkerProposal(template, context, region, getRelevance(template, prefix)));
+        }
+
+        return (ICompletionProposal[])matches.toArray(new ICompletionProposal[matches.size()]);
+    }   
+    
+    private Template prepareTemplate(Template template, String indent)
+    {
+        if(indent.length() == 0)
+            return template;
+        String newPattern = template.getPattern();
+        StringBuffer sb = new StringBuffer();
+        int i;
+        for(i = 0; i < newPattern.length() - 1; i++)
+        {
+            char c = newPattern.charAt(i);
+            char next = newPattern.charAt(i + 1);
+            if((c == '\n' || c == '\r') && next != '\n' && next != '\r')
+                sb.append(c).append(indent);
+            else
+                sb.append(c);
+        }
+
+        sb.append(newPattern.charAt(i));
+        newPattern = sb.toString();
+        Template t = new Template(template.getName(), template.getDescription(), template.getContextTypeId(), 
+                newPattern, template.isAutoInsertable());
+        return t;
+    }
+    
+    protected ICompletionProposal createFreemarkerProposal(Template template, TemplateContext context, IRegion region, int relevance)
+    {
+           return new FreemarkerTemplateProposal(editor, template, context, region, getImage(template), relevance);
+    }
+    
+    protected Template[] getTemplates(String contextTypeId) {
+        return Plugin.getDefault().getTemplateStore().getTemplates();
+    }
+}
Index: src/org/jboss/ide/eclipse/freemarker/contentassist/SubCompletionProposal.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/contentassist/SubCompletionProposal.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/contentassist/SubCompletionProposal.java	(revision 0)
@@ -0,0 +1,88 @@
+package org.jboss.ide.eclipse.freemarker.contentassist;
+
+import org.eclipse.jface.text.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+
+public class SubCompletionProposal implements ICompletionProposal {
+
+    private String fDisplayString;
+    private String fReplacementString;
+    private int fReplacementOffset;
+    private int fReplacementLength;
+    private int fCursorPosition;
+    private Image fImage;
+    private IContextInformation fContextInformation;
+    private String fAdditionalProposalInfo;
+    private boolean fRemoveLeftDot;
+    
+    public SubCompletionProposal(String replacementString, int replacementOffset, int replacementLength, int cursorPosition)
+    {
+        this(replacementString, replacementOffset, replacementLength, cursorPosition, null, null, null, null, false);
+    }
+
+    public SubCompletionProposal(String replacementString, int replacementOffset, 
+            int replacementLength, int cursorPosition, Image image, 
+            String displayString, IContextInformation contextInformation, 
+            String additionalProposalInfo, boolean removeLeftDot)
+    {
+        Assert.isNotNull(replacementString);
+        Assert.isTrue(replacementOffset >= 0);
+        Assert.isTrue(replacementLength >= 0);
+        Assert.isTrue(cursorPosition >= 0);
+        fReplacementString = replacementString;
+        fReplacementOffset = replacementOffset;
+        fReplacementLength = replacementLength;
+        fCursorPosition = cursorPosition;
+        fImage = image;
+        fDisplayString = displayString;
+        fContextInformation = contextInformation;
+        fAdditionalProposalInfo = additionalProposalInfo;
+        fRemoveLeftDot = removeLeftDot;
+    }
+
+    public void apply(IDocument document)
+    {
+        try
+        {   if (fRemoveLeftDot) {
+                String content = document.get(fReplacementOffset, 1);
+                if (content.equals("."))
+                    document.replace(fReplacementOffset, 1, "");
+            }
+            document.replace(fReplacementOffset, fReplacementLength, fReplacementString);
+        }
+        catch(BadLocationException _ex) { }
+    }
+
+    public Point getSelection(IDocument document)
+    {
+        return new Point(fReplacementOffset + fCursorPosition, 0);
+    }
+
+    public IContextInformation getContextInformation()
+    {
+        return fContextInformation;
+    }
+
+    public Image getImage()
+    {
+        return fImage;
+    }
+
+    public String getDisplayString()
+    {
+        if(fDisplayString != null)
+            return fDisplayString;
+        else
+            return fReplacementString;
+    }
+
+    public String getAdditionalProposalInfo()
+    {
+        return fAdditionalProposalInfo;
+    }
+}
Index: src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateContextType.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateContextType.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateContextType.java	(revision 0)
@@ -0,0 +1,34 @@
+package org.jboss.ide.eclipse.freemarker.template;
+
+import org.eclipse.jface.text.templates.TemplateContextType;
+
+/**
+ * 
+ * Set template context type for Freemarker Preference.
+ *  
+ * @version 1.0.4
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class FreemarkerTemplateContextType extends TemplateContextType
+{
+    public static final String FREEMARKER_CONTEXT_TYPE = "org.jboss.ide.eclipse.freemarker.template.context";
+     
+    public FreemarkerTemplateContextType()
+    {
+        addGlobalResolvers();
+    }
+
+    private void addGlobalResolvers()
+    {
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.Cursor());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.WordSelection());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.LineSelection());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.Dollar());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.Date());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.Year());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.Time());
+        addResolver(new org.eclipse.jface.text.templates.GlobalTemplateVariables.User());
+    }
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateProposal.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateProposal.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/template/FreemarkerTemplateProposal.java	(revision 0)
@@ -0,0 +1,42 @@
+package org.jboss.ide.eclipse.freemarker.template;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.templates.Template;
+import org.eclipse.jface.text.templates.TemplateContext;
+import org.eclipse.jface.text.templates.TemplateProposal;
+import org.eclipse.swt.graphics.Image;
+import org.jboss.ide.eclipse.freemarker.editor.editorpart.SourceEditor;
+
+/**
+ * 
+ * Template proposal for Freemarker. 
+ * 
+ * @version 1.0.4
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class FreemarkerTemplateProposal extends TemplateProposal{
+
+    private SourceEditor sourceEditor;
+    
+    public FreemarkerTemplateProposal(SourceEditor sourceEditor, 
+            Template arg0, TemplateContext arg1, IRegion arg2, Image arg3, int arg4) {
+        super(arg0, arg1, arg2, arg3, arg4);
+        this.sourceEditor = sourceEditor;
+        
+    }
+
+    public FreemarkerTemplateProposal(SourceEditor sourceEditor, 
+            Template arg0, TemplateContext arg1, IRegion arg2, Image arg3) {
+        super(arg0, arg1, arg2, arg3);
+        this.sourceEditor = sourceEditor;
+        
+    }
+
+    public void apply(ITextViewer viewer, char arg1, int arg2, int arg3) {
+        super.apply(viewer, arg1, arg2, arg3);
+        sourceEditor.clearCache();
+    }
+
+}
Index: src/org/jboss/ide/eclipse/freemarker/preferences/FreemarkerTemplatePreferencePage.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/preferences/FreemarkerTemplatePreferencePage.java	(revision 0)
+++ src/org/jboss/ide/eclipse/freemarker/preferences/FreemarkerTemplatePreferencePage.java	(revision 0)
@@ -0,0 +1,36 @@
+package org.jboss.ide.eclipse.freemarker.preferences;
+
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.texteditor.templates.TemplatePreferencePage;
+import org.jboss.ide.eclipse.freemarker.Plugin;
+
+/**
+ * 
+ * Manage Freemarker Template. 
+ * @version 1.0.0 
+ * @author <a href="mailto:angelo.zerr@gmail.com">Angelo ZERR</a>
+ *
+ */
+public class FreemarkerTemplatePreferencePage extends TemplatePreferencePage
+    implements IWorkbenchPreferencePage
+{
+
+    public FreemarkerTemplatePreferencePage()
+    {
+        setPreferenceStore(Plugin.getDefault().getPreferenceStore());
+        setTemplateStore(Plugin.getDefault().getTemplateStore());
+        setContextTypeRegistry(Plugin.getDefault().getContextTypeRegistry());
+    }
+
+    protected boolean isShowFormatterSetting()
+    {
+        return false;
+    }
+
+    public boolean performOk()
+    {
+        boolean ok = super.performOk();
+        Plugin.getDefault().savePluginPreferences();
+        return ok;
+    }
+}
Index: src/org/jboss/ide/eclipse/freemarker/preferences/ContextProperties.java
===================================================================
--- src/org/jboss/ide/eclipse/freemarker/preferences/ContextProperties.java	(revision 33273)
+++ src/org/jboss/ide/eclipse/freemarker/preferences/ContextProperties.java	(working copy)
@@ -51,7 +51,7 @@
 import org.jboss.ide.eclipse.freemarker.Messages;
 import org.jboss.ide.eclipse.freemarker.Plugin;
 import org.jboss.ide.eclipse.freemarker.configuration.ConfigurationManager;
-import org.jboss.ide.eclipse.freemarker.configuration.ContextValue;
+import org.jboss.ide.eclipse.freemarker.configuration.context.IContextValue;
 import org.jboss.ide.eclipse.freemarker.dialogs.ContextValueDialog;
 
 public class ContextProperties extends PropertyPage {
@@ -171,11 +171,12 @@
     public void reloadContextValues() {
         try {
             contextValuesTable.removeAll();
-            ContextValue[] values = ConfigurationManager.getInstance(getResource().getProject())
+            IContextValue[] values = ConfigurationManager.getInstance(getResource().getProject())
                     .getContextValues(getResource(), false);
             for (int i = 0; i < values.length; i++) {
                 TableItem item = new TableItem(contextValuesTable, SWT.NULL);
-                String[] arr = { values[i].name, values[i].objClass.getName() };
+                IContextValue contextValue = values[i];
+                String[] arr = { contextValue.getName(), contextValue.getFirstObjectContext().getName() };
                 item.setText(arr);
             }
             editContextValueButton.setEnabled(false);
@@ -236,7 +237,7 @@
             int index = contextValuesTable.getSelectionIndex();
             if (index >= 0) {
                 String key = contextValuesTable.getSelection()[0].getText(0);
-                ContextValue value = ConfigurationManager.getInstance(getResource().getProject()).getContextValue(key,
+                IContextValue value = ConfigurationManager.getInstance(getResource().getProject()).getContextValue(key,
                         getResource(), false);
                 ContextValueDialog dialog = new ContextValueDialog(new Shell(),
                         value, getResource());
@@ -275,9 +276,9 @@
                     if (confirm) {
                         String key = contextValuesTable.getSelection()[0]
                                 .getText(0);
-                        ContextValue value = ConfigurationManager.getInstance(getResource().getProject())
+                        IContextValue contextValue = ConfigurationManager.getInstance(getResource().getProject())
                                 .getContextValue(key, getResource(), false);
-                        ConfigurationManager.getInstance(getResource().getProject()).removeContextValue(value.name,
+                        ConfigurationManager.getInstance(getResource().getProject()).removeContextValue(contextValue.getName(),
                                 getResource());
                         reloadContextValues();
                     }
Index: plugin.properties
===================================================================
--- plugin.properties	(revision 33273)
+++ plugin.properties	(working copy)
@@ -2,3 +2,10 @@
 providerName = JBoss by Red Hat
 PreferencePage_FreeMarkerEditor=FreeMarker Editor
 PropertyPage_FreeMarkerContext=FreeMarker Context
+
+freemarker.library=Use as FreeMarker library
+freemarker.templates=Freemarker Templates
+freemarker.template.type=Freemarker
+
+# preferencePages
+freemarker.preferencePages.templates=Templates
