[271844] XML editor's design page should use table columns for a more native feel
diff --git a/bundles/org.eclipse.wst.xml.ui/plugin.xml b/bundles/org.eclipse.wst.xml.ui/plugin.xml
index d9fc7ff..db478c8 100644
--- a/bundles/org.eclipse.wst.xml.ui/plugin.xml
+++ b/bundles/org.eclipse.wst.xml.ui/plugin.xml
@@ -992,34 +992,6 @@
 	              </reference>
 	           </visibleWhen>
            </command>
-           <separator
-                 name="sed.tabletree.separator.2"
-                 visible="true">
-           </separator>
-           <command
-                 commandId="sed.tabletree.expandAll"
-                 icon="icons/full/etool16/expand_all.gif"
-                 id="ExpandAll"
-                 style="push">
-	           <visibleWhen
-	                 checkEnabled="false">
-	              <reference
-	                    definitionId="org.eclipse.wst.xml.ui.expand">
-	              </reference>
-	           </visibleWhen>
-           </command>
-           <command
-                 commandId="sed.tabletree.collapseAll"
-                 icon="icons/full/etool16/collapse_all.gif"
-                 id="CollapseAll"
-                 style="push">
-	             <visibleWhen
-	                 checkEnabled="false">
-	              <reference
-	                    definitionId="org.eclipse.wst.xml.ui.expand">
-	              </reference>
-	           </visibleWhen>
-           </command>
         </toolbar>
      </menuContribution>
      
diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorMessages.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorMessages.java
index c0471bf..4fbac12 100644
--- a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorMessages.java
+++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * Copyright (c) 2005, 2009 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,6 +21,8 @@
 	private static final String BUNDLE_NAME = "org.eclipse.wst.xml.ui.internal.tabletree.XMLEditorResources";//$NON-NLS-1$
 
 	public static String XMLTableTreeViewer_0;
+	public static String XMLTableTreeViewer_1;
+	public static String XMLTableTreeViewer_2;
 	public static String XMLMultiPageEditorPart_0;
 	public static String XMLTreeExtension_0;
 	public static String XMLTreeExtension_1;
diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorResources.properties b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorResources.properties
index 2fc1735..1943b11 100644
--- a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorResources.properties
+++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLEditorResources.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2004, 2005 IBM Corporation and others.
+# Copyright (c) 2004, 2009 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -9,6 +9,8 @@
 #     IBM Corporation - initial API and implementation
 ###############################################################################
 XMLTableTreeViewer_0=Design
+XMLTableTreeViewer_1=Node
+XMLTableTreeViewer_2=Content
 XMLMultiPageEditorPart_0=Source
 XMLTreeExtension_0=Structure
 XMLTreeExtension_1=Value
diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLMultiPageEditorPart.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLMultiPageEditorPart.java
index a3578cd..b1fed5c 100644
--- a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLMultiPageEditorPart.java
+++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLMultiPageEditorPart.java
@@ -17,10 +17,12 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextInputListener;
 import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
@@ -30,9 +32,13 @@
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.ui.IEditorActionBarContributor;
@@ -586,15 +592,42 @@
 		// note: By adding the design page as a Control instead of an
 		// IEditorPart, page switches will indicate
 		// a "null" active editor when the design page is made active
