//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.ui.forms;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.viewer.IViewerProvider;
import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
import org.eclipse.epf.authoring.gef.figures.Colors;
import org.eclipse.epf.authoring.ui.AuthoringUIHelpContexts;
import org.eclipse.epf.authoring.ui.AuthoringUIPlugin;
import org.eclipse.epf.authoring.ui.AuthoringUIResources;
import org.eclipse.epf.authoring.ui.editors.ColumnDescriptor;
import org.eclipse.epf.authoring.ui.editors.MethodElementEditor;
import org.eclipse.epf.authoring.ui.editors.ProcessEditor;
import org.eclipse.epf.authoring.ui.views.ProcessViewer;
import org.eclipse.epf.common.utils.StrUtil;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.edit.TngAdapterFactory;
import org.eclipse.epf.library.edit.command.IActionManager;
import org.eclipse.epf.library.edit.process.BreakdownElementWrapperItemProvider;
import org.eclipse.epf.library.edit.process.IBSItemProvider;
import org.eclipse.epf.library.edit.process.IColumnAware;
import org.eclipse.epf.library.edit.ui.ExposedAdapterFactoryContentProvider;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.Suppression;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.edit.util.VariabilityElementLabelProvider;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.DescribableElement;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.ProcessComponent;
import org.eclipse.epf.uma.UmaFactory;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.WorkBreakdownElement;
import org.eclipse.epf.uma.WorkOrder;
import org.eclipse.epf.uma.WorkOrderType;
import org.eclipse.epf.uma.WorkProductDescriptor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
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.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;


/**
 * Breadown structure editor
 * 
 * @author Phong Nguyen Le
 * @author Shilpa Toraskar
 * @since 1.0
 */
