Update Trinidad Tag Support:
 - tag conversion for tr:image, tr:panelGroupLayout, and tr:group

Enhance DTTagConverter:
 - allow a single source Node to have multiple ConvertPositions (necessary for tag conversion of many Trinidad tags, but not Trinidad-specific)
diff --git a/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/metadata/trinidad_dti.xml b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/metadata/trinidad_dti.xml
index 62c1144..511183d 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/metadata/trinidad_dti.xml
+++ b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/metadata/trinidad_dti.xml
@@ -328,6 +328,22 @@
 		</trait>
 	</entity>
 
+	<entity id="group" type="tag">
+		<trait id="dt-info">
+			<value xsi:type="dti:DTInfo">
+				<tag-convert-info>
+					<operation id="org.eclipse.jst.pagedesigner.CreateElementOperation">
+						<parameter value="span"/>
+					</operation>
+					<operation id="org.eclipse.jst.pagedesigner.CopyChildrenOperation"/>
+				</tag-convert-info>
+				<tag-decorate-info id="vpd-decorate-design"
+					needBorderDecorator="true"					
+				/>
+			</value>
+		</trait>
+	</entity>
+
 	<entity id="icon" type="tag">
 		<trait id="dt-info">
 			<value xsi:type="dti:DTInfo">
@@ -395,6 +411,35 @@
 		</trait>
 	</entity>
 
+	<entity id="image" type="tag">
+		<trait id="dt-info">
+			<value xsi:type="dti:DTInfo">
+				<tag-convert-info>
+					<operation id="org.eclipse.jst.pagedesigner.CreateElementOperation">
+						<parameter value="img"/>
+					</operation>
+					<operation id="org.eclipse.jst.pagedesigner.CopyAttributeWithRenameOperation">
+						<parameter value="styleClass"/>
+						<parameter value="class"/>
+					</operation>
+					<operation id="org.eclipse.jst.jsf.apache.trinidad.tagsupport.CreateStyleAttributeOperation"/>
+					<operation id="org.eclipse.jst.pagedesigner.CopyAttributeWithRenameOperation">
+						<parameter value="source"/>
+						<parameter value="src"/>
+					</operation>
+				</tag-convert-info>
+				<tag-decorate-info id="vpd-decorate-design"
+					widget="true"
+				>
+					<resolve-attribute-value attributeName="src"/>
+				</tag-decorate-info>
+				<tag-decorate-info id="vpd-decorate-preview">
+					<resolve-attribute-value attributeName="src"/>
+				</tag-decorate-info>
+			</value>
+		</trait>
+	</entity>
+
 	<entity id="inputText" type="tag">
 		<trait id="dt-info">
 			<value xsi:type="dti:DTInfo">
@@ -536,6 +581,20 @@
 		</trait>
 	</entity>
 
+	<entity id="panelGroupLayout" type="tag">
+		<trait id="dt-info">
+			<value xsi:type="dti:DTInfo">
+				<tag-convert-info>
+					<operation id="org.eclipse.jst.jsf.apache.trinidad.tagsupport.PanelGroupLayoutOperation"/>
+				</tag-convert-info>
+				<tag-decorate-info id="vpd-decorate-design"
+					multiLevel="true"
+					needBorderDecorator="true"
+				/>
+			</value>
+		</trait>
+	</entity>
+
 	<entity id="panelTabbed" type="tag">
 		<trait id="dt-info">
 			<value xsi:type="dti:DTInfo">
diff --git a/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/plugin.xml b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/plugin.xml
index e62f260..391105d 100644
--- a/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/plugin.xml
+++ b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/plugin.xml
@@ -42,6 +42,14 @@
             id="InputTextOperation">
       </tagTransformOperation>
       <tagTransformOperation
+            class="org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations.OutputFormattedOperation"
+            id="OutputFormattedOperation">
+      </tagTransformOperation>
+      <tagTransformOperation
+            class="org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations.PanelGroupLayoutOperation"
+            id="PanelGroupLayoutOperation">
+      </tagTransformOperation>
+      <tagTransformOperation
             class="org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations.PanelTabbedOperation"
             id="PanelTabbedOperation">
       </tagTransformOperation>
