content: /*******************************************************************************
   * Copyright (c) 2000, 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
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.ui.browsing;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Comparator;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.core.resources.IContainer;
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.IMarker;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.IAdaptable;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.help.IContextProvider;
  import org.eclipse.jface.action.IAction;
  import org.eclipse.jface.action.IMenuListener;
  import org.eclipse.jface.action.IMenuManager;
  import org.eclipse.jface.action.IStatusLineManager;
  import org.eclipse.jface.action.IToolBarManager;
  import org.eclipse.jface.action.MenuManager;
  import org.eclipse.jface.text.ITextSelection;
  import org.eclipse.jface.util.IPropertyChangeListener;
  import org.eclipse.jface.util.PropertyChangeEvent;
  import org.eclipse.jface.util.TransferDragSourceListener;
  import org.eclipse.jface.util.TransferDropTargetListener;
  import org.eclipse.jface.viewers.IContentProvider;
  import org.eclipse.jface.viewers.ILabelProvider;
  import org.eclipse.jface.viewers.IOpenListener;
  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.OpenEvent;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.jface.viewers.StructuredViewer;
  import org.eclipse.search.ui.ISearchResultViewPart;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.dnd.DND;
  import org.eclipse.swt.dnd.Transfer;
  import org.eclipse.swt.events.KeyAdapter;
  import org.eclipse.swt.events.KeyEvent;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Menu;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.ui.IActionBars;
  import org.eclipse.ui.IEditorInput;
  import org.eclipse.ui.IEditorPart;
  import org.eclipse.ui.IFileEditorInput;
  import org.eclipse.ui.IMemento;
  import org.eclipse.ui.IPartListener2;
  import org.eclipse.ui.ISelectionListener;
  import org.eclipse.ui.IViewSite;
  import org.eclipse.ui.IWorkbenchPage;
  import org.eclipse.ui.IWorkbenchPart;
  import org.eclipse.ui.IWorkbenchPartReference;
  import org.eclipse.ui.IWorkbenchPartSite;
  import org.eclipse.ui.IWorkingSet;
  import org.eclipse.ui.IWorkingSetManager;
  import org.eclipse.ui.PartInitException;
  import org.eclipse.ui.PlatformUI;
  import org.eclipse.ui.actions.ActionContext;
  import org.eclipse.ui.actions.ActionGroup;
  import org.eclipse.ui.part.IShowInSource;
  import org.eclipse.ui.part.ResourceTransfer;
  import org.eclipse.ui.part.ShowInContext;
  import org.eclipse.ui.part.ViewPart;
  import org.eclipse.ui.texteditor.ITextEditor;
  import org.eclipse.ui.views.navigator.LocalSelectionTransfer;
  import org.eclipse.wst.jsdt.core.IClassFile;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IPackageFragment;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.JavaScriptCore;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.actions.CompositeActionGroup;
  import org.eclipse.wst.jsdt.internal.ui.actions.NewWizardsActionGroup;
  import org.eclipse.wst.jsdt.internal.ui.dnd.DelegatingDropAdapter;
  import org.eclipse.wst.jsdt.internal.ui.dnd.JdtViewerDragAdapter;
  import org.eclipse.wst.jsdt.internal.ui.dnd.ResourceTransferDragAdapter;
  import org.eclipse.wst.jsdt.internal.ui.infoviews.AbstractInfoView;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.EditorUtility;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.IClassFileEditorInput;
  import org.eclipse.wst.jsdt.internal.ui.packageview.SelectionTransferDragAdapter;
  import org.eclipse.wst.jsdt.internal.ui.packageview.SelectionTransferDropAdapter;
  import org.eclipse.wst.jsdt.internal.ui.search.SearchUtil;
  import org.eclipse.wst.jsdt.internal.ui.util.JavaUIHelp;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.AppearanceAwareLabelProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.DecoratingJavaLabelProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.IViewPartInputProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.JavaElementImageProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.JavaUILabelProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.ProblemTableViewer;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.StatusBarUpdater;
  import org.eclipse.wst.jsdt.internal.ui.workingsets.WorkingSetFilterActionGroup;
  import org.eclipse.wst.jsdt.ui.IContextMenuConstants;
  import org.eclipse.wst.jsdt.ui.IWorkingCopyManager;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementComparator;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabelProvider;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  import org.eclipse.wst.jsdt.ui.PreferenceConstants;
  import org.eclipse.wst.jsdt.ui.actions.BuildActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.CCPActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.CustomFiltersActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.GenerateActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.ImportActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.JavaSearchActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.OpenEditorActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.OpenViewActionGroup;
  import org.eclipse.wst.jsdt.ui.actions.RefactorActionGroup;
  
  
  abstract class JavaBrowsingPart extends ViewPart implements IMenuListener, ISelectionListener, IViewPartInputProvider {
  
  	private static final String TAG_SELECTED_ELEMENTS= "selectedElements"; //$NON-NLS-1$
  	private static final String TAG_SELECTED_ELEMENT= "selectedElement"; //$NON-NLS-1$
  	private static final String TAG_LOGICAL_PACKAGE= "logicalPackage"; //$NON-NLS-1$
  	private static final String TAG_SELECTED_ELEMENT_PATH= "selectedElementPath"; //$NON-NLS-1$
  
  	private JavaUILabelProvider fLabelProvider;
  	private ILabelProvider fTitleProvider;
  	private StructuredViewer fViewer;
  	private IMemento fMemento;
  	private JavaElementTypeComparator fTypeComparator;
  
  	// Actions
  	private WorkingSetFilterActionGroup fWorkingSetFilterActionGroup;
  	private boolean fHasWorkingSetFilter= true;
  	private boolean fHasCustomFilter= true;
  	private OpenEditorActionGroup fOpenEditorGroup;
  	private CCPActionGroup fCCPActionGroup;
  	private BuildActionGroup fBuildActionGroup;
  	private ToggleLinkingAction fToggleLinkingAction;
  	protected CompositeActionGroup fActionGroups;
  
  
  	// Filters
  	private CustomFiltersActionGroup fCustomFiltersActionGroup;
  
  	protected IWorkbenchPart fPreviousSelectionProvider;
  	protected Object fPreviousSelectedElement;
  
  	// Linking
  	private boolean fLinkingEnabled;
  
  	/*
  	 * Ensure selection changed events being processed only if
  	 * initiated by user interaction with this part.
  	 */
  	private boolean fProcessSelectionEvents= true;
  
  	private IPartListener2 fPartListener= new IPartListener2() {
  		public void partActivated(IWorkbenchPartReference ref) {
  		}
  		public void partBroughtToTop(IWorkbenchPartReference ref) {
  		}
  	 	public void partInputChanged(IWorkbenchPartReference ref) {
  	 	}
  		public void partClosed(IWorkbenchPartReference ref) {
  		}
  		public void partDeactivated(IWorkbenchPartReference ref) {
  		}
  		public void partOpened(IWorkbenchPartReference ref) {
  		}
  		public void partVisible(IWorkbenchPartReference ref) {
  			if (ref != null && ref.getId() == getSite().getId()){
  				fProcessSelectionEvents= true;
  				IWorkbenchPage page= getSite().getWorkbenchWindow().getActivePage();
  				if (page != null)
  					selectionChanged(page.getActivePart(), page.getSelection());
  		}
  		}
  		public void partHidden(IWorkbenchPartReference ref) {
  			if (ref != null && ref.getId() == getSite().getId())
  				fProcessSelectionEvents= false;
  		}
  	};
  
  	public JavaBrowsingPart() {
  		super();
  		initLinkingEnabled();
  	}
  
  	/*
  	 * Implements method from IViewPart.
  	 */
  	public void init(IViewSite site, IMemento memento) throws PartInitException {
  		super.init(site, memento);
  		fMemento= memento;
  	}
  
  	/*
  	 * Implements method from IViewPart.
  	 */
  	public void saveState(IMemento memento) {
  		if (fViewer == null) {
  			// part has not been created
  			if (fMemento != null) //Keep the old state;
  				memento.putMemento(fMemento);
  			return;
  		}
  		if (fHasWorkingSetFilter)
  			fWorkingSetFilterActionGroup.saveState(memento);
  		if (fHasCustomFilter)
  			fCustomFiltersActionGroup.saveState(memento);
  		saveSelectionState(memento);
  		saveLinkingEnabled(memento);
  	}
  
  	private void saveLinkingEnabled(IMemento memento) {
  		memento.putInteger(getLinkToEditorKey(), fLinkingEnabled ? 1 : 0);
  	}
  
  	private void saveSelectionState(IMemento memento) {
  		Object elements[]= ((IStructuredSelection) fViewer.getSelection()).toArray();
  		if (elements.length > 0) {
  			IMemento selectionMem= memento.createChild(TAG_SELECTED_ELEMENTS);
  			for (int i= 0; i < elements.length; i++) {
  				IMemento elementMem= selectionMem.createChild(TAG_SELECTED_ELEMENT);
  				Object o= elements[i];
  				if (o instanceof IJavaScriptElement)
  					elementMem.putString(TAG_SELECTED_ELEMENT_PATH, ((IJavaScriptElement) elements[i]).getHandleIdentifier());
  				else if (o instanceof LogicalPackage) {
  					IPackageFragment[] packages=((LogicalPackage)o).getFragments();
  					for (int j= 0; j < packages.length; j++) {
  						IMemento packageMem= elementMem.createChild(TAG_LOGICAL_PACKAGE);
  						packageMem.putString(TAG_SELECTED_ELEMENT_PATH, packages[j].getHandleIdentifier());
  					}
  				}
  			}
  		}
  	}
  
  	protected void restoreState(IMemento memento) {
  		if (fHasWorkingSetFilter)
  			fWorkingSetFilterActionGroup.restoreState(memento);
  		if (fHasCustomFilter)
  			fCustomFiltersActionGroup.restoreState(memento);
  
  		if (fHasCustomFilter || fHasWorkingSetFilter) {
  			fViewer.getControl().setRedraw(false);
  			fViewer.refresh();
  			fViewer.getControl().setRedraw(true);
  		}
  	}
  
  	private ISelection restoreSelectionState(IMemento memento) {
  		if (memento == null)
  			return null;
  
  		IMemento childMem;
  		childMem= memento.getChild(TAG_SELECTED_ELEMENTS);
  		if (childMem != null) {
  			ArrayList list= new ArrayList();
  			IMemento[] elementMem= childMem.getChildren(TAG_SELECTED_ELEMENT);
  			for (int i= 0; i < elementMem.length; i++) {
  				String javaElementHandle= elementMem[i].getString(TAG_SELECTED_ELEMENT_PATH);
  				if (javaElementHandle == null) {
  					// logical package
  					IMemento[] packagesMem= elementMem[i].getChildren(TAG_LOGICAL_PACKAGE);
  					LogicalPackage lp= null;
  					for (int j= 0; j < packagesMem.length; j++) {
  						javaElementHandle= packagesMem[j].getString(TAG_SELECTED_ELEMENT_PATH);
  						Object pack= JavaScriptCore.create(javaElementHandle);
  						if (pack instanceof IPackageFragment && ((IPackageFragment)pack).exists()) {
  							if (lp == null)
  								lp= new LogicalPackage((IPackageFragment)pack);
  							else
  								lp.add((IPackageFragment)pack);
  						}
  					}
  					if (lp != null)
  						list.add(lp);
  				} else {
  					IJavaScriptElement element= JavaScriptCore.create(javaElementHandle);
  					if (element != null && element.exists())
  						list.add(element);
  				}
  			}
  			return new StructuredSelection(list);
  		}
  		return null;
  	}
  
  	private void restoreLinkingEnabled(IMemento memento) {
  		Integer val= memento.getInteger(getLinkToEditorKey());
  		if (val != null) {
  			fLinkingEnabled= val.intValue() != 0;
  		}
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
  	 */
  	public void createPartControl(Composite parent) {
  		Assert.isTrue(fViewer == null);
  
  
  		fTypeComparator= new JavaElementTypeComparator();
  
  		// Setup viewer
  		fViewer= createViewer(parent);
  
  		initDragAndDrop();
  
  		fLabelProvider= createLabelProvider();
  		fViewer.setLabelProvider(createDecoratingLabelProvider(fLabelProvider));
  
  		fViewer.setComparator(createJavaElementComparator());
  		fViewer.setUseHashlookup(true);
  		fTitleProvider= createTitleProvider();
  
  		createContextMenu();
  		getSite().setSelectionProvider(fViewer);
  
  		if (fMemento != null) { // initialize linking state before creating the actions
  			restoreLinkingEnabled(fMemento);
  		}
  
  		createActions(); // call before registering for selection changes
  		addKeyListener();
  
  		if (fMemento != null)
  			restoreState(fMemento);
  
  		getSite().setSelectionProvider(fViewer);
  
  		// Status line
  		IStatusLineManager slManager= getViewSite().getActionBars().getStatusLineManager();
  		fViewer.addSelectionChangedListener(createStatusBarUpdater(slManager));
  
  
  		hookViewerListeners();
  
  		// Filters
  		addFilters();
  
  		// Initialize viewer input
  		fViewer.setContentProvider(createContentProvider());
  		setInitialInput();
  
  		// Initialize selection
  		setInitialSelection();
  		fMemento= null;
  
  		// Listen to page changes
  		getViewSite().getPage().addPostSelectionListener(this);
  		getViewSite().getPage().addPartListener(fPartListener);
  
  		fillActionBars(getViewSite().getActionBars());
  		
  		setHelp();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
  	 */
  	public Object getAdapter(Class key) {
  		if (key == IShowInSource.class) {
  			return getShowInSource();
  		}
  		if (key == IContextProvider.class)
  			return JavaUIHelp.getHelpContextProvider(this, getHelpContextId());
  
  		return super.getAdapter(key);
  	}
  
  	/**
  	 * Returns the <code>IShowInSource</code> for this view.
  	 * @return returns the <code>IShowInSource</code>
  	 */
  	protected IShowInSource getShowInSource() {
  		return new IShowInSource() {
  			public ShowInContext getShowInContext() {
  				return new ShowInContext(
  					null,
  				getSite().getSelectionProvider().getSelection());
  			}
  		};
  	}
  
  	protected DecoratingJavaLabelProvider createDecoratingLabelProvider(JavaUILabelProvider provider) {
  //		XXX: Work in progress for problem decorator being a workbench decorator//
  //		return new ExcludingDecoratingLabelProvider(provider, decorationMgr, "org.eclipse.wst.jsdt.ui.problem.decorator"); //$NON-NLS-1$
  		return new DecoratingJavaLabelProvider(provider);
  	}
  
  	protected JavaScriptElementComparator createJavaElementComparator() {
  		return new JavaScriptElementComparator();
  	}
  
  	protected StatusBarUpdater createStatusBarUpdater(IStatusLineManager slManager) {
  		return new StatusBarUpdater(slManager);
  	}
  
  	protected void createContextMenu() {
  		MenuManager menuManager= new MenuManager("#PopupMenu"); //$NON-NLS-1$
  		menuManager.setRemoveAllWhenShown(true);
  		menuManager.addMenuListener(this);
  		Menu contextMenu= menuManager.createContextMenu(fViewer.getControl());
  		fViewer.getControl().setMenu(contextMenu);
  		getSite().registerContextMenu(menuManager, fViewer);
  	}
  
  	protected void initDragAndDrop() {
  		int ops= DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
  		// drop
  		Transfer[] dropTransfers= new Transfer[] {
  			LocalSelectionTransfer.getInstance()
  		};
  		TransferDropTargetListener[] dropListeners= new TransferDropTargetListener[] {
  			new SelectionTransferDropAdapter(fViewer)
  		};
  		fViewer.addDropSupport(ops | DND.DROP_DEFAULT, dropTransfers, new DelegatingDropAdapter(dropListeners));
  
  		// Drag
  		Transfer[] dragTransfers= new Transfer[] {
  			LocalSelectionTransfer.getInstance(),
  			ResourceTransfer.getInstance()};
  		TransferDragSourceListener[] dragListeners= new TransferDragSourceListener[] {
  			new SelectionTransferDragAdapter(fViewer),
  			new ResourceTransferDragAdapter(fViewer)
  		};
  		fViewer.addDragSupport(ops, dragTransfers, new JdtViewerDragAdapter(fViewer, dragListeners));
  	}
  
  	protected void fillActionBars(IActionBars actionBars) {
  		IToolBarManager toolBar= actionBars.getToolBarManager();
  		fillToolBar(toolBar);
  
  
  		if (fHasWorkingSetFilter)
  			fWorkingSetFilterActionGroup.fillActionBars(getViewSite().getActionBars());
  
  		actionBars.updateActionBars();
  
  		fActionGroups.fillActionBars(actionBars);
  
  		if (fHasCustomFilter)
  			fCustomFiltersActionGroup.fillActionBars(actionBars);
  
  		IMenuManager menu= actionBars.getMenuManager();
  		menu.add(fToggleLinkingAction);
  	}
  
  	//---- IWorkbenchPart ------------------------------------------------------
  
  
  	public void setFocus() {
  		fViewer.getControl().setFocus();
  	}
  
  	public void dispose() {
  		if (fViewer != null) {
  			getViewSite().getPage().removePostSelectionListener(this);
  			getViewSite().getPage().removePartListener(fPartListener);
  			fViewer= null;
  		}
  		if (fActionGroups != null)
  			fActionGroups.dispose();
  
  		if (fWorkingSetFilterActionGroup != null) {
  			fWorkingSetFilterActionGroup.dispose();
  		}
  
  		super.dispose();
  	}
  
  	/**
  	 * Adds the KeyListener
  	 */
  	protected void addKeyListener() {
  		fViewer.getControl().addKeyListener(new KeyAdapter() {
  			public void keyReleased(KeyEvent event) {
  				handleKeyReleased(event);
  			}
  		});
  	}
  
  	protected void handleKeyReleased(KeyEvent event) {
  		if (event.stateMask != 0)
  			return;
  
  		int key= event.keyCode;
  		if (key == SWT.F5) {
  			IAction action= fBuildActionGroup.getRefreshAction();
  			if (action.isEnabled())
  				action.run();
  		}
  	}
  
  	//---- Adding Action to Toolbar -------------------------------------------
  
  	protected void fillToolBar(IToolBarManager tbm) {
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
  	 */
  	public void menuAboutToShow(IMenuManager menu) {
  		JavaScriptPlugin.createStandardGroups(menu);
  
  		IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection();
  		int size= selection.size();
  		Object element= selection.getFirstElement();
  
  		if (size == 1)
  			addOpenNewWindowAction(menu, element);
  		fActionGroups.setContext(new ActionContext(selection));
  		fActionGroups.fillContextMenu(menu);
  		fActionGroups.setContext(null);
  	}
  
  	private void addOpenNewWindowAction(IMenuManager menu, Object element) {
  		if (element instanceof IJavaScriptElement) {
  			element= ((IJavaScriptElement)element).getResource();
  		}
  		if (!(element instanceof IContainer))
  			return;
  		menu.appendToGroup(
  			IContextMenuConstants.GROUP_OPEN,
  			new PatchedOpenInNewWindowAction(getSite().getWorkbenchWindow(), (IContainer)element));
  	}
  
  	protected void createActions() {
  		fActionGroups= new CompositeActionGroup(new ActionGroup[] {
  				new NewWizardsActionGroup(this.getSite()),
  				fOpenEditorGroup= new OpenEditorActionGroup(this),
  				new OpenViewActionGroup(this),
  				fCCPActionGroup= new CCPActionGroup(this),
  				new GenerateActionGroup(this),
  				new RefactorActionGroup(this),
  				new ImportActionGroup(this),
  				fBuildActionGroup= new BuildActionGroup(this),
  				new JavaSearchActionGroup(this)});
  
  
  		if (fHasWorkingSetFilter) {
  			String viewId= getConfigurationElement().getAttribute("id"); //$NON-NLS-1$
  			Assert.isNotNull(viewId);
  			IPropertyChangeListener workingSetListener= new IPropertyChangeListener() {
  				public void propertyChange(PropertyChangeEvent event) {
  					doWorkingSetChanged(event);
  				}
  			};
  			fWorkingSetFilterActionGroup= new WorkingSetFilterActionGroup(getSite(), workingSetListener);
  			fViewer.addFilter(fWorkingSetFilterActionGroup.getWorkingSetFilter());
  		}
  
  		// Custom filter group
  		if (fHasCustomFilter)
  			fCustomFiltersActionGroup= new CustomFiltersActionGroup(this, fViewer);
  
  		fToggleLinkingAction= new ToggleLinkingAction(this);
  	}
  
  	private void doWorkingSetChanged(PropertyChangeEvent event) {
  		String property= event.getProperty();
  		if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property))
  			updateTitle();
  		else	if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE.equals(property)) {
  			updateTitle();
  			fViewer.getControl().setRedraw(false);
  			fViewer.refresh();
  			fViewer.getControl().setRedraw(true);
  		}
  
  	}
  
  
  	/**
  	 * Returns the shell to use for opening dialogs.
  	 * Used in this class, and in the actions.
  	 * @return returns the shell
  	 */
  	Shell getShell() {
  		return fViewer.getControl().getShell();
  	}
  
  	protected final Display getDisplay() {
  		return fViewer.getControl().getDisplay();
  	}
  
  	/**
  	 * Returns the selection provider.
  	 * @return the selection provider
  	 */
  	ISelectionProvider getSelectionProvider() {
  		return fViewer;
  	}
  
  	/**
  	 * Answers if the given <code>element</code> is a valid
  	 * input for this part.
  	 *
  	 * @param 	element	the object to test
  	 * @return	<code>true</code> if the given element is a valid input
  	 */
  	abstract protected boolean isValidInput(Object element);
  
  	/**
  	 * Answers if the given <code>element</code> is a valid
  	 * element for this part.
  	 *
  	 * @param 	element	the object to test
  	 * @return	<code>true</code> if the given element is a valid element
  	 */
  	protected boolean isValidElement(Object element) {
  		if (!(element instanceof IJavaScriptElement)) {
  			return false;
  		}
  		Object input= getViewer().getInput();
  		if (input == null)
  			return false;
  		if (input instanceof Collection)
  			return ((Collection)input).contains(element);
  		else
  			return input.equals(element);
  
  	}
  
  	private boolean isInputResetBy(Object newInput, Object input, IWorkbenchPart part) {
  		if (newInput == null)
  			return part == fPreviousSelectionProvider;
  
  		if (input instanceof IJavaScriptElement && newInput instanceof IJavaScriptElement)
  			return getTypeComparator().compare(newInput, input)  > 0;
  
  		if((newInput instanceof List) && (part instanceof PackagesView))
  			return true;
  
  		else
  			return false;
  	}
  
  	private boolean isInputResetBy(IWorkbenchPart part) {
  		if (!(part instanceof JavaBrowsingPart))
  			return true;
  		Object thisInput= getViewer().getInput();
  		Object partInput= ((JavaBrowsingPart)part).getViewer().getInput();
  
  		if(thisInput instanceof Collection)
  			thisInput= ((Collection)thisInput).iterator().next();
  
  		if(partInput instanceof Collection)
  			partInput= ((Collection)partInput).iterator().next();
  
  		if (thisInput instanceof IJavaScriptElement && partInput instanceof IJavaScriptElement)
  			return getTypeComparator().compare(partInput, thisInput) > 0;
  		else
  			return true;
  	}
  
  	protected boolean isAncestorOf(Object ancestor, Object element) {
  		if (element instanceof IJavaScriptElement && ancestor instanceof IJavaScriptElement)
  			return !element.equals(ancestor) && internalIsAncestorOf((IJavaScriptElement)ancestor, (IJavaScriptElement)element);
  		return false;
  	}
  
  	private boolean internalIsAncestorOf(IJavaScriptElement ancestor, IJavaScriptElement element) {
  		if (element != null)
  			return element.equals(ancestor) || internalIsAncestorOf(ancestor, element.getParent());
  		else
  			return false;
  	}
  
  	private boolean isSearchResultView(IWorkbenchPart part) {
  		return SearchUtil.isSearchPlugInActivated() && part instanceof ISearchResultViewPart;
  	}
  
  	protected boolean needsToProcessSelectionChanged(IWorkbenchPart part, ISelection selection) {
  		if (!fProcessSelectionEvents || part == this || isSearchResultView(part) || part instanceof AbstractInfoView){
  			if (part == this)
  				fPreviousSelectionProvider= part;
  			return false;
  		}
  		return true;
  	}
  
  	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
  		if (!needsToProcessSelectionChanged(part, selection))
  			return;
  
  		if (fToggleLinkingAction.isChecked() && (part instanceof ITextEditor)) {
  			setSelectionFromEditor(part, selection);
  			return;
  		}
  
  		if (!(selection instanceof IStructuredSelection))
  			return;
  
  		// Set selection
  		Object selectedElement= getSingleElementFromSelection(selection);
  
  		if (selectedElement != null && (part == null || part.equals(fPreviousSelectionProvider)) && selectedElement.equals(fPreviousSelectedElement))
  			return;
  
  		fPreviousSelectedElement= selectedElement;
  
  		Object currentInput= getViewer().getInput();
  		if (selectedElement != null && selectedElement.equals(currentInput)) {
  			IJavaScriptElement elementToSelect= findElementToSelect(selectedElement);
  			if (elementToSelect != null && getTypeComparator().compare(selectedElement, elementToSelect) < 0)
  				setSelection(new StructuredSelection(elementToSelect), true);
  			else if (elementToSelect == null && (this instanceof MembersView)) {
  				setSelection(StructuredSelection.EMPTY, true);
  				fPreviousSelectedElement= StructuredSelection.EMPTY;
  			}
  			fPreviousSelectionProvider= part;
  			return;
  		}
  
  		// Clear input if needed
  		if (part != fPreviousSelectionProvider && selectedElement != null && !selectedElement.equals(currentInput) && isInputResetBy(selectedElement, currentInput, part)) {
  			if (!isAncestorOf(selectedElement, currentInput))
  				setInput(null);
  			fPreviousSelectionProvider= part;
  			return;
  		} else	if (selection.isEmpty() && !isInputResetBy(part)) {
  			fPreviousSelectionProvider= part;
  			return;
  		} else if (selectedElement == null && part == fPreviousSelectionProvider) {
  			setInput(null);
  			fPreviousSelectionProvider= part;
  			return;
  		}
  		fPreviousSelectionProvider= part;
  
  		// Adjust input and set selection and
  		adjustInputAndSetSelection(selectedElement);
  	}
  
  
  	void setHasWorkingSetFilter(boolean state) {
  		fHasWorkingSetFilter= state;
  	}
  
  	void setHasCustomSetFilter(boolean state) {
  		fHasCustomFilter= state;
  	}
  
  	protected Object getInput() {
  		return fViewer.getInput();
  	}
  
  	protected void setInput(Object input) {
  		setViewerInput(input);
  		updateTitle();
  	}
  
  	boolean isLinkingEnabled() {
  		return fLinkingEnabled;
  	}
  
  	private void initLinkingEnabled() {
  		fLinkingEnabled= PreferenceConstants.getPreferenceStore().getBoolean(getLinkToEditorKey());
  	}
  
  	private void setViewerInput(Object input) {
  		fProcessSelectionEvents= false;
  		fViewer.setInput(input);
  		fProcessSelectionEvents= true;
  	}
  
  	void updateTitle() {
  		setTitleToolTip(getToolTipText(fViewer.getInput()));
  	}
  
  	/**
  	 * Returns the tool tip text for the given element.
  	 * @param element the element
  	 * @return the tooltip for the element
  	 */
  	String getToolTipText(Object element) {
  		String result;
  		if (!(element instanceof IResource)) {
  			result= JavaScriptElementLabels.getTextLabel(element, AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS);
  		} else {
  			IPath path= ((IResource) element).getFullPath();
  			if (path.isRoot()) {
  				result= getConfigurationElement().getAttribute("name"); //$NON-NLS-1$
  			} else {
  				result= path.makeRelative().toString();
  			}
  		}
  
  		if (fWorkingSetFilterActionGroup == null || fWorkingSetFilterActionGroup.getWorkingSet() == null)
  			return result;
  
  		IWorkingSet ws= fWorkingSetFilterActionGroup.getWorkingSet();
  		String wsstr= Messages.format(JavaBrowsingMessages.JavaBrowsingPart_toolTip, new String[] { ws.getLabel() });
  		if (result.length() == 0)
  			return wsstr;
  		return Messages.format(JavaBrowsingMessages.JavaBrowsingPart_toolTip2, new String[] { result, ws.getLabel() });
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.ui.part.WorkbenchPart#getTitleToolTip()
  	 */
  	public String getTitleToolTip() {
  		if (fViewer == null)
  			return super.getTitleToolTip();
  		return getToolTipText(fViewer.getInput());
  	}
  
  	protected final StructuredViewer getViewer() {
  		return fViewer;
  	}
  
  	protected final void setViewer(StructuredViewer viewer){
  		fViewer= viewer;
  	}
  
  	protected JavaUILabelProvider createLabelProvider() {
  		return new AppearanceAwareLabelProvider(
  						AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS,
  						AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS | JavaElementImageProvider.SMALL_ICONS
  						);
  	}
  
  	protected ILabelProvider createTitleProvider() {
  		return new JavaScriptElementLabelProvider(JavaScriptElementLabelProvider.SHOW_BASICS | JavaScriptElementLabelProvider.SHOW_SMALL_ICONS);
  	}
  
  	protected final ILabelProvider getLabelProvider() {
  		return fLabelProvider;
  	}
  
  	protected final ILabelProvider getTitleProvider() {
  		return fTitleProvider;
  	}
  
  	/**
  	 * Creates the viewer of this part.
  	 *
  	 * @param parent	the parent for the viewer
  	 * @return the created viewer
  	 */
  	protected StructuredViewer createViewer(Composite parent) {
  		return new ProblemTableViewer(parent, SWT.MULTI);
  	}
  
  	protected int getLabelProviderFlags() {
  		return JavaScriptElementLabelProvider.SHOW_BASICS | JavaScriptElementLabelProvider.SHOW_OVERLAY_ICONS |
  				JavaScriptElementLabelProvider.SHOW_SMALL_ICONS | JavaScriptElementLabelProvider.SHOW_VARIABLE | JavaScriptElementLabelProvider.SHOW_PARAMETERS;
  	}
  
  	/**
  	 * Adds filters the viewer of this part.
  	 */
  	protected void addFilters() {
  		// default is to have no filters
  	}
  
  	/**
  	 * Creates the content provider of this part.
  	 * @return the content provider
  	 */
  	protected IContentProvider createContentProvider() {
  		return new JavaBrowsingContentProvider(true, this);
  	}
  
  	protected void setInitialInput() {
  		// Use the selection, if any
  		ISelection selection= getSite().getPage().getSelection();
  		Object input= getSingleElementFromSelection(selection);
  		if (!(input instanceof IJavaScriptElement)) {
  			// Use the input of the page
  			input= getSite().getPage().getInput();
  			if (!(input instanceof IJavaScriptElement) && input instanceof IAdaptable)
  				input= ((IAdaptable)input).getAdapter(IJavaScriptElement.class);
  		}
  		setInput(findInputForJavaElement((IJavaScriptElement)input));
  	}
  
  	protected void setInitialSelection() {
  		// Use the selection, if any
  		Object input;
  		IWorkbenchPage page= getSite().getPage();
  		ISelection selection= null;
  		if (page != null)
  			selection= page.getSelection();
  		if (selection instanceof ITextSelection) {
  			Object part= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
  			if (part instanceof IEditorPart) {
  				setSelectionFromEditor((IEditorPart)part);
  				if (fViewer.getSelection() != null)
  					return;
  			}
  		}
  
  		// Use saved selection from memento
  		if (selection == null || selection.isEmpty())
  			selection= restoreSelectionState(fMemento);
  
  		if (selection == null || selection.isEmpty()) {
  			// Use the input of the page
  			input= getSite().getPage().getInput();
  			if (!(input instanceof IJavaScriptElement)) {
  				if (input instanceof IAdaptable)
  					input= ((IAdaptable)input).getAdapter(IJavaScriptElement.class);
  				else
  					return;
  			}
  			selection= new StructuredSelection(input);
  		}
  		selectionChanged(null, selection);
  	}
  
  	protected final void setHelp() {
  		JavaUIHelp.setHelp(fViewer, getHelpContextId());
  	}
  
  	/**
  	 * Returns the context ID for the Help system
  	 *
  	 * @return	the string used as ID for the Help context
  	 */
  	abstract protected String getHelpContextId();
  
  	/**
  	 * Returns the preference key for the link to editor setting.
  	 *
  	 * @return	the string used as key into the preference store
  	 */
  	abstract protected String getLinkToEditorKey();
  
  	/**
  	 * Adds additional listeners to this view.
  	 * This method can be overridden but should
  	 * call super.
  	 */
  	protected void hookViewerListeners() {
  		fViewer.addPostSelectionChangedListener(new ISelectionChangedListener() {
  			public void selectionChanged(SelectionChangedEvent event) {
  				if (!fProcessSelectionEvents)
  					return;
  
  				fPreviousSelectedElement= getSingleElementFromSelection(event.getSelection());
  
  				IWorkbenchPage page= getSite().getPage();
  				if (page == null)
  					return;
  
  				if (page.equals(JavaScriptPlugin.getActivePage()) && JavaBrowsingPart.this.equals(page.getActivePart())) {
  					linkToEditor((IStructuredSelection)event.getSelection());
  				}
  			}
  		});
  
  		fViewer.addOpenListener(new IOpenListener() {
  			public void open(OpenEvent event) {
  				IAction open= fOpenEditorGroup.getOpenAction();
  				if (open.isEnabled()) {
  					open.run();
  					restoreSelection();
  				}
  			}
  		});
  	}
  
  	void restoreSelection() {
  		// Default is to do nothing
  	}
  
  	void adjustInputAndSetSelection(Object o) {
  		if (!(o instanceof IJavaScriptElement)) {
  			if (o == null)
  				setInput(null);
  			setSelection(StructuredSelection.EMPTY, true);
  			return;
  		}
  
  		IJavaScriptElement je= (IJavaScriptElement)o;
  		IJavaScriptElement elementToSelect= findElementToSelect(je);
  		IJavaScriptElement newInput= findInputForJavaElement(je);
  		IJavaScriptElement oldInput= null;
  		if (getInput() instanceof IJavaScriptElement)
  			oldInput= (IJavaScriptElement)getInput();
  
  		if (elementToSelect == null && !isValidInput(newInput) && (newInput == null && !isAncestorOf(je, oldInput)))
  			// Clear input
  			setInput(null);
  		else if (mustSetNewInput(elementToSelect, oldInput, newInput)) {
  			// Adjust input to selection
  			setInput(newInput);
  		}
  
  		if (elementToSelect != null && elementToSelect.exists())
  			setSelection(new StructuredSelection(elementToSelect), true);
  		else
  			setSelection(StructuredSelection.EMPTY, true);
  	}
  
  	/**
  	 * Compute if a new input must be set.
  	 * 
  	 * @param elementToSelect the element to select 
  	 * @param oldInput old input
  	 * @param newInput new input
  	 * @return	<code>true</code> if the input has to be set
  	 * 
  	 */
  	private boolean mustSetNewInput(IJavaScriptElement elementToSelect, IJavaScriptElement oldInput, IJavaScriptElement newInput) {
  		return (newInput == null || !newInput.equals(oldInput))
  			&& (elementToSelect == null
  				|| oldInput == null);
  	}
  
  	/**
  	 * Finds the closest Java element which can be used as input for
  	 * this part and has the given Java element as child
  	 *
  	 * @param 	je 	the Java element for which to search the closest input
  	 * @return	the closest Java element used as input for this part
  	 */
  	protected IJavaScriptElement findInputForJavaElement(IJavaScriptElement je) {
  		if (je == null || !je.exists())
  			return null;
  		if (isValidInput(je))
  			return je;
  		return findInputForJavaElement(je.getParent());
  	}
  
  	protected final IJavaScriptElement findElementToSelect(Object obj) {
  		if (obj instanceof IJavaScriptElement)
  			return findElementToSelect((IJavaScriptElement)obj);
  		return null;
  	}
  
  	/**
  	 * Finds the element which has to be selected in this part.
  	 *
  	 * @param je	the Java element which has the focus
  	 * @return returns the element to select
  	 */
  	abstract protected IJavaScriptElement findElementToSelect(IJavaScriptElement je);
  
  
  	protected final Object getSingleElementFromSelection(ISelection selection) {
  		if (!(selection instanceof IStructuredSelection) || selection.isEmpty())
  			return null;
  
  		Iterator iter= ((IStructuredSelection)selection).iterator();
  		Object firstElement= iter.next();
  		if (!(firstElement instanceof IJavaScriptElement)) {
  			if (firstElement instanceof IMarker)
  				firstElement= ((IMarker)firstElement).getResource();
  			if (firstElement instanceof IAdaptable) {
  				IJavaScriptElement je= (IJavaScriptElement)((IAdaptable)firstElement).getAdapter(IJavaScriptElement.class);
  				if (je == null && firstElement instanceof IFile) {
  					IContainer parent= ((IFile)firstElement).getParent();
  					if (parent != null)
  						return parent.getAdapter(IJavaScriptElement.class);
  					else return null;
  				} else
  					return je;
  
  			} else
  				return firstElement;
  		}
  		Object currentInput= getViewer().getInput();
  		if (currentInput == null || !currentInput.equals(findInputForJavaElement((IJavaScriptElement)firstElement)))
  			if (iter.hasNext())
  				// multi-selection and view is empty
  				return null;
  			else
  				// OK: single selection and view is empty
  				return firstElement;
  
  		// be nice to multi-selection
  		while (iter.hasNext()) {
  			Object element= iter.next();
  			if (!(element instanceof IJavaScriptElement))
  				return null;
  			if (!currentInput.equals(findInputForJavaElement((IJavaScriptElement)element)))
  				return null;
  		}
  		return firstElement;
  	}
  
  	/**
  	 * Gets the typeComparator.
  	 * @return Returns a JavaElementTypeComparator
  	 */
  	protected Comparator getTypeComparator() {
  		return fTypeComparator;
  	}
  
  	/**
  	 * Links to editor (if option enabled)
  	 * @param selection the selection
  	 */
  	private void linkToEditor(IStructuredSelection selection) {
  		Object obj= selection.getFirstElement();
  
  		if (selection.size() == 1) {
  			IEditorPart part= EditorUtility.isOpenInEditor(obj);
  			if (part != null) {
  				IWorkbenchPage page= getSite().getPage();
  				page.bringToTop(part);
  				if (obj instanceof IJavaScriptElement)
  					EditorUtility.revealInEditor(part, (IJavaScriptElement) obj);
  			}
  		}
  	}
  
  	void setSelectionFromEditor(IWorkbenchPart part) {
  		if (!fProcessSelectionEvents || !linkBrowsingViewSelectionToEditor() || !(part instanceof IEditorPart))
  			return;
  		
  		IWorkbenchPartSite site= part.getSite();
  		if (site == null)
  			return;
  		ISelectionProvider provider= site.getSelectionProvider();
  		if (provider != null)
  			setSelectionFromEditor(part, provider.getSelection());
  	}
  
  	private void setSelectionFromEditor(IWorkbenchPart part, ISelection selection) {
  		if (part instanceof IEditorPart) {
  			IJavaScriptElement element= null;
  			if (selection instanceof IStructuredSelection) {
  				Object obj= getSingleElementFromSelection(selection);
  				if (obj instanceof IJavaScriptElement)
  					element= (IJavaScriptElement)obj;
  			}
  			IEditorInput ei= ((IEditorPart)part).getEditorInput();
  			if (selection instanceof ITextSelection) {
  				int offset= ((ITextSelection)selection).getOffset();
  				element= getElementAt(ei, offset);
  			}
  			if (element != null) {
  				adjustInputAndSetSelection(element);
  				return;
  			}
  			if (ei instanceof IFileEditorInput) {
  				IFile file= ((IFileEditorInput)ei).getFile();
  				IJavaScriptElement je= (IJavaScriptElement)file.getAdapter(IJavaScriptElement.class);
  				if (je == null) {
  					IContainer container= ((IFileEditorInput)ei).getFile().getParent();
  					if (container != null)
  						je= (IJavaScriptElement)container.getAdapter(IJavaScriptElement.class);
  				}
  				if (je == null) {
  					setSelection(null, false);
  					return;
  				}
  				adjustInputAndSetSelection(je);
  			} else if (ei instanceof IClassFileEditorInput) {
  				IClassFile cf= ((IClassFileEditorInput)ei).getClassFile();
  				adjustInputAndSetSelection(cf);
  			}
  		}
  	}
  
  	/**
  	 * Returns the element contained in the EditorInput
  	 * @param input the editor input
  	 * @return the input element
  	 */
  	Object getElementOfInput(IEditorInput input) {
  		if (input instanceof IFileEditorInput)
  			return ((IFileEditorInput)input).getFile();
  		if (input != null)
  			return JavaScriptUI.getEditorInputJavaElement(input);
  		return null;
  	}
  
  	void setSelection(ISelection selection, boolean reveal) {
  		if (selection != null && selection.equals(fViewer.getSelection()))
  			return;
  		fProcessSelectionEvents= false;
  		fViewer.setSelection(selection, reveal);
  		fProcessSelectionEvents= true;
  	}
  
  	/**
  	 * @param input the editor input
  	 * @param offset the offset in the file
  	 * @return the element at the given offset
  	 */
  	protected IJavaScriptElement getElementAt(IEditorInput input, int offset) {
  		if (input instanceof IClassFileEditorInput) {
  			try {
  				return ((IClassFileEditorInput)input).getClassFile().getElementAt(offset);
  			} catch (JavaScriptModelException ex) {
  				return null;
  			}
  		}
  
  		IWorkingCopyManager manager= JavaScriptPlugin.getDefault().getWorkingCopyManager();
  		IJavaScriptUnit unit= manager.getWorkingCopy(input);
  		if (unit != null)
  			try {
  				if (unit.isConsistent())
  					return unit.getElementAt(offset);
  				else {
  					/*
  					 * XXX: We should set the selection later when the
  					 *      CU is reconciled.
  					 *      see https://bugs.eclipse.org/bugs/show_bug.cgi?id=51290
  					 */
  				}
  			} catch (JavaScriptModelException ex) {
  				// fall through
  			}
  		return null;
  	}
  
  	protected IType getTypeForCU(IJavaScriptUnit cu) {
  		// Use primary type if possible
  		IType primaryType= cu.findPrimaryType();
  		if (primaryType != null)
  			return primaryType;
  
  		// Use first top-level type
  		try {
  			IType[] types= cu.getTypes();
  			if (types.length > 0)
  				return types[0];
  			else
  				return null;
  		} catch (JavaScriptModelException ex) {
  			return null;
  		}
  	}
  
  	void setProcessSelectionEvents(boolean state) {
  		fProcessSelectionEvents= state;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
  	 */
  	public Object getViewPartInput() {
  		if (fViewer != null) {
  			return fViewer.getInput();
  		}
  		return null;
  	}
  
  	protected void setActionGroups(CompositeActionGroup actionGroups) {
  		fActionGroups= actionGroups;
  	}
  
  	protected void setBuildActionGroup(BuildActionGroup actionGroup) {
  		fBuildActionGroup= actionGroup;
  	}
  
  	protected void setCCPActionGroup(CCPActionGroup actionGroup) {
  		fCCPActionGroup= actionGroup;
  	}
  
  	protected void setCustomFiltersActionGroup(CustomFiltersActionGroup customFiltersActionGroup) {
  		fCustomFiltersActionGroup= customFiltersActionGroup;
  	}
  
  	protected boolean hasCustomFilter() {
  		return fHasCustomFilter;
  	}
  
  	protected boolean hasWorkingSetFilter() {
  		return fHasWorkingSetFilter;
  	}
  
  	protected void setOpenEditorGroup(OpenEditorActionGroup openEditorGroup) {
  		fOpenEditorGroup= openEditorGroup;
  	}
  
  	protected OpenEditorActionGroup getOpenEditorGroup() {
  		return fOpenEditorGroup;
  	}
  
  	protected BuildActionGroup getBuildActionGroup() {
  		return fBuildActionGroup;
  	}
  
  	protected CCPActionGroup getCCPActionGroup() {
  		return fCCPActionGroup;
  	}
  
  	private boolean linkBrowsingViewSelectionToEditor() {
  		return isLinkingEnabled();
  	}
  
  	public void setLinkingEnabled(boolean enabled) {
  		fLinkingEnabled= enabled;
  		PreferenceConstants.getPreferenceStore().setValue(getLinkToEditorKey(), enabled);
  		if (enabled) {
  			IEditorPart editor = getSite().getPage().getActiveEditor();
  			if (editor != null) {
  				setSelectionFromEditor(editor);
  			}
  		}
  	}
  
  }
  