[181857] Column sorting in Servers view
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerTableViewer.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerTableViewer.java
index 74c5975..ca41572 100644
--- a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerTableViewer.java
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerTableViewer.java
@@ -30,9 +30,11 @@
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Item;
 import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
 import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.swt.widgets.Widget;
 import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.actions.ActionFactory;
 /**
  * Tree view showing servers and their associations.
@@ -250,21 +252,7 @@
 			}
 		});
 		setLabelProvider(labelProvider);
-		setComparator(new ViewerComparator() {
-			public int compare(Viewer viewer, Object e1, Object e2) {
-				if (e1 instanceof IServer && e2 instanceof IServer) {
-					IServer s1 = (IServer) e1;
-					IServer s2 = (IServer) e2;
-					return (s1.getName().compareToIgnoreCase(s2.getName()));
-				} else if (e1 instanceof ModuleServer && e2 instanceof ModuleServer) {
-					ModuleServer s1 = (ModuleServer) e1;
-					ModuleServer s2 = (ModuleServer) e2;
-					return (s1.module[s1.module.length - 1].getName().compareToIgnoreCase(s2.module[s2.module.length - 1].getName()));
-				}
-				
-				return super.compare(viewer, e1, e2);
-			}
-		});
+		setComparator(new ServerViewerComparator(labelProvider));
 		
 		setInput(ROOT);
 		addListeners();
@@ -337,6 +325,42 @@
 		}
 	}
 
+	/**
+	 * Resort the table based on field.
+	 * 
+	 * @param column the column being updated
+	 * @param col
+	 */
+	protected void resortTable(final TreeColumn column, int col) {
+		ServerViewerComparator sorter = (ServerViewerComparator) getComparator();
+		
+		if (col == sorter.getTopPriority())
+			sorter.reverseTopPriority();
+		else
+			sorter.setTopPriority(col);
+		
+		PlatformUI.getWorkbench().getDisplay().asyncExec(
+			new Runnable() {
+				public void run() {
+					refresh();
+					updateDirectionIndicator(column);
+				}
+			});
+	}
+
+	/**
+	 * Update the direction indicator as column is now the primary column.
+	 * 
+	 * @param column
+	 */
+	protected void updateDirectionIndicator(TreeColumn column) {
+		getTree().setSortColumn(column);
+		if (((ServerViewerComparator) getComparator()).getTopPriorityDirection() == ServerViewerComparator.ASCENDING)
+			getTree().setSortDirection(SWT.UP);
+		else
+			getTree().setSortDirection(SWT.DOWN);
+	}
+
 	protected Object[] adaptLabelChangeObjects(Object[] obj) {
 		if (obj == null)
 			return obj;
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerViewerComparator.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerViewerComparator.java
new file mode 100644
index 0000000..34091de
--- /dev/null
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServerViewerComparator.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.server.ui.internal.view.servers;
+
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+
+public class ServerViewerComparator extends ViewerComparator {
+	public static final int MAX_DEPTH = 3;
+	public static final int ASCENDING = 1;
+	public static final int DESCENDING = -1;
+
+	protected ITableLabelProvider labelProvider;
+
+	protected int[] priorities = new int[] { 0 };
+
+	protected int[] directions = new int[] { ASCENDING };
+
+	public ServerViewerComparator(ITableLabelProvider labelProvider) {
+		this.labelProvider = labelProvider;
+	}
+
+	public void setTopPriority(int priority) {
+		if (priorities[0] == priority)
+			return;
+		
+		int len = priorities.length + 1;
+		if (len > MAX_DEPTH)
+			len = MAX_DEPTH;
+		
+		int[] temp = new int[len];
+		System.arraycopy(priorities, 0, temp, 1, len - 1);
+		temp[0] = priority;
+		priorities = temp;
+		
+		temp = new int[len];
+		System.arraycopy(directions, 0, temp, 1, len - 1);
+		temp[0] = ASCENDING;
+		directions = temp;
+	}
+
+	public int getTopPriority() {
+		return priorities[0];
+	}
+
+	public void setTopPriorityDirection(int direction) {
+		if (direction == ASCENDING || direction == DESCENDING) {
+			directions[0] = direction;
+		}
+	}
+
+	public int getTopPriorityDirection() {
+		return directions[0];
+	}
+
+	public void reverseTopPriority() {
+		directions[0] *= -1;
+	}
+
+	public int compare(Viewer viewer, Object e1, Object e2, int a) {
+		int col = priorities[a];
+		
+		String s1 = labelProvider.getColumnText(e1, col);
+		String s2 = labelProvider.getColumnText(e2, col);
+		
+		int s = s1.compareToIgnoreCase(s2) * directions[a];
+		if (s == 0) {
+			if (a == priorities.length - 1)
+				return 0;
+			return compare(viewer, e1, e2, a+1);
+		}
+		return s;
+	}
+
+	public int compare(Viewer viewer, Object e1, Object e2) {
+		return compare(viewer, e1, e2, 0);
+	}
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
index d315127..3cf96e7 100644
--- a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/view/servers/ServersView.java
@@ -31,6 +31,7 @@
 import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
@@ -70,13 +71,27 @@
 		super();
 	}
 
+	protected SelectionListener getHeaderListener(final int col) {
+		return new SelectionAdapter() {
+			/**
+			 * Handles the case of user selecting the header area.
+			 */
+			public void widgetSelected(SelectionEvent e) {
+				if (tableViewer == null)
+					return;
+				TreeColumn column = (TreeColumn) e.widget;
+				tableViewer.resortTable(column, col);
+			}
+		};
+	}
+
 	/**
 	 * createPartControl method comment.
 	 * 
 	 * @param parent a parent composite
 	 */
 	public void createPartControl(Composite parent) {
-		treeTable = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.NONE);
+		treeTable = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
 		treeTable.setHeaderVisible(true);
 		treeTable.setLinesVisible(false);
 		treeTable.setLayoutData(new GridData(GridData.FILL_BOTH));
@@ -87,14 +102,19 @@
 		TreeColumn column = new TreeColumn(treeTable, SWT.SINGLE);
 		column.setText(Messages.viewServer);
 		column.setWidth(cols[0]);
+		column.addSelectionListener(getHeaderListener(0));
+		treeTable.setSortColumn(column);
+		treeTable.setSortDirection(SWT.UP);
 		
 		TreeColumn column2 = new TreeColumn(treeTable, SWT.SINGLE);
 		column2.setText(Messages.viewState);
 		column2.setWidth(cols[1]);
+		column2.addSelectionListener(getHeaderListener(1));
 		
 		TreeColumn column3 = new TreeColumn(treeTable, SWT.SINGLE);
 		column3.setText(Messages.viewStatus);
 		column3.setWidth(cols[2]);
+		column3.addSelectionListener(getHeaderListener(2));
 		
 		deferInitialization();
 	}
