/**
 * File:    ModelOutlineAreaTreeviewer.java
 * Created: 12.12.2008
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany <www.ds-lab.org>
 *
 * 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:
 *    - Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *******************************************************************************/

package org.eclipse.jwt.we.editors.outline;

import java.util.ArrayList;

import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.gef.dnd.DelegatingDragAdapter;
import org.eclipse.gef.dnd.TemplateTransfer;
import org.eclipse.jface.util.DelegatingDropAdapter;
import org.eclipse.jface.util.TransferDragSourceListener;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jwt.meta.model.core.Model;
import org.eclipse.jwt.meta.model.processes.ActivityEdge;
import org.eclipse.jwt.we.editors.WEEditor;
import org.eclipse.jwt.we.editors.dnd.IDropListenerFactory;
import org.eclipse.jwt.we.editors.dnd.internal.DropListenerExtensionPoint;
import org.eclipse.jwt.we.editors.preferences.PreferenceReader;
import org.eclipse.jwt.we.model.view.Diagram;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Menu;

/**
 * A model treeview outline control for the outline page.
 * 
 * @version $Id: ModelOutlineAreaTreeviewer.java,v 1.6 2009/11/04 17:18:55
 *          chsaad Exp $
 * @author Florian Lautenbacher, Programming distributed Systems Lab, University
 *         of Augsburg, Germany, www.ds-lab.org
 */
public class ModelOutlineAreaTreeviewer
{

	/**
	 * The list of element types which should not be shown in the outline view.
	 */
	private ArrayList<Class> hiddenTypes = new ArrayList();


	/**
	 * The constructor.
	 * 
	 * @param parent
	 *            The parent composite.
	 */
	public ModelOutlineAreaTreeviewer(ModelOutlinePage outlinePage,
			WEEditor editor, TreeViewer contentOutlineViewer)
	{
		// Set up the tree viewer.
		contentOutlineViewer
				.setContentProvider(new AdapterFactoryContentProvider(
						outlinePage.getAdapterFactory()));
		contentOutlineViewer.setLabelProvider(new AdapterFactoryLabelProvider(
				outlinePage.getAdapterFactory()));
		contentOutlineViewer.setInput(editor.getMainModelResource());

		contentOutlineViewer.expandToLevel(2);

		// add drag support to the outline view
		// draglistener 1: template (source: outline view, target: graphical
		// viewer)
		TransferDragSourceListener dragListener1 = new TemplateTransferDragSourceListener(
				editor, contentOutlineViewer);
		// draglistener 2: viewer (source: outline view, target: outline view)
		CustomViewerDragAdapter dragListener2 = new CustomViewerDragAdapter(
				contentOutlineViewer);

		// add both drag listeners to outline view using a delegating drag
		// adapter
		DelegatingDragAdapter delegatingDragListenerAdapter = new DelegatingDragAdapter();
		delegatingDragListenerAdapter.addDragSourceListener(dragListener1);
		delegatingDragListenerAdapter.addDragSourceListener(dragListener2);
		Transfer[] transfers = new org.eclipse.swt.dnd.Transfer[]
		{ LocalTransfer.getInstance(), TemplateTransfer.getInstance() };
		contentOutlineViewer.addDragSupport(DND.DROP_COPY | DND.DROP_MOVE,
				transfers, delegatingDragListenerAdapter);

		// add a drop listener to the outline (source: outline view, target:
		// outline view)
		DelegatingDropAdapter delegateDrop = new DelegatingDropAdapter();
		// native drop adapter
		EditingDomainTransferDropListener dropListener = new EditingDomainTransferDropListener(
				editor.getEmfEditingDomain(), contentOutlineViewer);
		delegateDrop.addDropTargetListener(dropListener);
		// Plugins drops
		for (IDropListenerFactory factory : DropListenerExtensionPoint
				.getDropListenersFactories())
		{
			TransferDropTargetListener outlineDrop = factory
					.createWEOutlineDropListerner(contentOutlineViewer,
							(Model) editor.getModel(), editor.getEditDomain());
			if (outlineDrop != null)
				delegateDrop.addDropTargetListener(outlineDrop);
		}
		contentOutlineViewer.addDropSupport(DND.DROP_MOVE, delegateDrop
				.getTransfers(), delegateDrop);

		// contentOutlineViewer.addDropSupport(DND.DROP_MOVE | DND.DROP_LINK
		// | DND.DROP_DEFAULT, delegateDrop.getTransfers(), delegateDrop);

		// Make sure our popups work
		Menu contextMenu = outlinePage.getContextMenuManager()
				.createContextMenu(contentOutlineViewer.getControl());
		contentOutlineViewer.getControl().setMenu(contextMenu);
		editor.getSite().registerContextMenu(
				outlinePage.getContextMenuManager(), contentOutlineViewer);

		// listen for double clicks
		contentOutlineViewer.addDoubleClickListener(outlinePage);

		// add a filter
		contentOutlineViewer.addFilter(new OutlineViewFilter());
	}


	/**
	 * Refreshes this outline, i.e. forces an update of the outline and resets
	 * sorting and filtering options.
	 */
	public void refresh(TreeViewer treeViewer)
	{
		if (treeViewer != null)
		{
			// refresh sorter
			if (PreferenceReader.outlineSortByElement.get()
					&& treeViewer.getSorter() == null)
			{
				treeViewer.setSorter(new ViewerSorter());
			}
			else if (!PreferenceReader.outlineSortByElement.get()
					&& treeViewer.getSorter() != null)
			{
				treeViewer.setSorter(null);
			}

			// add the element types, which should be hidden
			hiddenTypes.clear();
			if (PreferenceReader.outlineHideActEdges.get())
			{
				hiddenTypes.add(ActivityEdge.class);
			}

			treeViewer.refresh();
		}
	}


	/**
	 * Dispose.
	 */
	public void dispose()
	{
		if (hiddenTypes != null)
		{
			hiddenTypes.clear();
			hiddenTypes = null;
		}
	}

	/**
	 * A filter that hides classes of the specified types.
	 * 
	 * @version $Id: ModelOutlineAreaTreeviewer.java,v 1.1.2.1 2009/01/20
	 *          15:25:39 chsaad Exp $
	 * @author Christian Saad (csaad@gmx.net), Programming distributed Systems
	 *         Lab, University of Augsburg, Germany, www.ds-lab.org
	 */
	private class OutlineViewFilter extends ViewerFilter
	{

		/**
		 * Returns whether the given element makes it through this filter.
		 * 
		 * @param viewer
		 *            the viewer
		 * @param parentElement
		 *            the parent element
		 * @param element
		 *            the element
		 * @return <code>true</code> if element is included in the filtered set,
		 *         and <code>false</code> if excluded
		 */
		@Override
		public boolean select(Viewer viewer, Object parentElement,
				Object element)
		{
			// hide diagram
			if (Diagram.class.isAssignableFrom(element.getClass()))
			{
				return false;
			}

			// hide element if its type is in hiddenTypes
			for (Class classType : hiddenTypes)
			{
				if (classType.isAssignableFrom(element.getClass()))
				{
					return false;
				}
			}

			return true;
		}
	}

}