@@ -49,10 +57,6 @@
             class="org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations.ShowDetailItemOperation"
             id="ShowDetailItemOperation">
       </tagTransformOperation>
-      <tagTransformOperation
-            class="org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations.OutputFormattedOperation"
-            id="OutputFormattedOperation">
-      </tagTransformOperation>
    </extension>
    <extension
          point="org.eclipse.jst.jsf.core.variableresolver">
diff --git a/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/src/org/eclipse/jst/jsf/apache/trinidad/tagsupport/converter/operations/PanelGroupLayoutOperation.java b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/src/org/eclipse/jst/jsf/apache/trinidad/tagsupport/converter/operations/PanelGroupLayoutOperation.java
new file mode 100644
index 0000000..cc303c7
--- /dev/null
+++ b/jsf/plugins/org.eclipse.jst.jsf.apache.trinidad.tagsupport/src/org/eclipse/jst/jsf/apache/trinidad/tagsupport/converter/operations/PanelGroupLayoutOperation.java
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2008 Oracle Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Oracle Corporation - initial API and implementation
+ */
+package org.eclipse.jst.jsf.apache.trinidad.tagsupport.converter.operations;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jst.jsf.core.internal.tld.IJSFConstants;
+import org.eclipse.jst.jsf.core.internal.tld.TagIdentifierFactory;
+import org.eclipse.jst.pagedesigner.converter.ConvertPosition;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * ITransformOperation implementation specifically for the "panelGroupLayout"
+ * JSF Element.
+ * 
+ * <br><b>Note:</b> requires ITransformOperation.setTagConverterContext(...) to
+ * have been called to provide a valid ITagConverterContext instance prior to
+ * a call to the transform(...) method.
+ * 
+ * @author Ian Trimble - Oracle
+ */
+public class PanelGroupLayoutOperation extends AbstractTrinidadTransformOperation {
+
+	private static final int LAYOUT_DEFAULT = 0;
+	private static final int LAYOUT_HORIZONTAL = 1;
+	private static final int LAYOUT_VERTICAL = 2;
+
+	/* (non-Javadoc)
+	 * @see org.eclipse.jst.pagedesigner.dtmanager.converter.operations.AbstractTransformOperation#transform(org.w3c.dom.Element, org.w3c.dom.Element)
+	 */
+	@Override
+	public Element transform(Element srcElement, Element curElement) {
+		Element outerElement;
+
+		//create outer element and set element-specific attributes
+		final int layout = getLayout(srcElement);
+		Element containerElement;
+		switch (layout) {
+		case LAYOUT_HORIZONTAL:
+			outerElement = createElement("table"); //$NON-NLS-1$
+			outerElement.setAttribute("cellpadding", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+			outerElement.setAttribute("cellspacing", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+			outerElement.setAttribute("border", "0"); //$NON-NLS-1$ //$NON-NLS-2$
+			containerElement = appendChildElement("tr", outerElement); //$NON-NLS-1$
+			break;
+		case LAYOUT_VERTICAL:
+			outerElement = createElement("div"); //$NON-NLS-1$
+			containerElement = outerElement;
+			break;
+		default:
+			outerElement = createElement("span"); //$NON-NLS-1$
+			containerElement = outerElement;
+			break;
+		}
+
+		//set common attributes on outer element
+		final String styleClass = srcElement.getAttribute("styleClass"); //$NON-NLS-1$
+		if (styleClass != null && styleClass.length() > 0) {
+			outerElement.setAttribute("class", styleClass); //$NON-NLS-1$
+		}
+		final String inlineStyle = srcElement.getAttribute("inlineStyle"); //$NON-NLS-1$
+		if (inlineStyle != null && inlineStyle.length() > 0) {
+			outerElement.setAttribute("style", inlineStyle); //$NON-NLS-1$
+		}
+
+		//get child nodes, skipping "facet" elements and empty Text nodes
+		List<Node> childNodes = new ArrayList<Node>();
+		Iterator<Node> itCopyChildrenNodes = getCopyChildrenNodes(srcElement).iterator();
+		while (itCopyChildrenNodes.hasNext()) {
+			Node copyChildrenNode = itCopyChildrenNodes.next();
+			if (!(copyChildrenNode instanceof Element && TagIdentifierFactory.createDocumentTagWrapper((Element)copyChildrenNode).isSameTagType(IJSFConstants.TAG_IDENTIFIER_FACET))) {
+				if (!(copyChildrenNode instanceof Text && copyChildrenNode.getNodeValue().trim().length() < 1)) {
+					childNodes.add(copyChildrenNode);
+				}
+			}
+		}
+
+		//get "separator" facet's first child Element (only one used at runtime)
+		Element separatorElement = null;
+		final Element facetElement = getChildFacetByName(srcElement, "separator"); //$NON-NLS-1$
+		if (facetElement != null) {
+			NodeList facetChildNodes = facetElement.getChildNodes();
+			for (int i = 0; i < facetChildNodes.getLength(); i++) {
+				Node curChildNode = facetChildNodes.item(i);
+				if (curChildNode instanceof Element) {
+					separatorElement = (Element)curChildNode;
+					break;
+				}
+			}
+		}
+
+		//iterate over child nodes, interspersing separator(s) as required
+		int curChildNodeIndex = 0;
+		int curIndex = 0;
+		Iterator<Node> itChildNodes = childNodes.iterator();
+		switch (layout) {
+		case LAYOUT_HORIZONTAL:
+			while (itChildNodes.hasNext()) {
+				final Element childTDElement = appendChildElement("td", containerElement); //$NON-NLS-1$
+				tagConverterContext.addChild(itChildNodes.next(), new ConvertPosition(childTDElement, 0));
+				if (++curChildNodeIndex < childNodes.size()) {
+					if (separatorElement != null) {
+						final Element sepTDElement = appendChildElement("td", containerElement); //$NON-NLS-1$
+						tagConverterContext.addChild(separatorElement, new ConvertPosition(sepTDElement, 0));
+					}
+				}
+			}
+			break;
+		case LAYOUT_VERTICAL:
+			while (itChildNodes.hasNext()) {
+				tagConverterContext.addChild(itChildNodes.next(), new ConvertPosition(containerElement, curIndex++));
+				if (++curChildNodeIndex < childNodes.size()) {
+					final Element divElement = appendChildElement("div", containerElement); //$NON-NLS-1$
+					curIndex++;
+					if (separatorElement != null) {
+						tagConverterContext.addChild(separatorElement, new ConvertPosition(divElement, 0));
+					}
+				}
+			}
+			break;
+		default:
+			while (itChildNodes.hasNext()) {
+				tagConverterContext.addChild(itChildNodes.next(), new ConvertPosition(containerElement, curIndex++));
+				if (++curChildNodeIndex < childNodes.size()) {
+					if (separatorElement != null) {
+						tagConverterContext.addChild(separatorElement, new ConvertPosition(containerElement, curIndex++));
+					}
+				}
+			}
+			break;
+		}
+
+		return outerElement;
+	}
+
+	private int getLayout(Element srcElement) {
+		int layout = LAYOUT_DEFAULT;
+		if (srcElement != null) {
+			String layoutValue = srcElement.getAttribute("layout"); //$NON-NLS-1$
+			if (layoutValue != null) {
+				if (layoutValue.equals("horizontal")) { //$NON-NLS-1$
+					layout = LAYOUT_HORIZONTAL;
+				} else if (layoutValue.equals("vertical")) { //$NON-NLS-1$
+					layout = LAYOUT_VERTICAL;
+				}
+			}
+		}
+		return layout;
+	}
+
+}
diff --git a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/dtmanager/converter/internal/DTTagConverter.java b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/dtmanager/converter/internal/DTTagConverter.java
index a5cb784..6beb185 100644
--- a/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/dtmanager/converter/internal/DTTagConverter.java
+++ b/jsf/plugins/org.eclipse.jst.pagedesigner/src/org/eclipse/jst/pagedesigner/dtmanager/converter/internal/DTTagConverter.java
@@ -44,7 +44,7 @@
 	private ImageDescriptor visualImageDescriptor;
 	private IDOMDocument destDocument;
 	private List childNodeList = Collections.EMPTY_LIST;
-	private Map childVisualPositionMap = Collections.EMPTY_MAP;
+	private NodeConvertPositionMap childVisualPositionMap;
 	private List nonVisualChildElementList = Collections.EMPTY_LIST;
 	private boolean isMultiLevel = false;
 	private boolean isVisualByHTML = true;
@@ -69,7 +69,7 @@
 	 */
 	public void convertRefresh(Object context) {
 		childNodeList = new ArrayList();
-		childVisualPositionMap = new HashMap();
+		childVisualPositionMap = new NodeConvertPositionMap();
 		nonVisualChildElementList = new ArrayList();
 		resultElement = new DTHTMLOutputRenderer().render(new DTTagConverterContext(this));
 		new DTTagConverterDecorator().decorate(this);
@@ -91,6 +91,8 @@
 	 * @see org.eclipse.jst.pagedesigner.converter.ITagConverter#getChildModeList()
 	 */
 	public List getChildModeList() {
+		//need to reset the NodeConvertPositionMap at this time
+		childVisualPositionMap.reset();
 		return childNodeList;
 	}
 
@@ -98,7 +100,7 @@
 	 * @see org.eclipse.jst.pagedesigner.converter.ITagConverter#getChildVisualPosition(org.w3c.dom.Node)
 	 */
 	public ConvertPosition getChildVisualPosition(Node childModel) {
-		return (ConvertPosition)childVisualPositionMap.get(childModel);
+		return childVisualPositionMap.get(childModel);
 	}
 
 	/* (non-Javadoc)
@@ -397,4 +399,70 @@
 		nonVisualChildElementList.add(childElement);
 	}
 
+	/**
+	 * Supports multiple ConvertPosition instances associated with a single
+	 * Node instance.
+	 */
+	private class NodeConvertPositionMap {
+
+		private Map mapOfConvertPositions = new HashMap();
+		private Map mapOfIndexes = new HashMap();
+
+		/**
+		 * Puts a ConvertPosition instance for the specified Node instance into
+		 * the map.
+		 * 
+		 * @param node Node instance for which the ConvertPosition is to be
+		 * applied.
+		 * @param convertPosition ConvertPosition instance for the specified
+		 * Node instance.
+		 */
+		public void put(Node node, ConvertPosition convertPosition) {
+			List convertPositions = (List)mapOfConvertPositions.get(node);
+			if (convertPositions == null) {
+				convertPositions = new ArrayList();
+				mapOfConvertPositions.put(node, convertPositions);
+			}
+			convertPositions.add(convertPosition);
+		}
+
+		/**
+		 * Gets the current ConvertPosition instance for the specified Node
+		 * instance. Note that each time this is called without a reset having
+		 * occurred, the next ConvertPosition instance mapped to the Node
+		 * instance is returned.
+		 * 
+		 * @param node Node instance for which a ConvertPosition instance is
+		 * being requested.
+		 * @return the current ConvertPosition instance for the specified Node
+		 * instance.
+		 */
+		public ConvertPosition get(Node node) {
+			ConvertPosition convertPosition = null;
+			List convertPositions = (List)mapOfConvertPositions.get(node);
+			if (convertPositions != null) {
+				int index;
+				Object obj = mapOfIndexes.get(node);
+				if (obj != null) {
+					index = ((Integer)obj).intValue();
+				} else {
+					index = 0;
+				}
+				convertPosition = (ConvertPosition)convertPositions.get(index);
+				mapOfIndexes.put(node, new Integer(++index));
+			}
+			return convertPosition;
+		}
+
+		/**
+		 * Resets the concept of "current" ConvertPosition instance for all
+		 * Node instances. Typically called when the List of child Nodes is
+		 * retrieved.
+		 */
+		public void reset() {
+			mapOfIndexes.clear();
+		}
+
+	}
+
 }