-		fDesignPageIndex = addPage(designViewer.getControl());
+		fDesignPageIndex = addPage(designViewer.getControl().getParent());
 		setPageText(fDesignPageIndex, designViewer.getTitle());
 	}
 
 	protected IDesignViewer createDesignPage() {
-		XMLTableTreeViewer tableTreeViewer = new XMLTableTreeViewer(getContainer());
+		Composite container = new Composite(getContainer(), SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.verticalSpacing = 0;
+		layout.marginWidth = 0;
+		container.setLayout(layout);
+
+		ToolBar tb = new ToolBar(container, SWT.FLAT);
+
+		ToolBarManager manager = new ToolBarManager(tb);
+		tb.setLayoutData(new GridData(GridData.END, GridData.VERTICAL_ALIGN_BEGINNING, true, false));
+
+		IDesignViewer designViewer = new XMLTableTreeViewer(container);
+		designViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
 		// Set the default infopop for XML design viewer.
-		XMLUIPlugin.getInstance().getWorkbench().getHelpSystem().setHelp(tableTreeViewer.getControl(), XMLTableTreeHelpContextIds.XML_DESIGN_VIEW_HELPID);
-		return tableTreeViewer;
+		XMLUIPlugin.getInstance().getWorkbench().getHelpSystem().setHelp(designViewer.getControl(), XMLTableTreeHelpContextIds.XML_DESIGN_VIEW_HELPID);
+
+		addToolBarActions(manager, designViewer);
+
+		return designViewer;
+	}
+
+	private void addToolBarActions(ToolBarManager manager, IDesignViewer viewer) {
+		ViewerExpandCollapseAction expand = new ViewerExpandCollapseAction(true);
+		ViewerExpandCollapseAction collapse = new ViewerExpandCollapseAction(false);
+		manager.add(expand);
+		manager.add(collapse);
+		manager.update(true);
+
+		expand.setViewer((AbstractTreeViewer) viewer);
+		collapse.setViewer((AbstractTreeViewer) viewer);
 	}
 
 	/**
diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java
index 3383d00..95125b6 100644
--- a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java
+++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * Copyright (c) 2004, 2009 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -14,18 +14,24 @@
 
 import org.eclipse.jface.viewers.ILabelProvider;
 import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableColorProvider;
 import org.eclipse.jface.viewers.ITableLabelProvider;
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.StructuredViewer;
 import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
 import org.eclipse.wst.sse.ui.internal.contentoutline.IJFaceNodeAdapter;
 import org.eclipse.wst.sse.ui.internal.contentoutline.IJFaceNodeAdapterFactory;
 import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
 import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.CMDocumentManager;
 import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.CMDocumentManagerListener;
 import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDescriptionBuilder;
 import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDocumentCache;
 import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
@@ -39,7 +45,7 @@
 import org.w3c.dom.Text;
 
 
-public class XMLTableTreeContentProvider implements ITreeContentProvider, ITableLabelProvider, ILabelProvider, CMDocumentManagerListener {
+public class XMLTableTreeContentProvider implements ITreeContentProvider, ITableLabelProvider, ITableColorProvider, ILabelProvider, CMDocumentManagerListener {
 
 	protected CMDocumentManager documentManager;
 
@@ -47,6 +53,10 @@
 
 	private TreeContentHelper treeContentHelper = new TreeContentHelper();
 
+	private CMDescriptionBuilder descriptionBuilder = new CMDescriptionBuilder();
+
+	private Color fCMColor = null;
+
 	public XMLTableTreeContentProvider() {
 		super();
 	}
@@ -83,6 +93,9 @@
 				}
 			}
 		}
+		if (fCMColor != null) {
+			fCMColor.dispose();
+		}
 	}
 
 	private void doDelayedRefreshForViewers() {
@@ -118,6 +131,22 @@
 		}
 		else if ((column == 1) && (object instanceof Node)) {
 			result = treeContentHelper.getNodeValue((Node) object);
+			if (result == null)
+				result = getElementValueHelper((Element) object);
+				
+		}
+		return result != null ? result : ""; //$NON-NLS-1$
+	}
+	
+	private String getElementValueHelper(Element element) {
+		String result = null;
+
+		ModelQuery mq = ModelQueryUtil.getModelQuery(element.getOwnerDocument());
+		if ((result == null) && (mq != null)) {
+			CMElementDeclaration ed = mq.getCMElementDeclaration(element);
+			if ((ed != null) && !Boolean.TRUE.equals(ed.getProperty("isInferred"))) { //$NON-NLS-1$
+				result = descriptionBuilder.buildDescription(ed);
+			}
 		}
 		return result != null ? result : ""; //$NON-NLS-1$
 	}
@@ -328,4 +357,25 @@
 		// since we always return 'false' for "isLabelProperty",
 		// not need to listen. Maybe that should change some day?
 	}
+
+	public Color getBackground(Object element, int columnIndex) {
+		return null;
+	}
+
+	public Color getForeground(Object element, int columnIndex) {
+		if (columnIndex == 1 && treeContentHelper.getNodeValue((Node) element) == null)
+			return getCMColor();
+		return null;
+	}
+	
+	private Color getCMColor() {
+		if (fCMColor == null) {
+			Color background = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+			int r = Math.abs(background.getRed() - 125);
+			int g = Math.abs(background.getGreen() - 85);
+			int b = Math.abs(background.getBlue() - 105);
+			fCMColor = new Color(Display.getCurrent(), r, g, b);
+		}
+		return fCMColor;
+	}
 }
diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java
index 331f2d6..00694e7 100644
--- a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java
+++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others. All rights reserved. This
+ * Copyright (c) 2004, 2009 IBM Corporation and others. All rights reserved. This
  * program and the accompanying materials are made available under the terms
  * of the Eclipse Public License v1.0 which accompanies this distribution, and
  * is available at http://www.eclipse.org/legal/epl-v10.html
@@ -17,12 +17,16 @@
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.util.SafeRunnable;
 import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ICellModifier;
 import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TextCellEditor;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.dnd.DND;
@@ -34,13 +38,19 @@
 import org.eclipse.swt.dnd.DropTargetListener;
 import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Item;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
 import org.eclipse.wst.sse.core.StructuredModelManager;
 import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
@@ -137,22 +147,50 @@
 		}
 	}
 
-	protected CellEditor cellEditor;
+	private PaintListener fContentPaintListener = new PaintListener() {
 
-	protected XMLTreeExtension treeExtension;
-	
+		public void paintControl(PaintEvent e) {
+			GC gc = e.gc;
+			if (getTree().getItemCount() == 0) {
+				gc.setForeground(getTree().getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+				gc.setBackground(getTree().getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+				gc.drawString(XMLEditorMessages.XMLTreeExtension_3, 10, 10);
+				gc.drawString(XMLEditorMessages.XMLTreeExtension_4, 10, 10 + gc.getFontMetrics().getHeight());
+			}
+		}
+		
+	};
+
 	private ISelectionProvider fSelectionProvider = new SelectionProvider();
 
 	public XMLTableTreeViewer(Composite parent) {
 		super(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+		
+		TableLayout layout = new TableLayout();
+		
+		layout.addColumnData(new ColumnWeightData(40));
+		TreeColumn column = new TreeColumn(this.getTree(), SWT.LEFT);
+		column.setText(XMLEditorMessages.XMLTableTreeViewer_1);
+
+		layout.addColumnData(new ColumnWeightData(60));
+		column = new TreeColumn(this.getTree(), SWT.LEFT);
+		column.setText(XMLEditorMessages.XMLTableTreeViewer_2);
+
+		this.getTree().setHeaderVisible(true);
+		this.getTree().setLinesVisible(true);
+		this.getTree().setLayout(layout);
 
 		// set up providers
-		this.treeExtension = new XMLTreeExtension(getTree());
+		propertyDescriptorFactory = new XMLTableTreePropertyDescriptorFactory();
 
 		XMLTableTreeContentProvider provider = new XMLTableTreeContentProvider();
 		setContentProvider(provider);
 		setLabelProvider(provider);
 
+		setColumnProperties(new String[] {STRUCTURE_PROPERTY, VALUE_PROPERTY});
+		setCellEditors(new CellEditor[] {null, new TextCellEditor(this.getTree())});
+
+		setCellModifier(new XMLCMCellModifier());
 		createContextMenu();
 
 		DragSource dragSource = new DragSource(getControl(), DND.DROP_COPY | DND.DROP_MOVE);
@@ -161,6 +199,8 @@
 		DropTarget dropTarget = new DropTarget(getControl(), DND.DROP_COPY | DND.DROP_MOVE);
 		dropTarget.addDropListener(createDropTargetListener());
 		dropTarget.setTransfer(new Transfer[] {LocalSelectionTransfer.getTransfer()});
+
+		this.getTree().addPaintListener(fContentPaintListener);
 	}
 
 	/**
@@ -265,7 +305,6 @@
 	}
 	
 	protected void doRefresh(Object o, boolean fromDelayed) {
-		treeExtension.resetCachedData();
 		super.refresh(o);
 	}
 
@@ -279,32 +318,10 @@
 
 	protected void handleDispose(DisposeEvent event) {
 		super.handleDispose(event);
-		treeExtension.dispose();
+		this.getTree().removePaintListener(fContentPaintListener);
 		setDocument(null);
 	}
 
-	public void refresh() {
-		treeExtension.resetCachedData();
-		super.refresh();
-	}
-
-	public void refresh(Object o) {
-		treeExtension.resetCachedData();
-		super.refresh(o);
-	}
-
-	public void refresh(boolean updateLabels) {
-		treeExtension.resetCachedData();
-		super.refresh(updateLabels);
-		getControl().redraw();
-	}
-
-	public void refresh(Object element, boolean updateLabels) {
-		treeExtension.resetCachedData();
-		super.refresh(element, updateLabels);
-		getControl().redraw();
-	}
-
 	public void setDocument(IDocument document) {
 		/*
 		 * let the text editor to be the one that manages the model's lifetime
@@ -317,10 +334,6 @@
 				Document domDoc = null;
 				domDoc = ((IDOMModel) model).getDocument();
 				setInput(domDoc);
-				treeExtension.setIsUnsupportedInput(false);
-			}
-			else {
-				treeExtension.setIsUnsupportedInput(true);
 			}
 		}
 		finally {
@@ -330,5 +343,56 @@
 		}
 
 	}
+	
+	protected TreeContentHelper treeContentHelper = new TreeContentHelper();
+	protected XMLTableTreePropertyDescriptorFactory propertyDescriptorFactory;
+	
+	private final static String STRUCTURE_PROPERTY = XMLEditorMessages.XMLTreeExtension_0;
+	private final static String VALUE_PROPERTY = XMLEditorMessages.XMLTreeExtension_1;
+	
+	public class XMLCMCellModifier implements ICellModifier, TreeExtension.ICellEditorProvider {
+		public boolean canModify(Object element, String property) {
+			boolean result = false;
+			if (element instanceof Node) {
+				Node node = (Node) element;
+				if (property == VALUE_PROPERTY) {
+					result = treeContentHelper.isEditable(node);
+					if (result) {
+						/* Set up the cell editor based on the element */
+						CellEditor[] editors = getCellEditors();
+						if (editors.length > 0) {
+							if (editors[1] != null)
+								editors[1].dispose();
+							editors[1] = getCellEditor(element, 1);
+						}
+					}
+					
+				}
+			}
+			return result;
+		}
+
+		public Object getValue(Object object, String property) {
+			String result = null;
+			if (object instanceof Node) {
+				result = treeContentHelper.getNodeValue((Node) object);
+			}
+			return (result != null) ? result : ""; //$NON-NLS-1$
+		}
+
+		public void modify(Object element, String property, Object value) {
+			Item item = (Item) element;
+			String oldValue = treeContentHelper.getNodeValue((Node) item.getData());
+			String newValue = value.toString();
+			if ((newValue != null) && !newValue.equals(oldValue)) {
+				treeContentHelper.setNodeValue((Node) item.getData(), value.toString());
+			}
+		}
+
+		public CellEditor getCellEditor(Object o, int col) {
+			IPropertyDescriptor pd = propertyDescriptorFactory.createPropertyDescriptor(o);
+			return pd != null ? pd.createPropertyEditor(XMLTableTreeViewer.this.getTree()) : null;
+		}
+	}
 
 }
\ No newline at end of file