public class ProcessBreakdownStructureFormPage extends ProcessFormPage
		implements IViewerProvider {

	private static final String TXT_TRUE = "true"; //$NON-NLS-1$

	private static final String TXT_FALSE = "false"; //$NON-NLS-1$

	protected static final Collection ECLASSES;
	
	private int tabIndex = 0;
	
	static {
		ECLASSES = new ArrayList();
		ECLASSES.add(UmaPackage.eINSTANCE.getMethodPackage());
	}

	private class ProcessAdapterFactoryLabelProvider extends
			VariabilityElementLabelProvider implements IColorProvider {

		/**
		 * @param adapterFactory
		 */
		public ProcessAdapterFactoryLabelProvider(AdapterFactory adapterFactory) {
			super(adapterFactory);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object)
		 */
		public Color getForeground(Object element) {
			if (isSuppressed(element)) {
				return Colors.SUPRESSED_ELEMENT_LABEL;
			}
			else if (isExternal(element)) {
				return Colors.INHERITED_ELEMENT_LABEL;
			}
			return ColorConstants.listForeground;
		}

		private boolean isSuppressed(Object element) {
			if (element instanceof BreakdownElement) {
				return getSuppression()
						.isSuppressed((BreakdownElement) element);
			} else if (element instanceof BreakdownElementWrapperItemProvider) {
				return getSuppression().isSuppressed(
						(BreakdownElementWrapperItemProvider) element);
			}
			return false;
		}

		private Suppression getSuppression() {
			return ((ProcessEditor) ProcessBreakdownStructureFormPage.this
					.getEditor()).getSuppression();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
		 */
		public Color getBackground(Object element) {
			// let OS take control over tree widget background
			// rather than sending one fixed background.
			return null;//ColorConstants.listBackground;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.ibm.library.edit.util.VariabilityElementLabelProvider#isExternal(java.lang.Object)
		 */
		public boolean isExternal(Object element) {
			return ProcessUtil.isInherited(element);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.ibm.library.edit.util.VariabilityElementLabelProvider#getFont(java.lang.Object)
		 */
		public Font getFont(Object element) {
			if (isExternal(element)) {
				return italicFont;
			}
			return regularFont;
		}
	}

	private class ValidatingTextCellEditor extends TextCellEditor {
		protected Object lastInvalidElement;

		private int columnIndex;

		/**
		 * @param parent
		 */
		public ValidatingTextCellEditor(Composite parent) {
			super(parent);
		}

		void setColumnIndex(int columnIndex) {
			this.columnIndex = columnIndex;
		}

		public int getColumnIndex() {
			return columnIndex;
		}

		public Object getLastInvalidElement() {
			return lastInvalidElement;
		}

		String isValid(String txt) {
			IStructuredSelection selection = (IStructuredSelection) viewer
					.getSelection();
			if (selection.size() == 1) {
				Object e = selection.getFirstElement();
				String msg = isValid(e, txt);
				if (msg != null) {
					lastInvalidElement = e;
				} else {
					lastInvalidElement = null;
				}
				return msg;
			}
			return null;
		}

		protected String isValid(Object e, String txt) {
			return null;
		}
	}

	private static class CellEditorValidator implements ICellEditorValidator {

		private ValidatingTextCellEditor cellEditor;

		/**
		 * 
		 */
		public CellEditorValidator(ValidatingTextCellEditor cellEditor) {
			this.cellEditor = cellEditor;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.jface.viewers.ICellEditorValidator#isValid(java.lang.Object)
		 */
		public String isValid(Object value) {
			return cellEditor.isValid((String) value);
		}

	}

	private class ValidatingDeactivateListener implements Listener {
		private ValidatingTextCellEditor cellEditor;

		ValidatingDeactivateListener(ValidatingTextCellEditor cellEditor) {
			this.cellEditor = cellEditor;
		}

		public void handleEvent(Event e) {
			Display.getCurrent().asyncExec(new Runnable() {
				public void run() {
					if (cellEditor.getLastInvalidElement() != null) {
						AuthoringUIPlugin
								.getDefault()
								.getMsgDialog()
								.displayError(
										AuthoringUIResources.editProcessElementErrorDialog_title, //$NON-NLS-1$
										cellEditor.getErrorMessage());
						viewer.editElement(cellEditor.getLastInvalidElement(),
								cellEditor.getColumnIndex());
					}
				}

			});
		}
	}

	// private class ValidatingFocusAdapter extends FocusAdapter {
	// private ValidatingTextCellEditor cellEditor;
	//
	// ValidatingFocusAdapter(ValidatingTextCellEditor cellEditor) {
	// this.cellEditor = cellEditor;
	// }
	//
	// public void focusLost(FocusEvent e) {
	// Display.getCurrent().asyncExec(new Runnable() {
	//
	// public void run() {
	// if (cellEditor.getLastInvalidElement() != null) {
	// AuthoringUIPlugin
	// .getDefault()
	// .getMsgDialog()
	// .displayError(
	// AuthoringUIResources
	// .getString("AuthoringUI.editProcessElementErrorDialog.title"),
	// //$NON-NLS-1$
	// cellEditor.getErrorMessage());
	// viewer.editElement(cellEditor.getLastInvalidElement(),
	// cellEditor.getColumnIndex());
	// }
	// }
	//
	// });
	// }
	// }

	// private Composite parent = null;

	private ColumnDescriptor[] columnDescriptors;

	// private boolean validNamePrompted = false;
	// private int promptCount = 0;

	// private MethodElement promptedElement;

	// private TableTreeViewer tableTreeViewer;

	private AdapterFactory adapterFactory;

	// private int tabIndex;

	// private Object tabFolder;

	protected ProcessViewer viewer;

	private TextCellEditor textCellEditor;

	private ValidatingTextCellEditor nameCellEditor;

	private ValidatingTextCellEditor predListCellEditor;

	private ComboBoxCellEditor comboBoxCellEditor;

	private CheckboxCellEditor checkBoxCellEditor;

	private ValidatingTextCellEditor presentationNameCellEditor;

	// private HashMap columnIndexToNameMap;
	private boolean isReadOnly;

	/**
	 * @param editor
	 * @param id
	 * @param title
	 */
	public ProcessBreakdownStructureFormPage(FormEditor editor, String id,
			String title) {
		super(editor, id, title);
	}

	public boolean isReadOnly() {
		if (isReadOnly) {
			return isReadOnly;
		}
		return TngUtil.isLocked(process);
	}
	
	public boolean basicIsReadOnly() {
		return isReadOnly;
	}

	public void setReadOnly(boolean isReadOnly) {
		this.isReadOnly = isReadOnly;
	}

	public void setAdapterFactory(AdapterFactory adapterFactory) {
		this.adapterFactory = adapterFactory;
	}

	public void setColumnDescriptors(ColumnDescriptor[] columnDescriptors) {
		this.columnDescriptors = columnDescriptors;

		if (adapterFactory instanceof IColumnAware) {
			Map columnIndexToNameMap = new HashMap();
			for (int i = 0; i < columnDescriptors.length; i++) {
				columnIndexToNameMap.put(new Integer(i),
						columnDescriptors[i].id);
			}
			((IColumnAware) adapterFactory)
					.setColumnIndexToNameMap(columnIndexToNameMap);
		}
	}

	private void setText(BreakdownElement e, String prop, String txt) {
		IActionManager actionMgr = ((MethodElementEditor) getEditor())
				.getActionManager();
		if (prop == IBSItemProvider.COL_PREDECESSORS) {
			List predecessors = new ArrayList();
			WorkBreakdownElement wbe = (WorkBreakdownElement) e;
			if (ProcessUtil.checkPredecessorList(wbe, txt, adapterFactory,
					process, predecessors) == null) {
				WorkOrder wo = null;
				int size = wbe.getLinkToPredecessor().size();
				
				// remove WorkOrders for predecessors that are not in predecessor list and accepted by the filter
				//
				List predToBeDeleted = new ArrayList();
				IFilter filter = ProcessUtil.getFilter(adapterFactory);
				boolean nullFilter = filter == null;
				for (Iterator iter = wbe.getLinkToPredecessor().iterator(); iter
						.hasNext();) {
					wo = (WorkOrder) iter.next();
					int id = predecessors.indexOf(wo.getPred());
					if (id == -1 && (nullFilter || filter.accept(wo.getPred()))) {
						predToBeDeleted.add(wo);
					}
				}
				for (Iterator iter = predToBeDeleted.iterator(); iter.hasNext();)
				{
					WorkOrder w = (WorkOrder) iter.next();
					actionMgr.doAction(
							IActionManager.REMOVE,
							wbe,
							UmaPackage.eINSTANCE
									.getWorkBreakdownElement_LinkToPredecessor(),
							w, -1);
				}

				size = predecessors.size();
				for (int i = 0; i < size; i++) {
					WorkBreakdownElement element = (WorkBreakdownElement) predecessors
							.get(i);
					boolean found = false;
					find_pred: for (Iterator iterator = wbe
							.getLinkToPredecessor().iterator(); iterator
							.hasNext();) {
						wo = (WorkOrder) iterator.next();
						if (wo.getPred() == element) {
							found = true;
							break find_pred;
						}
					}
					if (!found) {
						wo = UmaFactory.eINSTANCE.createWorkOrder();
						wo.setPred(element);
						// wo.setSucc(e);
						wo.setLinkType(WorkOrderType.FINISH_TO_FINISH_LITERAL);

						// // try to add the new WorkOrder to the right place so
						// the order of WorkOrder list can be preserved.
						// //
						// if(prev != null) {
						// int id = e.getLinkToPredecessor().indexOf(prev) + 1;
						// if(id >= e.getLinkToPredecessor().size()) {
						// e.getLinkToPredecessor().add(wo);
						// }
						// else {
						// e.getLinkToPredecessor().add(id, wo);
						// }
						// }
						actionMgr
								.doAction(
										IActionManager.ADD,
										wbe,
										UmaPackage.eINSTANCE
												.getWorkBreakdownElement_LinkToPredecessor(),
										wo, -1);
						// wbe.getLinkToPredecessor().add(wo);
					}
				}
			}
			return;
		}
		// IBSItemProvider adapter = (IBSItemProvider) adapterFactory.adapt(e,
		// ITreeItemContentProvider.class);
		// adapter.setAttribute(e, prop, txt);

		ProcessUtil.setAttribute(actionMgr, e, prop, txt);
	}

	private String getText(BreakdownElement e, String prop) {
		// handle editing presentation name of extending/contributing activity
		// specially
		//
		if (prop == IBSItemProvider.COL_PRESENTATION_NAME
				&& ProcessUtil.isExtendingOrLocallyContributing(e)) {
			return ((DescribableElement) e).getPresentationName();
		}

		IBSItemProvider adapter = (IBSItemProvider) adapterFactory.adapt(e,
				ITreeItemContentProvider.class);
		return adapter.getAttribute(e, prop);
	}

	public void setTabIndex(int id) {
		 tabIndex = id;
	}
	
	public int getTabIndex() {
		return tabIndex;
	}

	public void setTabFolder(CTabFolder tabFolder) {
		// this.tabFolder = tabFolder;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.forms.editor.FormPage#createFormContent(org.eclipse.ui.forms.IManagedForm)
	 */
	protected void createFormContent(IManagedForm managedForm) {
		// create form toolkit
		ScrolledForm form = managedForm.getForm();
		FormToolkit toolkit = managedForm.getToolkit();
		form.setText(getEditor().getPartName());

		TableWrapLayout layout = new TableWrapLayout();
		form.getBody().setLayout(layout);

		Section section = toolkit.createSection(form.getBody(),
				Section.EXPANDED | Section.TITLE_BAR);
		TableWrapData td = new TableWrapData(TableWrapData.FILL_GRAB,
				TableWrapData.FILL_GRAB);
		section.setLayoutData(td);
		section
				.setText(getTitle()
						+ " " + AuthoringUIResources.processBreakdownStructureFormPage_BSEditor); 
		section.setLayout(new GridLayout());

		Composite composite = toolkit.createComposite(section);
		// composite.setLayout(new GridLayout(1, false));
		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		composite.setLayout(new GridLayout());
		section.setClient(composite);
		Control control = createControl(composite);
		toolkit.adapt(control, true, true);
		GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
		gridData.verticalIndent = 10;
		gridData.heightHint = 600;
		control.setLayoutData(gridData);

		ProcessEditor editor = (ProcessEditor) getEditor();
		// editor.createContextMenuFor(tableTreeViewer);
		editor.createContextMenuFor(viewer);

		setInput(process);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ibm.rup.authoring.views.IContentTab#createControl(org.eclipse.swt.widgets.Composite)
	 */
	public Control createControl(Composite parent) {
		// this.parent = parent;
		// This is the page for the table tree viewer.
		//
		Composite comp = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		comp.setLayout(layout);
		GridData gd = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
		comp.setLayoutData(gd);
		
		viewer = new ProcessViewer(comp, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
		viewer.getControl().setLayoutData(gd);
		viewer.setupColumns(columnDescriptors);
		viewer.setContentProvider(new ExposedAdapterFactoryContentProvider(
				adapterFactory));
		viewer.setLabelProvider(new ProcessAdapterFactoryLabelProvider(
				adapterFactory));

		viewer.setActionManager(((MethodElementEditor) getEditor())
			.getActionManager());

		textCellEditor = new TextCellEditor(viewer.getCellEditorParent());
		comboBoxCellEditor = new ComboBoxCellEditor(viewer
				.getCellEditorParent(), new String[] { TXT_TRUE, TXT_FALSE });
		checkBoxCellEditor = new CheckboxCellEditor(viewer
				.getCellEditorParent());

		setCellEditors();

		// Set the cell modifier
		viewer.setCellModifier(new ICellModifier() {
			public boolean canModify(Object element, String property) {
				// System.out.println("canModify: element="+element+",
				// property="+property);

				if (isReadOnly() ||
						(element instanceof BreakdownElementWrapperItemProvider && ((BreakdownElementWrapperItemProvider) element).isReadOnly())) {
					return false;
				}

//				if (!(element instanceof BreakdownElement)
//						&& !(element instanceof BreakdownElementWrapperItemProvider && !((BreakdownElementWrapperItemProvider) element)
//								.isReadOnly())) {
//					Collection types = new ArrayList();
//					types.add(VariabilityType.EXTENDS_LITERAL);
//					if (TngUtil
//							.isGeneralizer(
//									(VariabilityElement) ((BreakdownElementWrapperItemProvider) element)
//											.getOwner(), types))
//						return false;
//				}
				
				if (property == IBSItemProvider.COL_ID
						|| property == IBSItemProvider.COL_TYPE
						|| property == IBSItemProvider.COL_MODEL_INFO
						|| property == IBSItemProvider.COL_DELIVERABLE) {
					return false;
				}

				element = TngUtil.unwrap(element);
				if (!(element instanceof WorkProductDescriptor)
						&& (property == IBSItemProvider.COL_ENTRY_STATE || property == IBSItemProvider.COL_EXIT_STATE)) {
					return false;
				}
				if (!(element instanceof WorkBreakdownElement)
						&& (property == IBSItemProvider.COL_PREDECESSORS)) {
					return false;
				}

				return true;
			}

			public Object getValue(Object element, String property) {
				// System.out.println("getValue: element="+element+",
				// property="+property);
				BreakdownElement e = (BreakdownElement) TngUtil.unwrap(element);
				String val = getText(e, property);
				switch (getCellEditorType(property)) {
				case ColumnDescriptor.CELL_EDITOR_TYPE_COMBO_BOOLEAN:
					if (TXT_TRUE.equalsIgnoreCase(val)) {
						return new Integer(0);
					} else {
						return new Integer(1);
					}
				case ColumnDescriptor.CELL_EDITOR_TYPE_TEXT:
					return val;
				case ColumnDescriptor.CELL_EDITOR_TYPE_CHECK_BOOLEAN:
					return Boolean.valueOf(val);
				default:
					return val;
				}
			}

			public void modify(final Object element, String property,
					Object value) {
				// System.out.println("modify: element="+element+",
				// property="+property+", value="+value);
				Widget item = (Widget) element;
				BreakdownElement be = (BreakdownElement) TngUtil.unwrap(item
						.getData());

				final int columnIndex = getColumnIndex(property);
				CellEditor cellEditor = viewer.getCellEditors()[columnIndex];
				String errMsg = cellEditor.getErrorMessage();
				if (errMsg != null) {
					return;
				}

				String txt;
				switch (getCellEditorType(property)) {
				case ColumnDescriptor.CELL_EDITOR_TYPE_TEXT:
					txt = (String) value;
					break;
				case ColumnDescriptor.CELL_EDITOR_TYPE_COMBO_BOOLEAN:
					int index = ((Number) value).intValue();
					if (index == 0) {
						txt = TXT_TRUE;
					} else {
						txt = TXT_FALSE;
					}
					break;
				case ColumnDescriptor.CELL_EDITOR_TYPE_CHECK_BOOLEAN:
					txt = value.toString();
					break;
				default:
					txt = TngUtil.checkNull(value.toString());
				}
				setText(be, property, txt);
				if (property == IBSItemProvider.COL_PRESENTATION_NAME
						&& StrUtil.isBlank(be.getName())) {
					be.setName(txt);
				}
				viewer.refresh();
			}
		});

		viewer.setAutoExpandLevel(3);
		viewer.setInput(process);

		// int dndOperations = DND.DROP_COPY | DND.DROP_MOVE ;
		// Transfer[] transfers = new Transfer[] { TNGObjTransfer.getInstance()
		// };
		// tableTreeViewer.addDropSupport(DND.DROP_MOVE, transfers, new
		// BSTabDropAdapter(tableTreeViewer));

		// BSEditorView.getView().createContextMenuFor(tableTreeViewer);
		// return tableTreeViewer.getControl();

		setContextHelp(viewer.getControl());

//		return viewer.getControl();
		return comp;

	}

	public CellEditor getCellEditor(String columnID, int columnIndex) {
		if (columnID == IBSItemProvider.COL_PRESENTATION_NAME) {
			if (presentationNameCellEditor == null) {
				presentationNameCellEditor = new ValidatingTextCellEditor(
						viewer.getCellEditorParent()) {
					protected String isValid(Object e, String txt) {
						e = TngUtil.unwrap(e);
						Suppression suppression = ((ProcessEditor)getEditor()).getSuppression();
						boolean ignoreSuppressed = true;
						return ProcessUtil
								.checkBreakdownElementPresentationName(
										adapterFactory, (BreakdownElement) e,
										txt, suppression, ignoreSuppressed);
					}
				};

				presentationNameCellEditor
						.setValidator(new CellEditorValidator(
								presentationNameCellEditor));
				// presentationNameCellEditor.getControl().addFocusListener(new
				// ValidatingFocusAdapter(presentationNameCellEditor));
				presentationNameCellEditor.getControl().addListener(
						SWT.Deactivate,
						new ValidatingDeactivateListener(
								presentationNameCellEditor));
			}
			presentationNameCellEditor.setColumnIndex(columnIndex);

			return presentationNameCellEditor;
		} else if (columnID == IBSItemProvider.COL_NAME) {
			if (nameCellEditor == null) {
				nameCellEditor = new ValidatingTextCellEditor(viewer
						.getCellEditorParent()) {
					protected String isValid(Object e, String txt) {
						e = TngUtil.unwrap(e);
						Suppression suppression = ((ProcessEditor)getEditor()).getSuppression();
						return TngUtil
								.checkActivityName(adapterFactory, e, txt, suppression);
					}
				};
				nameCellEditor.setValidator(new CellEditorValidator(
						nameCellEditor));
				// nameCellEditor.getControl().addFocusListener(new
				// ValidatingFocusAdapter(nameCellEditor));
				nameCellEditor.getControl().addListener(SWT.Deactivate,
						new ValidatingDeactivateListener(nameCellEditor));
			}
			nameCellEditor.setColumnIndex(columnIndex);

			return nameCellEditor;
		} else if (columnID == IBSItemProvider.COL_PREDECESSORS) {
			if (predListCellEditor == null) {
				predListCellEditor = new ValidatingTextCellEditor(viewer
						.getCellEditorParent()) {
					protected String isValid(Object e, String txt) {
						e = TngUtil.unwrap(e);
						return ProcessUtil.checkPredecessorList(
								(WorkBreakdownElement) e, txt, adapterFactory,
								process, null);
					}
				};
				predListCellEditor.setValidator(new CellEditorValidator(
						predListCellEditor));
				// predListCellEditor.getControl().addFocusListener(new
				// ValidatingFocusAdapter(predListCellEditor));
				predListCellEditor.getControl().addListener(SWT.Deactivate,
						new ValidatingDeactivateListener(predListCellEditor));
			}
			predListCellEditor.setColumnIndex(columnIndex);

			return predListCellEditor;
		}
		return null;
	}

	/**
	 * 
	 */
	public void setCellEditors() {
		CellEditor[] cellEditors = new CellEditor[columnDescriptors.length];
		for (int i = 0; i < columnDescriptors.length; i++) {
			CellEditor cellEditor = getCellEditor(columnDescriptors[i].id, i);
			if (cellEditor != null) {
				cellEditors[i] = cellEditor;
			} else {
				switch (columnDescriptors[i].cellEditorType) {
				case ColumnDescriptor.CELL_EDITOR_TYPE_COMBO_BOOLEAN:
					cellEditors[i] = comboBoxCellEditor;
					break;
				case ColumnDescriptor.CELL_EDITOR_TYPE_TEXT:
					cellEditors[i] = textCellEditor;
					break;
				case ColumnDescriptor.CELL_EDITOR_TYPE_CHECK_BOOLEAN:
					cellEditors[i] = checkBoxCellEditor;
					break;
				default:
					cellEditors[i] = null;
				}
			}
		}
		viewer.setCellEditors(cellEditors);
	}

	public void setInput(Object newInput) {
		if (newInput instanceof Process) {
			process = (Process) newInput;
			if (process.eContainer() instanceof ProcessComponent) {
				viewer.setInput(process.eContainer());
				// viewer.expandAll();
//				viewer.reveal(process);
				return;
			}
		}
		viewer.setInput(null);
	}

	private int getColumnIndex(String property) {
		Object[] colProps = viewer.getColumnProperties();
		for (int i = 0; i < colProps.length; i++) {
			if (colProps[i] == property)
				return i;
		}
		return -1;
	}

	private int getCellEditorType(String property) {
		for (int i = 0; i < columnDescriptors.length; i++) {
			ColumnDescriptor desc = columnDescriptors[i];
			if (desc.id == property) {
				return desc.cellEditorType;
			}
		}
		return ColumnDescriptor.CELL_EDITOR_TYPE_NONE;
	}

	public Viewer getViewer() {
		return viewer;
	}

	public void setProcess(Process proc) {
		if (process != proc) {
			setInput(proc);
		}
	}

	/**
	 * @return Returns the adapterFactory.
	 */
	public AdapterFactory getAdapterFactory() {
		return adapterFactory;
	}

	public void updateColumns(ColumnDescriptor[] newColumnDescriptors) {
		setColumnDescriptors(newColumnDescriptors);
		viewer.setupColumns(newColumnDescriptors);
		setCellEditors();
		viewer.refresh();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.forms.editor.FormPage#dispose()
	 */
	public void dispose() {
		// if(adapterFactory instanceof ComposeableAdapterFactory) {
		// ((ComposedAdapterFactory)adapterFactory).dispose();
		// }

		if (viewer.getContentProvider() != null) {
			viewer.getContentProvider().dispose();
		}

		if (viewer.getLabelProvider() != null) {
			viewer.getLabelProvider().dispose();
		}

		super.dispose();
	}

	private void setContextHelp(Control control) {
		AdapterFactory adapterFac = getAdapterFactory();
		AdapterFactory allFac = TngAdapterFactory.INSTANCE
				.getProcessComposedAdapterFactory();
		AdapterFactory wbsFac = TngAdapterFactory.INSTANCE
				.getWBS_ComposedAdapterFactory();
		AdapterFactory obsFac = TngAdapterFactory.INSTANCE
				.getOBS_ComposedAdapterFactory();
		AdapterFactory pbsFac = TngAdapterFactory.INSTANCE
				.getPBS_ComposedAdapterFactory();

		// System.out.println("$$$ DEBUG: current dadpter fac = " + adapterFac);
		// System.out.println("$$$ DEBUG: all dadpter fac = " + allFac);
		// System.out.println("$$$ DEBUG: wbs dadpter fac = " + wbsFac);
		// System.out.println("$$$ DEBUG: obs dadpter fac = " + obsFac);
		// System.out.println("$$$ DEBUG: pbs dadpter fac = " + pbsFac);

		if (adapterFac == wbsFac)
			PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
					AuthoringUIHelpContexts.FORM_EDITOR_PROCESS_WBS_CONTEXT);
		else if (adapterFac == obsFac)
			PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
					AuthoringUIHelpContexts.FORM_EDITOR_PROCESS_OBS_CONTEXT);
		else if (adapterFac == pbsFac)
			PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
					AuthoringUIHelpContexts.FORM_EDITOR_PROCESS_PBS_CONTEXT);
		else if (adapterFac == allFac)
			PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
					AuthoringUIHelpContexts.FORM_EDITOR_PROCESS_ALLBS_CONTEXT);
	}
	
	public IAction[] getAdditionalActions() {
		return null;
	}
}