diff --git a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/wizard/page/ModifyModulesComposite.java b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/wizard/page/ModifyModulesComposite.java
index b2310eb..e477028 100644
--- a/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/wizard/page/ModifyModulesComposite.java
+++ b/plugins/org.eclipse.wst.server.ui/serverui/org/eclipse/wst/server/ui/internal/wizard/page/ModifyModulesComposite.java
@@ -34,8 +34,13 @@
 import org.eclipse.jface.viewers.ViewerComparator;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
@@ -43,6 +48,8 @@
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.wst.server.core.*;
 import org.eclipse.wst.server.ui.ServerUICore;
@@ -54,6 +61,8 @@
  */
 public class ModifyModulesComposite extends Composite {
 	private static final String ROOT = "root";
+	protected static Color color;
+	protected static Font font;
 
 	protected IWizardHandle wizard;
 
@@ -403,6 +412,20 @@
 		setFont(getParent().getFont());
 		PlatformUI.getWorkbench().getHelpSystem().setHelp(this, ContextIds.MODIFY_MODULES_COMPOSITE);
 		
+		Display display = getDisplay();
+		color = display.getSystemColor(SWT.COLOR_DARK_GRAY);
+		FontData[] fd = getFont().getFontData();
+		int size2 = fd.length;
+		for (int i = 0; i < size2; i++)
+			fd[i].setStyle(SWT.ITALIC);
+		font = new Font(display, fd);
+		addDisposeListener(new DisposeListener() {
+			public void widgetDisposed(DisposeEvent e) {
+				font.dispose();
+				color.dispose();
+			}
+		});
+		
 		Label label = new Label(this, SWT.NONE);
 		GridData data = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
 		data.horizontalSpan = 3;
@@ -523,7 +546,26 @@
 		data.widthHint = 150;
 		deployedTree.setLayoutData(data);
 		
-		deployedTreeViewer = new TreeViewer(deployedTree);
+		deployedTreeViewer = new TreeViewer(deployedTree) {
+			public void doUpdateItem(Widget widget, Object element, boolean fullMap) {
+				if (widget instanceof TreeItem && color != null) {
+					TreeItem item = (TreeItem) widget;
+					if (element instanceof ModuleServer) {
+						ModuleServer ms = (ModuleServer) element;
+						IModule m = ms.module[ms.module.length-1];
+						if (m.isExternal())
+							item.setForeground(color);
+						else
+							item.setForeground(null);
+						if (!(server instanceof IServer) || ((IServer)server).getModulePublishState(ms.module) != IServer.PUBLISH_STATE_NONE)
+							item.setFont(font);
+						else
+							item.setFont(null);
+					}
+				}
+				super.doUpdateItem(widget, element, fullMap);
+			}
+		};
 		labelProvider = ServerUICore.getLabelProvider();
 		labelProvider.addListener(new ILabelProviderListener() {
 			public void labelProviderChanged(LabelProviderChangedEvent event) {