content: /*******************************************************************************
   * Copyright (c) 2000, 2011 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
   *     Tom Eicher (Avaloq Evolution AG) - block selection mode
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.ui.javaeditor;
  
  import java.text.CharacterIterator;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import org.eclipse.core.commands.operations.IOperationApprover;
  import org.eclipse.core.commands.operations.IUndoContext;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.resources.ProjectScope;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.ListenerList;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.Job;
  import org.eclipse.core.runtime.preferences.IEclipsePreferences;
  import org.eclipse.core.runtime.preferences.IScopeContext;
  import org.eclipse.help.IContextProvider;
  import org.eclipse.jface.action.Action;
  import org.eclipse.jface.action.GroupMarker;
  import org.eclipse.jface.action.IAction;
  import org.eclipse.jface.action.IMenuManager;
  import org.eclipse.jface.action.MenuManager;
  import org.eclipse.jface.preference.IPreferenceStore;
  import org.eclipse.jface.text.BadLocationException;
  import org.eclipse.jface.text.DocumentEvent;
  import org.eclipse.jface.text.IDocument;
  import org.eclipse.jface.text.IDocumentExtension4;
  import org.eclipse.jface.text.IDocumentListener;
  import org.eclipse.jface.text.IInformationControl;
  import org.eclipse.jface.text.IInformationControlCreator;
  import org.eclipse.jface.text.IRegion;
  import org.eclipse.jface.text.ISelectionValidator;
  import org.eclipse.jface.text.ISynchronizable;
  import org.eclipse.jface.text.ITextHover;
  import org.eclipse.jface.text.ITextInputListener;
  import org.eclipse.jface.text.ITextOperationTarget;
  import org.eclipse.jface.text.ITextSelection;
  import org.eclipse.jface.text.ITextViewer;
  import org.eclipse.jface.text.ITextViewerExtension2;
  import org.eclipse.jface.text.ITextViewerExtension5;
  import org.eclipse.jface.text.Position;
  import org.eclipse.jface.text.Region;
  import org.eclipse.jface.text.TextUtilities;
  import org.eclipse.jface.text.link.LinkedModeModel;
  import org.eclipse.jface.text.link.LinkedPosition;
  import org.eclipse.jface.text.reconciler.IReconciler;
  import org.eclipse.jface.text.source.Annotation;
  import org.eclipse.jface.text.source.AnnotationRulerColumn;
  import org.eclipse.jface.text.source.CompositeRuler;
  import org.eclipse.jface.text.source.IAnnotationModel;
  import org.eclipse.jface.text.source.IAnnotationModelExtension;
  import org.eclipse.jface.text.source.ICharacterPairMatcher;
  import org.eclipse.jface.text.source.IOverviewRuler;
  import org.eclipse.jface.text.source.ISourceViewer;
  import org.eclipse.jface.text.source.ISourceViewerExtension2;
  import org.eclipse.jface.text.source.IVerticalRuler;
  import org.eclipse.jface.text.source.IVerticalRulerColumn;
  import org.eclipse.jface.text.source.LineChangeHover;
  import org.eclipse.jface.text.source.SourceViewerConfiguration;
  import org.eclipse.jface.text.source.projection.ProjectionSupport;
  import org.eclipse.jface.text.source.projection.ProjectionViewer;
  import org.eclipse.jface.util.IPropertyChangeListener;
  import org.eclipse.jface.util.PropertyChangeEvent;
  import org.eclipse.jface.viewers.DoubleClickEvent;
  import org.eclipse.jface.viewers.IDoubleClickListener;
  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.SelectionChangedEvent;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.ST;
  import org.eclipse.swt.custom.StyledText;
  import org.eclipse.swt.graphics.Image;
  import org.eclipse.swt.graphics.Point;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.ui.IEditorInput;
  import org.eclipse.ui.IEditorPart;
  import org.eclipse.ui.IPageLayout;
  import org.eclipse.ui.IPartListener2;
  import org.eclipse.ui.IPartService;
  import org.eclipse.ui.ISelectionListener;
  import org.eclipse.ui.IWindowListener;
  import org.eclipse.ui.IWorkbenchPage;
  import org.eclipse.ui.IWorkbenchPart;
  import org.eclipse.ui.IWorkbenchPartReference;
  import org.eclipse.ui.IWorkbenchPartSite;
  import org.eclipse.ui.IWorkbenchWindow;
  import org.eclipse.ui.PlatformUI;
  import org.eclipse.ui.actions.ActionContext;
  import org.eclipse.ui.actions.ActionGroup;
  import org.eclipse.ui.editors.text.DefaultEncodingSupport;
  import org.eclipse.ui.editors.text.EditorsUI;
  import org.eclipse.ui.editors.text.IEncodingSupport;
  import org.eclipse.ui.operations.NonLocalUndoUserApprover;
  import org.eclipse.ui.part.IShowInSource;
  import org.eclipse.ui.part.IShowInTargetList;
  import org.eclipse.ui.part.ShowInContext;
  import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
  import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
  import org.eclipse.ui.texteditor.AnnotationPreference;
  import org.eclipse.ui.texteditor.ChainedPreferenceStore;
  import org.eclipse.ui.texteditor.IDocumentProvider;
  import org.eclipse.ui.texteditor.ITextEditorActionConstants;
  import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
  import org.eclipse.ui.texteditor.IUpdate;
  import org.eclipse.ui.texteditor.MarkerAnnotation;
  import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
  import org.eclipse.ui.texteditor.TextNavigationAction;
  import org.eclipse.ui.texteditor.TextOperationAction;
  import org.eclipse.ui.views.contentoutline.ContentOutline;
  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
  import org.eclipse.wst.jsdt.core.IClassFile;
  import org.eclipse.wst.jsdt.core.IImportContainer;
  import org.eclipse.wst.jsdt.core.IImportDeclaration;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.ILocalVariable;
  import org.eclipse.wst.jsdt.core.IMember;
  import org.eclipse.wst.jsdt.core.ISourceRange;
  import org.eclipse.wst.jsdt.core.ISourceReference;
  import org.eclipse.wst.jsdt.core.JavaScriptCore;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.ASTNode;
  import org.eclipse.wst.jsdt.core.dom.IBinding;
  import org.eclipse.wst.jsdt.core.dom.IVariableBinding;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.core.dom.Name;
  import org.eclipse.wst.jsdt.core.formatter.DefaultCodeFormatterConstants;
  import org.eclipse.wst.jsdt.core.util.IModifierConstants;
  import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder;
  import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds;
  import org.eclipse.wst.jsdt.internal.ui.IProductConstants;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.ProductProperties;
  import org.eclipse.wst.jsdt.internal.ui.actions.CompositeActionGroup;
  import org.eclipse.wst.jsdt.internal.ui.actions.CopyQualifiedNameAction;
  import org.eclipse.wst.jsdt.internal.ui.actions.FoldingActionGroup;
  import org.eclipse.wst.jsdt.internal.ui.actions.SelectionConverter;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.GoToNextPreviousMemberAction;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.SelectionHistory;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectEnclosingAction;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectHistoryAction;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectNextAction;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectPreviousAction;
  import org.eclipse.wst.jsdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction;
  import org.eclipse.wst.jsdt.internal.ui.search.BreakContinueTargetFinder;
  import org.eclipse.wst.jsdt.internal.ui.search.ExceptionOccurrencesFinder;
  import org.eclipse.wst.jsdt.internal.ui.search.ImplementOccurrencesFinder;
  import org.eclipse.wst.jsdt.internal.ui.search.MethodExitsFinder;
  import org.eclipse.wst.jsdt.internal.ui.search.OccurrencesFinder;
  import org.eclipse.wst.jsdt.internal.ui.text.DocumentCharacterIterator;
  import org.eclipse.wst.jsdt.internal.ui.text.JavaChangeHover;
  import org.eclipse.wst.jsdt.internal.ui.text.JavaPairMatcher;
  import org.eclipse.wst.jsdt.internal.ui.text.JavaWordFinder;
  import org.eclipse.wst.jsdt.internal.ui.text.JavaWordIterator;
  import org.eclipse.wst.jsdt.internal.ui.text.PreferencesAdapter;
  import org.eclipse.wst.jsdt.internal.ui.text.java.hover.JavaExpandHover;
  import org.eclipse.wst.jsdt.internal.ui.text.java.hover.SourceViewerInformationControl;
  import org.eclipse.wst.jsdt.internal.ui.util.JavaUIHelp;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.ISelectionListenerWithAST;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.IViewPartInputProvider;
  import org.eclipse.wst.jsdt.internal.ui.viewsupport.SelectionListenerWithASTManager;
  import org.eclipse.wst.jsdt.ui.IContextMenuConstants;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  import org.eclipse.wst.jsdt.ui.PreferenceConstants;
  import org.eclipse.wst.jsdt.ui.actions.IJavaEditorActionDefinitionIds;
  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.ShowInPackageViewAction;
  import org.eclipse.wst.jsdt.ui.text.IJavaScriptPartitions;
  import org.eclipse.wst.jsdt.ui.text.JavaScriptSourceViewerConfiguration;
  import org.eclipse.wst.jsdt.ui.text.JavaScriptTextTools;
  import org.eclipse.wst.jsdt.ui.text.folding.IJavaFoldingStructureProvider;
  import org.eclipse.wst.jsdt.ui.text.folding.IJavaFoldingStructureProviderExtension;
  import org.osgi.service.prefs.BackingStoreException;
  
  import com.ibm.icu.text.BreakIterator;
  
  /**
   * Java specific text editor.
   */
  public abstract class JavaEditor extends AbstractDecoratedTextEditor implements IViewPartInputProvider {
  
  	/**
  	 * Internal implementation class for a change listener.
  	 * 
  	 */
  	protected abstract class AbstractSelectionChangedListener implements ISelectionChangedListener  {
  
  		/**
  		 * Installs this selection changed listener with the given selection provider. If
  		 * the selection provider is a post selection provider, post selection changed
  		 * events are the preferred choice, otherwise normal selection changed events
  		 * are requested.
  		 *
  		 * @param selectionProvider
  		 */
  		public void install(ISelectionProvider selectionProvider) {
  			if (selectionProvider == null)
  				return;
  
  			if (selectionProvider instanceof IPostSelectionProvider)  {
  				IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider;
  				provider.addPostSelectionChangedListener(this);
  			} else  {
  				selectionProvider.addSelectionChangedListener(this);
  			}
  		}
  
  		/**
  		 * Removes this selection changed listener from the given selection provider.
  		 *
  		 * @param selectionProvider the selection provider
  		 */
  		public void uninstall(ISelectionProvider selectionProvider) {
  			if (selectionProvider == null)
  				return;
  
  			if (selectionProvider instanceof IPostSelectionProvider)  {
  				IPostSelectionProvider provider= (IPostSelectionProvider) selectionProvider;
  				provider.removePostSelectionChangedListener(this);
  			} else  {
  				selectionProvider.removeSelectionChangedListener(this);
  			}
  		}
  	}
  
  	/**
  	 * Updates the Java outline page selection and this editor's range indicator.
  	 *
  	 * 
  	 */
  	private class EditorSelectionChangedListener extends AbstractSelectionChangedListener {
  
  		/*
  		 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
  		 */
  		public void selectionChanged(SelectionChangedEvent event) {
  			// XXX: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=56161
  			JavaEditor.this.selectionChanged();
  		}
  	}
  
  	/**
  	 * Updates the selection in the editor's widget with the selection of the outline page.
  	 */
  	class OutlineSelectionChangedListener  extends AbstractSelectionChangedListener {
  		public void selectionChanged(SelectionChangedEvent event) {
  			doSelectionChanged(event);
  		}
  	}
  
  
  	/**
  	 * Adapts an options {@link IEclipsePreferences} to {@link org.eclipse.jface.preference.IPreferenceStore}.
  	 * <p>
  	 * This preference store is read-only i.e. write access
  	 * throws an {@link java.lang.UnsupportedOperationException}.
  	 * </p>
  	 *
  	 * 
  	 */
  	private static class EclipsePreferencesAdapter implements IPreferenceStore {
  
  		/**
  		 * Preference change listener. Listens for events preferences
  		 * fires a {@link org.eclipse.jface.util.PropertyChangeEvent}
  		 * on this adapter with arguments from the received event.
  		 */
  		private class PreferenceChangeListener implements IEclipsePreferences.IPreferenceChangeListener {
  
  			/**
  			 * {@inheritDoc}
  			 */
  			public void preferenceChange(final IEclipsePreferences.PreferenceChangeEvent event) {
  				if (Display.getCurrent() == null) {
  					Display.getDefault().asyncExec(new Runnable() {
  						public void run() {
  							firePropertyChangeEvent(event.getKey(), event.getOldValue(), event.getNewValue());
  						}
  					});
  				} else {
  					firePropertyChangeEvent(event.getKey(), event.getOldValue(), event.getNewValue());
  				}
  			}
  		}
  
  		/** Listeners on on this adapter */
  		private ListenerList fListeners= new ListenerList(ListenerList.IDENTITY);
  
  		/** Listener on the node */
  		private IEclipsePreferences.IPreferenceChangeListener fListener= new PreferenceChangeListener();
  
  		/** wrapped node */
  		private final IScopeContext fContext;
  		private final String fQualifier;
  
  		/**
  		 * Initialize with the node to wrap
  		 *
  		 * @param context the context to access
  		 * @param qualifier the qualifier
  		 */
  		public EclipsePreferencesAdapter(IScopeContext context, String qualifier) {
  			fContext= context;
  			fQualifier= qualifier;
  		}
  
  		private IEclipsePreferences getNode() {
  			return fContext.getNode(fQualifier);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void addPropertyChangeListener(IPropertyChangeListener listener) {
  			if (fListeners.size() == 0)
  				getNode().addPreferenceChangeListener(fListener);
  			fListeners.add(listener);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void removePropertyChangeListener(IPropertyChangeListener listener) {
  			fListeners.remove(listener);
  			if (fListeners.size() == 0) {
  				getNode().removePreferenceChangeListener(fListener);
  			}
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public boolean contains(String name) {
  			return getNode().get(name, null) != null;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) {
  			PropertyChangeEvent event= new PropertyChangeEvent(this, name, oldValue, newValue);
  			Object[] listeners= fListeners.getListeners();
  			for (int i= 0; i < listeners.length; i++)
  				((IPropertyChangeListener) listeners[i]).propertyChange(event);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public boolean getBoolean(String name) {
  			return getNode().getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public boolean getDefaultBoolean(String name) {
  			return BOOLEAN_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public double getDefaultDouble(String name) {
  			return DOUBLE_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public float getDefaultFloat(String name) {
  			return FLOAT_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public int getDefaultInt(String name) {
  			return INT_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public long getDefaultLong(String name) {
  			return LONG_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public String getDefaultString(String name) {
  			return STRING_DEFAULT_DEFAULT;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public double getDouble(String name) {
  			return getNode().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public float getFloat(String name) {
  			return getNode().getFloat(name, FLOAT_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public int getInt(String name) {
  			return getNode().getInt(name, INT_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public long getLong(String name) {
  			return getNode().getLong(name, LONG_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public String getString(String name) {
  			return getNode().get(name, STRING_DEFAULT_DEFAULT);
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public boolean isDefault(String name) {
  			return false;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public boolean needsSaving() {
  			try {
  				return getNode().keys().length > 0;
  			} catch (BackingStoreException e) {
  				// ignore
  			}
  			return true;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void putValue(String name, String value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, double value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, float value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, int value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, long value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, String defaultObject) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setDefault(String name, boolean value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setToDefault(String name) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, double value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, float value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, int value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, long value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, String value) {
  			throw new UnsupportedOperationException();
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public void setValue(String name, boolean value) {
  			throw new UnsupportedOperationException();
  		}
  
  	}
  
  
  	/**
  	 * Cancels the occurrences finder job upon document changes.
  	 *
  	 * 
  	 */
  	class OccurrencesFinderJobCanceler implements IDocumentListener, ITextInputListener {
  
  		public void install() {
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer == null)
  				return;
  
  			StyledText text= sourceViewer.getTextWidget();
  			if (text == null || text.isDisposed())
  				return;
  
  			sourceViewer.addTextInputListener(this);
  
  			IDocument document= sourceViewer.getDocument();
  			if (document != null)
  				document.addDocumentListener(this);
  		}
  
  		public void uninstall() {
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer != null)
  				sourceViewer.removeTextInputListener(this);
  
  			IDocumentProvider documentProvider= getDocumentProvider();
  			if (documentProvider != null) {
  				IDocument document= documentProvider.getDocument(getEditorInput());
  				if (document != null)
  					document.removeDocumentListener(this);
  			}
  		}
  
  
  		/*
  		 * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
  		 */
  		public void documentAboutToBeChanged(DocumentEvent event) {
  			if (fOccurrencesFinderJob != null)
  				fOccurrencesFinderJob.doCancel();
  		}
  
  		/*
  		 * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
  		 */
  		public void documentChanged(DocumentEvent event) {
  		}
  
  		/*
  		 * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
  		 */
  		public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
  			if (oldInput == null)
  				return;
  
  			oldInput.removeDocumentListener(this);
  		}
  
  		/*
  		 * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
  		 */
  		public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
  			if (newInput == null)
  				return;
  			newInput.addDocumentListener(this);
  		}
  	}
  
  	/**
  	 * This action implements smart home.
  	 *
  	 * Instead of going to the start of a line it does the following:
  	 *
  	 * - if smart home/end is enabled and the caret is after the line's first non-whitespace then the caret is moved directly before it, taking JavaDoc and multi-line comments into account.
  	 * - if the caret is before the line's first non-whitespace the caret is moved to the beginning of the line
  	 * - if the caret is at the beginning of the line see first case.
  	 *
  	 * 
  	 */
  	protected class SmartLineStartAction extends LineStartAction {
  
  		/**
  		 * Creates a new smart line start action
  		 *
  		 * @param textWidget the styled text widget
  		 * @param doSelect a boolean flag which tells if the text up to the beginning of the line should be selected
  		 */
  		public SmartLineStartAction(final StyledText textWidget, final boolean doSelect) {
  			super(textWidget, doSelect);
  		}
  
  		/*
  		 * @see org.eclipse.ui.texteditor.AbstractTextEditor.LineStartAction#getLineStartPosition(java.lang.String, int, java.lang.String)
  		 */
  		protected int getLineStartPosition(final IDocument document, final String line, final int length, final int offset) {
  
  			String type= IDocument.DEFAULT_CONTENT_TYPE;
  			try {
  				type= TextUtilities.getContentType(document, IJavaScriptPartitions.JAVA_PARTITIONING, offset, true);
  			} catch (BadLocationException exception) {
  				// Should not happen
  			}
  
  			int index= super.getLineStartPosition(document, line, length, offset);
  			if (type.equals(IJavaScriptPartitions.JAVA_DOC) || type.equals(IJavaScriptPartitions.JAVA_MULTI_LINE_COMMENT)) {
  				if (index < length - 1 && line.charAt(index) == '*' && line.charAt(index + 1) != '/') {
  					do {
  						++index;
  					} while (index < length && Character.isWhitespace(line.charAt(index)));
  				}
  			} else {
  				if (index < length - 1 && line.charAt(index) == '/' && line.charAt(index + 1) == '/') {
  					index++;
  					do {
  						++index;
  					} while (index < length && Character.isWhitespace(line.charAt(index)));
  				}
  			}
  			return index;
  		}
  	}
  
  	/**
  	 * Text navigation action to navigate to the next sub-word.
  	 *
  	 * 
  	 */
  	protected abstract class NextSubWordAction extends TextNavigationAction {
  
  		protected JavaWordIterator fIterator= new JavaWordIterator();
  
  		/**
  		 * Creates a new next sub-word action.
  		 *
  		 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
  		 */
  		protected NextSubWordAction(int code) {
  			super(getSourceViewer().getTextWidget(), code);
  		}
  
  		/*
  		 * @see org.eclipse.jface.action.IAction#run()
  		 */
  		public void run() {
  			// Check whether we are in a java code partition and the preference is enabled
  			final IPreferenceStore store= getPreferenceStore();
  			if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
  				super.run();
  				return;
  			}
  
  			final ISourceViewer viewer= getSourceViewer();
  			final IDocument document= viewer.getDocument();
  			fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
  			int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
  			if (position == -1)
  				return;
  
  			int next= findNextPosition(position);
  			try {
  				if (isBlockSelectionModeEnabled() && document.getLineOfOffset(next) != document.getLineOfOffset(position)) {
  					super.run(); // may navigate into virtual white space
  				} else if (next != BreakIterator.DONE) {
  					setCaretPosition(next);
  					getTextWidget().showSelection();
  					fireSelectionChanged();
  				}
  			} catch (BadLocationException x) {
  				// ignore
  			}
  		}
  
  		/**
  		 * Finds the next position after the given position.
  		 *
  		 * @param position the current position
  		 * @return the next position
  		 */
  		protected int findNextPosition(int position) {
  			ISourceViewer viewer= getSourceViewer();
  			int widget= -1;
  			int next= position;
  			while (next != BreakIterator.DONE && widget == -1) { // TODO: optimize
  				next= fIterator.following(next);
  				if (next != BreakIterator.DONE)
  					widget= modelOffset2WidgetOffset(viewer, next);
  			}
  			
  			IDocument document= viewer.getDocument();
  			LinkedModeModel model= LinkedModeModel.getModel(document, position);
  			if (model != null) {
  				LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
  				if (linkedPosition != null) {
  					int linkedPositionEnd= linkedPosition.getOffset() + linkedPosition.getLength();
  					if (position != linkedPositionEnd && linkedPositionEnd < next)
  						next= linkedPositionEnd;
  				} else {
  					LinkedPosition nextLinkedPosition= model.findPosition(new LinkedPosition(document, next, 0));
  					if (nextLinkedPosition != null) {
  						int nextLinkedPositionOffset= nextLinkedPosition.getOffset();
  						if (position != nextLinkedPositionOffset && nextLinkedPositionOffset < next)
  							next= nextLinkedPositionOffset;
  					}
  				}
  			}
  			
  			return next;
  		}
  
  		/**
  		 * Sets the caret position to the sub-word boundary given with <code>position</code>.
  		 *
  		 * @param position Position where the action should move the caret
  		 */
  		protected abstract void setCaretPosition(int position);
  	}
  
  	/**
  	 * Text navigation action to navigate to the next sub-word.
  	 *
  	 * 
  	 */
  	protected class NavigateNextSubWordAction extends NextSubWordAction {
  
  		/**
  		 * Creates a new navigate next sub-word action.
  		 */
  		public NavigateNextSubWordAction() {
  			super(ST.WORD_NEXT);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(final int position) {
  			getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
  		}
  	}
  
  	/**
  	 * Text operation action to delete the next sub-word.
  	 *
  	 * 
  	 */
  	protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
  
  		/**
  		 * Creates a new delete next sub-word action.
  		 */
  		public DeleteNextSubWordAction() {
  			super(ST.DELETE_WORD_NEXT);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(final int position) {
  			if (!validateEditorInputState())
  				return;
  
  			final ISourceViewer viewer= getSourceViewer();
  			StyledText text= viewer.getTextWidget();
  			Point widgetSelection= text.getSelection();
  			if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
  				final int caret= text.getCaretOffset();
  				final int offset= modelOffset2WidgetOffset(viewer, position);
  
  				if (caret == widgetSelection.x)
  					text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
  				else
  					text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
  				text.invokeAction(ST.DELETE_NEXT);
  			} else {
  				Point selection= viewer.getSelectedRange();
  				final int caret, length;
  				if (selection.y != 0) {
  					caret= selection.x;
  					length= selection.y;
  				} else {
  					caret= widgetOffset2ModelOffset(viewer, text.getCaretOffset());
  					length= position - caret;
  				}
  
  				try {
  					viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$
  				} catch (BadLocationException exception) {
  					// Should not happen
  				}
  			}
  		}
  
  		/*
  		 * @see org.eclipse.ui.texteditor.IUpdate#update()
  		 */
  		public void update() {
  			setEnabled(isEditorInputModifiable());
  		}
  	}
  
  	/**
  	 * Text operation action to select the next sub-word.
  	 *
  	 * 
  	 */
  	protected class SelectNextSubWordAction extends NextSubWordAction {
  
  		/**
  		 * Creates a new select next sub-word action.
  		 */
  		public SelectNextSubWordAction() {
  			super(ST.SELECT_WORD_NEXT);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(final int position) {
  			final ISourceViewer viewer= getSourceViewer();
  
  			final StyledText text= viewer.getTextWidget();
  			if (text != null && !text.isDisposed()) {
  
  				final Point selection= text.getSelection();
  				final int caret= text.getCaretOffset();
  				final int offset= modelOffset2WidgetOffset(viewer, position);
  
  				if (caret == selection.x)
  					text.setSelectionRange(selection.y, offset - selection.y);
  				else
  					text.setSelectionRange(selection.x, offset - selection.x);
  			}
  		}
  	}
  
  	/**
  	 * Text navigation action to navigate to the previous sub-word.
  	 *
  	 * 
  	 */
  	protected abstract class PreviousSubWordAction extends TextNavigationAction {
  
  		protected JavaWordIterator fIterator= new JavaWordIterator();
  
  		/**
  		 * Creates a new previous sub-word action.
  		 *
  		 * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
  		 */
  		protected PreviousSubWordAction(final int code) {
  			super(getSourceViewer().getTextWidget(), code);
  		}
  
  		/*
  		 * @see org.eclipse.jface.action.IAction#run()
  		 */
  		public void run() {
  			// Check whether we are in a java code partition and the preference is enabled
  			final IPreferenceStore store= getPreferenceStore();
  			if (!store.getBoolean(PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION)) {
  				super.run();
  				return;
  			}
  
  			final ISourceViewer viewer= getSourceViewer();
  			final IDocument document= viewer.getDocument();
  			fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
  			int position= widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
  			if (position == -1)
  				return;
  
  			int previous= findPreviousPosition(position);
  			try {
  				if (isBlockSelectionModeEnabled() && document.getLineOfOffset(previous) != document.getLineOfOffset(position)) {
  					super.run(); // may navigate into virtual white space
  				} else if (previous != BreakIterator.DONE) {
  					setCaretPosition(previous);
  					getTextWidget().showSelection();
  					fireSelectionChanged();
  				}
  			} catch (BadLocationException x) {
  				// ignore - getLineOfOffset failed
  			}
  
  		}
  
  		/**
  		 * Finds the previous position before the given position.
  		 *
  		 * @param position the current position
  		 * @return the previous position
  		 */
  		protected int findPreviousPosition(int position) {
  			ISourceViewer viewer= getSourceViewer();
  			int widget= -1;
  			int previous= position;
  			while (previous != BreakIterator.DONE && widget == -1) { // TODO: optimize
  				previous= fIterator.preceding(previous);
  				if (previous != BreakIterator.DONE)
  					widget= modelOffset2WidgetOffset(viewer, previous);
  			}
  			
  			IDocument document= viewer.getDocument();
  			LinkedModeModel model= LinkedModeModel.getModel(document, position);
  			if (model != null) {
  				LinkedPosition linkedPosition= model.findPosition(new LinkedPosition(document, position, 0));
  				if (linkedPosition != null) {
  					int linkedPositionOffset= linkedPosition.getOffset();
  					if (position != linkedPositionOffset && previous < linkedPositionOffset)
  						previous= linkedPositionOffset;
  				} else {
  					LinkedPosition previousLinkedPosition= model.findPosition(new LinkedPosition(document, previous, 0));
  					if (previousLinkedPosition != null) {
  						int previousLinkedPositionEnd= previousLinkedPosition.getOffset() + previousLinkedPosition.getLength();
  						if (position != previousLinkedPositionEnd && previous < previousLinkedPositionEnd)
  							previous= previousLinkedPositionEnd;
  					}
  				}
  			}
  			
  			return previous;
  		}
  
  		/**
  		 * Sets the caret position to the sub-word boundary given with <code>position</code>.
  		 *
  		 * @param position Position where the action should move the caret
  		 */
  		protected abstract void setCaretPosition(int position);
  	}
  
  	/**
  	 * Text navigation action to navigate to the previous sub-word.
  	 *
  	 * 
  	 */
  	protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
  
  		/**
  		 * Creates a new navigate previous sub-word action.
  		 */
  		public NavigatePreviousSubWordAction() {
  			super(ST.WORD_PREVIOUS);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(final int position) {
  			getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
  		}
  	}
  
  	/**
  	 * Text operation action to delete the previous sub-word.
  	 *
  	 * 
  	 */
  	protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
  
  		/**
  		 * Creates a new delete previous sub-word action.
  		 */
  		public DeletePreviousSubWordAction() {
  			super(ST.DELETE_WORD_PREVIOUS);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(int position) {
  			if (!validateEditorInputState())
  				return;
  
  			final int length;
  			final ISourceViewer viewer= getSourceViewer();
  			StyledText text= viewer.getTextWidget();
  			Point widgetSelection= text.getSelection();
  			if (isBlockSelectionModeEnabled() && widgetSelection.y != widgetSelection.x) {
  				final int caret= text.getCaretOffset();
  				final int offset= modelOffset2WidgetOffset(viewer, position);
  
  				if (caret == widgetSelection.x)
  					text.setSelectionRange(widgetSelection.y, offset - widgetSelection.y);
  				else
  					text.setSelectionRange(widgetSelection.x, offset - widgetSelection.x);
  				text.invokeAction(ST.DELETE_PREVIOUS);
  			} else {
  				Point selection= viewer.getSelectedRange();
  				if (selection.y != 0) {
  					position= selection.x;
  					length= selection.y;
  				} else {
  					length= widgetOffset2ModelOffset(viewer, text.getCaretOffset()) - position;
  				}
  
  				try {
  					viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$
  				} catch (BadLocationException exception) {
  					// Should not happen
  				}
  			}
  		}
  
  		/*
  		 * @see org.eclipse.ui.texteditor.IUpdate#update()
  		 */
  		public void update() {
  			setEnabled(isEditorInputModifiable());
  		}
  	}
  
  	/**
  	 * Text operation action to select the previous sub-word.
  	 *
  	 * 
  	 */
  	protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
  
  		/**
  		 * Creates a new select previous sub-word action.
  		 */
  		public SelectPreviousSubWordAction() {
  			super(ST.SELECT_WORD_PREVIOUS);
  		}
  
  		/*
  		 * @see org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
  		 */
  		protected void setCaretPosition(final int position) {
  			final ISourceViewer viewer= getSourceViewer();
  
  			final StyledText text= viewer.getTextWidget();
  			if (text != null && !text.isDisposed()) {
  
  				final Point selection= text.getSelection();
  				final int caret= text.getCaretOffset();
  				final int offset= modelOffset2WidgetOffset(viewer, position);
  
  				if (caret == selection.x)
  					text.setSelectionRange(selection.y, offset - selection.y);
  				else
  					text.setSelectionRange(selection.x, offset - selection.x);
  			}
  		}
  	}
  
  	/**
  	 * Format element action to format the enclosing java element.
  	 * <p>
  	 * The format element action works as follows:
  	 * <ul>
  	 * <li>If there is no selection and the caret is positioned on a Java element,
  	 * only this element is formatted. If the element has some accompanying comment,
  	 * then the comment is formatted as well.</li>
  	 * <li>If the selection spans one or more partitions of the document, then all
  	 * partitions covered by the selection are entirely formatted.</li>
  	 * <p>
  	 * Partitions at the end of the selection are not completed, except for comments.
  	 *
  	 * 
  	 */
  	protected class FormatElementAction extends Action implements IUpdate {
  		
  		/*
  		 * 
  		 */
  		FormatElementAction() {
  			setEnabled(isEditorInputModifiable());
  		}
  
  		/*
  		 * @see org.eclipse.jface.action.IAction#run()
  		 */
  		public void run() {
  
  			final JavaSourceViewer viewer= (JavaSourceViewer) getSourceViewer();
  			if (viewer.isEditable()) {
  
  				final Point selection= viewer.rememberSelection();
  				try {
  					viewer.setRedraw(false);
  
  					final String type= TextUtilities.getContentType(viewer.getDocument(), IJavaScriptPartitions.JAVA_PARTITIONING, selection.x, true);
  					if (type.equals(IDocument.DEFAULT_CONTENT_TYPE) && selection.y == 0) {
  
  						try {
  							final IJavaScriptElement element= getElementAt(selection.x, true);
  							if (element != null && element.exists()) {
  
  								final int kind= element.getElementType();
  								if (kind == IJavaScriptElement.TYPE || kind == IJavaScriptElement.METHOD || kind == IJavaScriptElement.INITIALIZER) {
  
  									final ISourceReference reference= (ISourceReference)element;
  									final ISourceRange range= reference.getSourceRange();
  
  									if (range != null) {
  										viewer.setSelectedRange(range.getOffset(), range.getLength());
  										viewer.doOperation(ISourceViewer.FORMAT);
  									}
  								}
  							}
  						} catch (JavaScriptModelException exception) {
  							// Should not happen
  						}
  					} else {
  						viewer.setSelectedRange(selection.x, 1);
  						viewer.doOperation(ISourceViewer.FORMAT);
  					}
  				} catch (BadLocationException exception) {
  					// Can not happen
  				} finally {
  
  					viewer.setRedraw(true);
  					viewer.restoreSelection();
  				}
  			}
  		}
  
  		/*
  		 * @see org.eclipse.ui.texteditor.IUpdate#update()
  		 * 
  		 */
  		public void update() {
  			setEnabled(isEditorInputModifiable());
  		}
  	}
  
  	/**
  	 * Internal activation listener.
  	 * 
  	 */
  	private class ActivationListener implements IWindowListener {
  
  		/*
  		 * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow)
  		 * 
  		 */
  		public void windowActivated(IWorkbenchWindow window) {
  			if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart()) {
  				fForcedMarkOccurrencesSelection= getSelectionProvider().getSelection();
  				updateOccurrenceAnnotations((ITextSelection)fForcedMarkOccurrencesSelection, JavaScriptPlugin.getDefault().getASTProvider().getAST(getInputJavaElement(), ASTProvider.WAIT_NO, getProgressMonitor()));
  			}
  		}
  
  		/*
  		 * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow)
  		 * 
  		 */
  		public void windowDeactivated(IWorkbenchWindow window) {
  			if (window == getEditorSite().getWorkbenchWindow() && fMarkOccurrenceAnnotations && isActivePart())
  				removeOccurrenceAnnotations();
  		}
  
  		/*
  		 * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow)
  		 * 
  		 */
  		public void windowClosed(IWorkbenchWindow window) {
  		}
  
  		/*
  		 * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow)
  		 * 
  		 */
  		public void windowOpened(IWorkbenchWindow window) {
  		}
  	}
  
  	/**
  	 * Runner that will toggle folding either instantly (if the editor is
  	 * visible) or the next time it becomes visible. If a runner is started when
  	 * there is already one registered, the registered one is canceled as
  	 * toggling folding twice is a no-op.
  	 * <p>
  	 * The access to the fFoldingRunner field is not thread-safe, it is assumed
  	 * that <code>runWhenNextVisible</code> is only called from the UI thread.
  	 * </p>
  	 *
  	 * 
  	 */
  	private final class ToggleFoldingRunner implements IPartListener2 {
  		/**
  		 * The workbench page we registered the part listener with, or
  		 * <code>null</code>.
  		 */
  		private IWorkbenchPage fPage;
  
  		/**
  		 * Does the actual toggling of projection.
  		 */
  		private void toggleFolding() {
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer instanceof ProjectionViewer) {
  				ProjectionViewer pv= (ProjectionViewer) sourceViewer;
  				if (pv.isProjectionMode() != isFoldingEnabled()) {
  					if (pv.canDoOperation(ProjectionViewer.TOGGLE))
  						pv.doOperation(ProjectionViewer.TOGGLE);
  				}
  			}
  		}
  
  		/**
  		 * Makes sure that the editor's folding state is correct the next time
  		 * it becomes visible. If it already is visible, it toggles the folding
  		 * state. If not, it either registers a part listener to toggle folding
  		 * when the editor becomes visible, or cancels an already registered
  		 * runner.
  		 */
  		public void runWhenNextVisible() {
  			// if there is one already: toggling twice is the identity
  			if (fFoldingRunner != null) {
  				fFoldingRunner.cancel();
  				return;
  			}
  			IWorkbenchPartSite site= getSite();
  			if (site != null) {
  				IWorkbenchPage page= site.getPage();
  				if (!page.isPartVisible(JavaEditor.this)) {
  					// if we're not visible - defer until visible
  					fPage= page;
  					fFoldingRunner= this;
  					page.addPartListener(this);
  					return;
  				}
  			}
  			// we're visible - run now
  			toggleFolding();
  		}
  
  		/**
  		 * Remove the listener and clear the field.
  		 */
  		private void cancel() {
  			if (fPage != null) {
  				fPage.removePartListener(this);
  				fPage= null;
  			}
  			if (fFoldingRunner == this)
  				fFoldingRunner= null;
  		}
  
  		/*
  		 * @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference)
  		 */
  		public void partVisible(IWorkbenchPartReference partRef) {
  			if (JavaEditor.this.equals(partRef.getPart(false))) {
  				cancel();
  				toggleFolding();
  			}
  		}
  
  		/*
  		 * @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference)
  		 */
  		public void partClosed(IWorkbenchPartReference partRef) {
  			if (JavaEditor.this.equals(partRef.getPart(false))) {
  				cancel();
  			}
  		}
  
  		public void partActivated(IWorkbenchPartReference partRef) {}
  		public void partBroughtToTop(IWorkbenchPartReference partRef) {}
  		public void partDeactivated(IWorkbenchPartReference partRef) {}
  		public void partOpened(IWorkbenchPartReference partRef) {}
  		public void partHidden(IWorkbenchPartReference partRef) {}
  		public void partInputChanged(IWorkbenchPartReference partRef) {}
  	}
  
  	/** Preference key for matching brackets */
  	protected final static String MATCHING_BRACKETS=  PreferenceConstants.EDITOR_MATCHING_BRACKETS;
  	/** Preference key for matching brackets color */
  	protected final static String MATCHING_BRACKETS_COLOR=  PreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
  
  	protected final static char[] BRACKETS= { '{', '}', '(', ')', '[', ']', '<', '>' };
  
  	/** The outline page */
  	protected JavaOutlinePage fOutlinePage;
  	/** Outliner context menu Id */
  	protected String fOutlinerContextMenuId;
  	/**
  	 * The editor selection changed listener.
  	 *
  	 * 
  	 */
  	private EditorSelectionChangedListener fEditorSelectionChangedListener;
  	/** The selection changed listener */
  	protected AbstractSelectionChangedListener fOutlineSelectionChangedListener= new OutlineSelectionChangedListener();
  	/** The editor's bracket matcher */
  	protected JavaPairMatcher fBracketMatcher= new JavaPairMatcher(BRACKETS);
  	/** This editor's encoding support */
  	private DefaultEncodingSupport fEncodingSupport;
  	/** History for structure select action */
  	private SelectionHistory fSelectionHistory;
  	protected CompositeActionGroup fActionGroups;
  
  	/**
  	 * The action group for folding.
  	 *
  	 * 
  	 */
  	private FoldingActionGroup fFoldingGroup;
  
  	private CompositeActionGroup fContextMenuGroup;
  	/**
  	 * Holds the current occurrence annotations.
  	 * 
  	 */
  	private Annotation[] fOccurrenceAnnotations= null;
  	/**
  	 * Tells whether all occurrences of the element at the
  	 * current caret location are automatically marked in
  	 * this editor.
  	 * 
  	 */
  	private boolean fMarkOccurrenceAnnotations;
  	/**
  	 * Tells whether the occurrence annotations are sticky
  	 * i.e. whether they stay even if there's no valid Java
  	 * element at the current caret position.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fStickyOccurrenceAnnotations;
  	/**
  	 * Tells whether to mark type occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkTypeOccurrences;
  	/**
  	 * Tells whether to mark method occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkMethodOccurrences;
  	/**
  	 * Tells whether to mark constant occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkConstantOccurrences;
  	/**
  	 * Tells whether to mark field occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkFieldOccurrences;
  	/**
  	 * Tells whether to mark local variable occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkLocalVariableypeOccurrences;
  	/**
  	 * Tells whether to mark exception occurrences in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkExceptions;
  	/**
  	 * Tells whether to mark method exits in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkMethodExitPoints;
  	
  	/**
  	 * Tells whether to mark targets of <code>break</code> and <code>continue</code> statements in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkBreakContinueTargets;
  	
  	/**
  	 * Tells whether to mark implementors in this editor.
  	 * Only valid if {@link #fMarkOccurrenceAnnotations} is <code>true</code>.
  	 * 
  	 */
  	private boolean fMarkImplementors;
  	/**
  	 * The selection used when forcing occurrence marking
  	 * through code.
  	 * 
  	 */
  	private ISelection fForcedMarkOccurrencesSelection;
  	/**
  	 * The document modification stamp at the time when the last
  	 * occurrence marking took place.
  	 * 
  	 */
  	private long fMarkOccurrenceModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
  	/**
  	 * The region of the word under the caret used to when
  	 * computing the current occurrence markings.
  	 * 
  	 */
  	private IRegion fMarkOccurrenceTargetRegion;
  
  	/**
  	 * The internal shell activation listener for updating occurrences.
  	 * 
  	 */
  	private ActivationListener fActivationListener= new ActivationListener();
  	private ISelectionListenerWithAST fPostSelectionListenerWithAST;
  	private OccurrencesFinderJob fOccurrencesFinderJob;
  	/** The occurrences finder job canceler */
  	private OccurrencesFinderJobCanceler fOccurrencesFinderJobCanceler;
  	/**
  	 * This editor's projection support
  	 * 
  	 */
  	private ProjectionSupport fProjectionSupport;
  	/**
  	 * This editor's projection model updater
  	 * 
  	 */
  	private IJavaFoldingStructureProvider fProjectionModelUpdater;
  	/**
  	 * The override and implements indicator manager for this editor.
  	 * 
  	 */
  	protected OverrideIndicatorManager fOverrideIndicatorManager;
  	/**
  	 * Semantic highlighting manager
  	 * , protected as of 3.3
  	 */
  	protected SemanticHighlightingManager fSemanticManager;
  	/**
  	 * The folding runner.
  	 * 
  	 */
  	private ToggleFoldingRunner fFoldingRunner;
  	
  	/**
  	 * Tells whether the selection changed event is caused
  	 * by a call to {@link #gotoAnnotation(boolean)}.
  	 * 
  	 * 
  	 */
  	private boolean fSelectionChangedViaGotoAnnotation;
  	/**
  	 * The cached selected range.
  	 * 
  	 * @see ITextViewer#getSelectedRange()
  	 * 
  	 */
  	private Point fCachedSelectedRange;
  
  
  	/**
  	 * Returns the most narrow java element including the given offset.
  	 *
  	 * @param offset the offset inside of the requested element
  	 * @return the most narrow java element
  	 */
  	abstract protected IJavaScriptElement getElementAt(int offset);
  
  	/**
  	 * Returns the java element of this editor's input corresponding to the given IJavaScriptElement.
  	 *
  	 * @param element the java element
  	 * @return the corresponding Java element
  	 */
  	abstract protected IJavaScriptElement getCorrespondingElement(IJavaScriptElement element);
  
  	/**
  	 * Default constructor.
  	 */
  	public JavaEditor() {
  		super();
  	}
  	
  	/**
  	 * Sets the input of the editor's outline page.
  	 *
  	 * @param page the Java outline page
  	 * @param input the editor input
  	 */
  	protected void setOutlinePageInput(JavaOutlinePage page, IEditorInput input) {
  		if (page == null)
  			return;
  		
  		IJavaScriptElement je= getInputJavaElement();
  		if (je != null && je.exists())
  			page.setInput(je);
  		else
  			page.setInput(null);
  		
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeKeyBindingScopes()
  	 */
  	protected void initializeKeyBindingScopes() {
  		setKeyBindingScopes(new String[] { "org.eclipse.wst.jsdt.ui.javascriptViewScope" });  //$NON-NLS-1$
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeEditor()
  	 */
  	protected void initializeEditor() {
  		IPreferenceStore store= createCombinedPreferenceStore(null);
  		setPreferenceStore(store);
  		setSourceViewerConfiguration(createJavaSourceViewerConfiguration());
  		fMarkOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
  		fStickyOccurrenceAnnotations= store.getBoolean(PreferenceConstants.EDITOR_STICKY_OCCURRENCES);
  		fMarkTypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES);
  		fMarkMethodOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES);
  		fMarkConstantOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES);
  		fMarkFieldOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES);
  		fMarkLocalVariableypeOccurrences= store.getBoolean(PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES);
  		fMarkExceptions= store.getBoolean(PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES);
  		fMarkImplementors= store.getBoolean(PreferenceConstants.EDITOR_MARK_IMPLEMENTORS);
  		fMarkMethodExitPoints= store.getBoolean(PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS);
  		fMarkBreakContinueTargets= store.getBoolean(PreferenceConstants.EDITOR_MARK_BREAK_CONTINUE_TARGETS);
  	}
  
  	/**
  	 * Returns a new Java source viewer configuration.
  	 * 
  	 * @return a new <code>JavaScriptSourceViewerConfiguration</code>
  	 * 
  	 */
  	protected JavaScriptSourceViewerConfiguration createJavaSourceViewerConfiguration() {
  		JavaScriptTextTools textTools= JavaScriptPlugin.getDefault().getJavaTextTools();
  		return new JavaScriptSourceViewerConfiguration(textTools.getColorManager(), getPreferenceStore(), this, IJavaScriptPartitions.JAVA_PARTITIONING);
  	}
  
  	/*
  	 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
  	 */
  	protected final ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) {
  
  		IPreferenceStore store= getPreferenceStore();
  		ISourceViewer viewer= createJavaSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles, store);
  
  		JavaUIHelp.setHelp(this, viewer.getTextWidget(), IJavaHelpContextIds.JAVA_EDITOR);
  		
  		JavaSourceViewer javaSourceViewer= null;
  		if (viewer instanceof JavaSourceViewer)
  			javaSourceViewer= (JavaSourceViewer)viewer;
  
  		/*
  		 * This is a performance optimization to reduce the computation of
  		 * the text presentation triggered by {@link #setVisibleDocument(IDocument)}
  		 */
  		if (javaSourceViewer != null && isFoldingEnabled() && (store == null || !store.getBoolean(PreferenceConstants.EDITOR_SHOW_SEGMENTS)))
  			javaSourceViewer.prepareDelayedProjection();
  		
  		ProjectionViewer projectionViewer= (ProjectionViewer)viewer;
  		fProjectionSupport= new ProjectionSupport(projectionViewer, getAnnotationAccess(), getSharedColors());
  		fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$
  		fProjectionSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$
  		fProjectionSupport.setHoverControlCreator(new IInformationControlCreator() {
  			public IInformationControl createInformationControl(Shell shell) {
  				return new SourceViewerInformationControl(shell, SWT.TOOL | SWT.NO_TRIM | getOrientation(), SWT.NONE, EditorsUI.getTooltipAffordanceString());
  			}
  		});
  		fProjectionSupport.setInformationPresenterControlCreator(new IInformationControlCreator() {
  			public IInformationControl createInformationControl(Shell shell) {
  				int shellStyle= SWT.RESIZE | SWT.TOOL | getOrientation();
  				int style= SWT.V_SCROLL | SWT.H_SCROLL;
  				return new SourceViewerInformationControl(shell, shellStyle, style);
  			}
  		});
  		fProjectionSupport.install();
  
  		fProjectionModelUpdater= JavaScriptPlugin.getDefault().getFoldingStructureProviderRegistry().getCurrentFoldingProvider();
  		if (fProjectionModelUpdater != null)
  			fProjectionModelUpdater.install(this, projectionViewer);
  
  		// ensure source viewer decoration support has been created and configured
  		getSourceViewerDecorationSupport(viewer);
  
  		return viewer;
  	}
  
  	public final ISourceViewer getViewer() {
  		return getSourceViewer();
  	}
  
  	/*
  	 * @see AbstractTextEditor#createSourceViewer(Composite, IVerticalRuler, int)
  	 */
  	protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler, boolean isOverviewRulerVisible, int styles, IPreferenceStore store) {
  		return new JavaSourceViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles, store);
  	}
  
  	/*
  	 * @see AbstractTextEditor#affectsTextPresentation(PropertyChangeEvent)
  	 */
  	protected boolean affectsTextPresentation(PropertyChangeEvent event) {
  		return ((JavaScriptSourceViewerConfiguration)getSourceViewerConfiguration()).affectsTextPresentation(event) || super.affectsTextPresentation(event);
  	}
  
  	/**
  	 * Creates and returns the preference store for this Java editor with the given input.
  	 *
  	 * @param input The editor input for which to create the preference store
  	 * @return the preference store for this editor
  	 *
  	 * 
  	 */
  	private IPreferenceStore createCombinedPreferenceStore(IEditorInput input) {
  		List stores= new ArrayList(3);
  
  		IJavaScriptProject project= EditorUtility.getJavaProject(input);
  		if (project != null) {
  			stores.add(new EclipsePreferencesAdapter(new ProjectScope(project.getProject()), JavaScriptCore.PLUGIN_ID));
  		}
  
  		stores.add(JavaScriptPlugin.getDefault().getPreferenceStore());
  		stores.add(new PreferencesAdapter(JavaScriptCore.getPlugin().getPluginPreferences()));
  		stores.add(EditorsUI.getPreferenceStore());
  
  		return new ChainedPreferenceStore((IPreferenceStore[]) stores.toArray(new IPreferenceStore[stores.size()]));
  	}
  
  	/**
  	 * Sets the outliner's context menu ID.
  	 *
  	 * @param menuId the menu ID
  	 */
  	protected void setOutlinerContextMenuId(String menuId) {
  		fOutlinerContextMenuId= menuId;
  	}
  
  	/**
  	 * Returns the standard action group of this editor.
  	 *
  	 * @return returns this editor's standard action group
  	 */
  	protected ActionGroup getActionGroup() {
  		return fActionGroups;
  	}
  
  	/*
  	 * @see AbstractTextEditor#editorContextMenuAboutToShow
  	 */
  	public void editorContextMenuAboutToShow(IMenuManager menu) {
  
  		super.editorContextMenuAboutToShow(menu);
  		menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker(IContextMenuConstants.GROUP_SHOW));
  
  		ActionContext context= new ActionContext(getSelectionProvider().getSelection());
  		fContextMenuGroup.setContext(context);
  		fContextMenuGroup.fillContextMenu(menu);
  		fContextMenuGroup.setContext(null);
  
  		// Quick views
  		IAction action= getAction(IJavaEditorActionDefinitionIds.SHOW_OUTLINE);
  		menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
  		action= getAction(IJavaEditorActionDefinitionIds.OPEN_HIERARCHY);
  		menu.appendToGroup(IContextMenuConstants.GROUP_OPEN, action);
  		
  	}
  
  	/**
  	 * Creates the outline page used with this editor.
  	 *
  	 * @return the created Java outline page
  	 */
  	protected JavaOutlinePage createOutlinePage() {
  		JavaOutlinePage page= new JavaOutlinePage(fOutlinerContextMenuId, this);
  		fOutlineSelectionChangedListener.install(page);
  		setOutlinePageInput(page, getEditorInput());
  		return page;
  	}
  
  	/**
  	 * Informs the editor that its outliner has been closed.
  	 */
  	public void outlinePageClosed() {
  		if (fOutlinePage != null) {
  			fOutlineSelectionChangedListener.uninstall(fOutlinePage);
  			fOutlinePage= null;
  			resetHighlightRange();
  		}
  	}
  
  	/**
  	 * Synchronizes the outliner selection with the given element
  	 * position in the editor.
  	 *
  	 * @param element the java element to select
  	 */
  	protected void synchronizeOutlinePage(ISourceReference element) {
  		synchronizeOutlinePage(element, true);
  	}
  
  	/**
  	 * Synchronizes the outliner selection with the given element
  	 * position in the editor.
  	 *
  	 * @param element the java element to select
  	 * @param checkIfOutlinePageActive <code>true</code> if check for active outline page needs to be done
  	 */
  	protected void synchronizeOutlinePage(ISourceReference element, boolean checkIfOutlinePageActive) {
  		if (fOutlinePage != null && element != null && !(checkIfOutlinePageActive && isJavaOutlinePageActive())) {
  			fOutlineSelectionChangedListener.uninstall(fOutlinePage);
  			fOutlinePage.select(element);
  			fOutlineSelectionChangedListener.install(fOutlinePage);
  		}
  	}
  
  	/**
  	 * Synchronizes the outliner selection with the actual cursor
  	 * position in the editor.
  	 */
  	public void synchronizeOutlinePageSelection() {
  		synchronizeOutlinePage(computeHighlightRangeSourceReference());
  	}
  
  	/*
  	 * @see AbstractTextEditor#getAdapter(Class)
  	 */
  	public Object getAdapter(Class required) {
  
  		if (IContentOutlinePage.class.equals(required)) {
  			if (fOutlinePage == null)
  				fOutlinePage= createOutlinePage();
  			return fOutlinePage;
  		}
  
  		if (IEncodingSupport.class.equals(required))
  			return fEncodingSupport;
  
  		if (required == IShowInTargetList.class) {
  			return new IShowInTargetList() {
  				public String[] getShowInTargetIds() {
  					String explorerViewID = ProductProperties.getProperty(IProductConstants.PERSPECTIVE_EXPLORER_VIEW);
  					// make sure the specified view ID is known
  					if (PlatformUI.getWorkbench().getViewRegistry().find(explorerViewID) == null)
  						explorerViewID = ProductProperties.ID_PERSPECTIVE_EXPLORER_VIEW;
  					return new String[] {explorerViewID, JavaScriptUI.ID_PACKAGES, IPageLayout.ID_OUTLINE, IPageLayout.ID_RES_NAV };
  				}
  
  			};
  		}
  
  		if (required == IShowInSource.class) {
  			return new IShowInSource() {
  				public ShowInContext getShowInContext() {
  					return new ShowInContext(getEditorInput(), null) {
  						/*
  						 * @see org.eclipse.ui.part.ShowInContext#getSelection()
  						 * 
  						 */
  						public ISelection getSelection() {
  							IJavaScriptElement je= null;
  							try {
  								je= SelectionConverter.getElementAtOffset(JavaEditor.this);
  								if (je==null)
  									return null;
  								return new StructuredSelection(je);
  							} catch (JavaScriptModelException ex) {
  								return null;
  							}
  						}
  					};
  				}
  			};
  		}
  
  		if (required == IJavaFoldingStructureProvider.class)
  			return fProjectionModelUpdater;
  
  		if (fProjectionSupport != null) {
  			Object adapter= fProjectionSupport.getAdapter(getSourceViewer(), required);
  			if (adapter != null)
  				return adapter;
  		}
  
  		if (required == IContextProvider.class)
  			return JavaUIHelp.getHelpContextProvider(this, IJavaHelpContextIds.JAVA_EDITOR);
  
  		return super.getAdapter(required);
  	}
  
  	/**
  	 * React to changed selection.
  	 *
  	 * 
  	 */
  	protected void selectionChanged() {
  		if (getSelectionProvider() == null)
  			return;
  		ISourceReference element= computeHighlightRangeSourceReference();
  		if (getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE))
  			synchronizeOutlinePage(element);
  		setSelection(element, false);
  		if (!fSelectionChangedViaGotoAnnotation)
  			updateStatusLine();
  		fSelectionChangedViaGotoAnnotation= false;
  	}
  
  	protected void setSelection(ISourceReference reference, boolean moveCursor) {
  		if (getSelectionProvider() == null)
  			return;
  
  		ISelection selection= getSelectionProvider().getSelection();
  		if (selection instanceof ITextSelection) {
  			ITextSelection textSelection= (ITextSelection) selection;
  			// PR 39995: [navigation] Forward history cleared after going back in navigation history:
  			// mark only in navigation history if the cursor is being moved (which it isn't if
  			// this is called from a PostSelectionEvent that should only update the magnet)
  			if (moveCursor && (textSelection.getOffset() != 0 || textSelection.getLength() != 0))
  				markInNavigationHistory();
  		}
  
  		if (reference != null) {
  
  			StyledText  textWidget= null;
  
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer != null)
  				textWidget= sourceViewer.getTextWidget();
  
  			if (textWidget == null)
  				return;
  
  			try {
  				ISourceRange range= null;
  				if (reference instanceof ILocalVariable) {
  					IJavaScriptElement je= ((ILocalVariable)reference).getParent();
  					if (je instanceof ISourceReference)
  						range= ((ISourceReference)je).getSourceRange();
  				} else
  					range= reference.getSourceRange();
  
  				if (range == null)
  					return;
  
  				int offset= range.getOffset();
  				int length= range.getLength();
  
  				if (offset < 0 || length < 0)
  					return;
  
  				setHighlightRange(offset, length, moveCursor);
  
  				if (!moveCursor)
  					return;
  
  				offset= -1;
  				length= -1;
  
  				if (reference instanceof IMember) {
  					range= ((IMember) reference).getNameRange();
  					if (range != null) {
  						offset= range.getOffset();
  						length= range.getLength();
  					}
  				} else if (reference instanceof ILocalVariable) {
  					range= ((ILocalVariable)reference).getNameRange();
  					if (range != null) {
  						offset= range.getOffset();
  						length= range.getLength();
  					}
  				} else if (reference instanceof IImportDeclaration) {
  					String content= reference.getSource();
  					if (content != null) {
  						int start= content.indexOf("import") + 6; //$NON-NLS-1$
  						while (start < content.length() && content.charAt(start) == ' ')
  							start++;
  						
  						int end= content.indexOf(';');
  						do {
  							end--;
  						} while (end >= 0 && content.charAt(end) == ' ');
  						
  						offset= range.getOffset() + start;
  						length= end - start + 1;
  					} else {
  						// fallback
  						offset= range.getOffset();
  						length= range.getLength();
  					}
  				}
  
  				if (offset > -1 && length > 0) {
  
  					try  {
  						textWidget.setRedraw(false);
  						sourceViewer.revealRange(offset, length);
  						sourceViewer.setSelectedRange(offset, length);
  					} finally {
  						textWidget.setRedraw(true);
  					}
  
  					markInNavigationHistory();
  				}
  
  			} catch (JavaScriptModelException x) {
  			} catch (IllegalArgumentException x) {
  			}
  
  		} else if (moveCursor) {
  			resetHighlightRange();
  			markInNavigationHistory();
  		}
  	}
  
  	public void setSelection(IJavaScriptElement element) {
  
  		if (element == null || element instanceof IJavaScriptUnit || element instanceof IClassFile) {
  			/*
  			 * If the element is an IJavaScriptUnit this unit is either the input
  			 * of this editor or not being displayed. In both cases, nothing should
  			 * happened. (http://dev.eclipse.org/bugs/show_bug.cgi?id=5128)
  			 */
  			return;
  		}
  
  		IJavaScriptElement corresponding= getCorrespondingElement(element);
  		if (corresponding instanceof ISourceReference) {
  			ISourceReference reference= (ISourceReference) corresponding;
  			// set highlight range
  			setSelection(reference, true);
  			// set outliner selection
  			if (fOutlinePage != null) {
  				fOutlineSelectionChangedListener.uninstall(fOutlinePage);
  				fOutlinePage.select(reference);
  				fOutlineSelectionChangedListener.install(fOutlinePage);
  			}
  		}
  	}
  
  	protected void doSelectionChanged(SelectionChangedEvent event) {
  
  		ISourceReference reference= null;
  
  		ISelection selection= event.getSelection();
  		Iterator iter= ((IStructuredSelection) selection).iterator();
  		while (iter.hasNext()) {
  			Object o= iter.next();
  			if (o instanceof ISourceReference) {
  				reference= (ISourceReference) o;
  				break;
  			}
  		}
  		if (!isActivePart() && JavaScriptPlugin.getActivePage() != null)
  			JavaScriptPlugin.getActivePage().bringToTop(this);
  
  		setSelection(reference, !isActivePart());
  		
  		ISelectionProvider selectionProvider= getSelectionProvider();
  		if (selectionProvider == null )
  			return;
  		
  		ISelection textSelection= selectionProvider.getSelection();
  		if (!(textSelection instanceof ITextSelection))
  			return;
  		
  		JavaScriptUnit ast= JavaScriptPlugin.getDefault().getASTProvider().getAST(getInputJavaElement(), ASTProvider.WAIT_ACTIVE_ONLY, getProgressMonitor());
  		if (ast != null) {
  			fForcedMarkOccurrencesSelection= textSelection;
  			updateOccurrenceAnnotations((ITextSelection)textSelection, ast);
  		}
  		
  	}
  
  	/*
  	 * @see AbstractTextEditor#adjustHighlightRange(int, int)
  	 */
  	protected void adjustHighlightRange(int offset, int length) {
  
  		try {
  
  			IJavaScriptElement element= getElementAt(offset, false);
  			while (element instanceof ISourceReference) {
  				ISourceRange range= ((ISourceReference) element).getSourceRange();
  				if (range != null && offset < range.getOffset() + range.getLength() && range.getOffset() < offset + length) {
  
  					ISourceViewer viewer= getSourceViewer();
  					if (viewer instanceof ITextViewerExtension5) {
  						ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
  						extension.exposeModelRange(new Region(range.getOffset(), range.getLength()));
  					}
  
  					setHighlightRange(range.getOffset(), range.getLength(), true);
  					if (fOutlinePage != null) {
  						fOutlineSelectionChangedListener.uninstall(fOutlinePage);
  						fOutlinePage.select((ISourceReference) element);
  						fOutlineSelectionChangedListener.install(fOutlinePage);
  					}
  
  					return;
  				}
  				element= element.getParent();
  			}
  
  		} catch (JavaScriptModelException x) {
  			JavaScriptPlugin.log(x.getStatus());
  		}
  
  		ISourceViewer viewer= getSourceViewer();
  		if (viewer instanceof ITextViewerExtension5) {
  			ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
  			extension.exposeModelRange(new Region(offset, length));
  		} else {
  			resetHighlightRange();
  		}
  
  	}
  
  	protected boolean isActivePart() {
  		IWorkbenchPart part= getActivePart();
  		return part != null && part.equals(this);
  	}
  
  	private boolean isJavaOutlinePageActive() {
  		IWorkbenchPart part= getActivePart();
  		return part instanceof ContentOutline && ((ContentOutline)part).getCurrentPage() == fOutlinePage;
  	}
  
  	private IWorkbenchPart getActivePart() {
  		IWorkbenchWindow window= getSite().getWorkbenchWindow();
  		IPartService service= window.getPartService();
  		IWorkbenchPart part= service.getActivePart();
  		return part;
  	}
  
  	/*
  	 * @see StatusTextEditor#getStatusHeader(IStatus)
  	 */
  	protected String getStatusHeader(IStatus status) {
  		if (fEncodingSupport != null) {
  			String message= fEncodingSupport.getStatusHeader(status);
  			if (message != null)
  				return message;
  		}
  		return super.getStatusHeader(status);
  	}
  
  	/*
  	 * @see StatusTextEditor#getStatusBanner(IStatus)
  	 */
  	protected String getStatusBanner(IStatus status) {
  		if (fEncodingSupport != null) {
  			String message= fEncodingSupport.getStatusBanner(status);
  			if (message != null)
  				return message;
  		}
  		return super.getStatusBanner(status);
  	}
  
  	/*
  	 * @see StatusTextEditor#getStatusMessage(IStatus)
  	 */
  	protected String getStatusMessage(IStatus status) {
  		if (fEncodingSupport != null) {
  			String message= fEncodingSupport.getStatusMessage(status);
  			if (message != null)
  				return message;
  		}
  		return super.getStatusMessage(status);
  	}
  
  	/*
  	 * @see AbstractTextEditor#doSetInput
  	 */
  	protected void doSetInput(IEditorInput input) throws CoreException {
  		ISourceViewer sourceViewer= getSourceViewer();
  		if (!(sourceViewer instanceof ISourceViewerExtension2)) {
  			setPreferenceStore(createCombinedPreferenceStore(input));
  			internalDoSetInput(input);
  			return;
  		}
  
  		// uninstall & unregister preference store listener
  		getSourceViewerDecorationSupport(sourceViewer).uninstall();
  		((ISourceViewerExtension2)sourceViewer).unconfigure();
  
  		setPreferenceStore(createCombinedPreferenceStore(input));
  
  		// install & register preference store listener
  		sourceViewer.configure(getSourceViewerConfiguration());
  		getSourceViewerDecorationSupport(sourceViewer).install(getPreferenceStore());
  
  		internalDoSetInput(input);
  	}
  
  	private void internalDoSetInput(IEditorInput input) throws CoreException {
  		ISourceViewer sourceViewer= getSourceViewer();
  		JavaSourceViewer javaSourceViewer= null;
  		if (sourceViewer instanceof JavaSourceViewer)
  			javaSourceViewer= (JavaSourceViewer)sourceViewer;
  		
  		IPreferenceStore store= getPreferenceStore();
  		if (javaSourceViewer != null && isFoldingEnabled() &&(store == null || !store.getBoolean(PreferenceConstants.EDITOR_SHOW_SEGMENTS)))
  			javaSourceViewer.prepareDelayedProjection();
  		
  		super.doSetInput(input);
  
  		if (javaSourceViewer != null && javaSourceViewer.getReconciler() == null) {
  			IReconciler reconciler= getSourceViewerConfiguration().getReconciler(javaSourceViewer);
  			if (reconciler != null) {
  				reconciler.install(javaSourceViewer);
  				javaSourceViewer.setReconciler(reconciler);
  			}
  		}
  
  		if (fEncodingSupport != null)
  			fEncodingSupport.reset();
  
  		setOutlinePageInput(fOutlinePage, input);
  
  		if (isShowingOverrideIndicators())
  			installOverrideIndicator(false);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#setPreferenceStore(org.eclipse.jface.preference.IPreferenceStore)
  	 * 
  	 */
  	protected void setPreferenceStore(IPreferenceStore store) {
  		super.setPreferenceStore(store);
  		if (getSourceViewerConfiguration() instanceof JavaScriptSourceViewerConfiguration) {
  			JavaScriptTextTools textTools= JavaScriptPlugin.getDefault().getJavaTextTools();
  			setSourceViewerConfiguration(new JavaScriptSourceViewerConfiguration(textTools.getColorManager(), store, this, IJavaScriptPartitions.JAVA_PARTITIONING));
  		}
  		if (getSourceViewer() instanceof JavaSourceViewer)
  			((JavaSourceViewer)getSourceViewer()).setPreferenceStore(store);
  	}
  
  	/*
  	 * @see IWorkbenchPart#dispose()
  	 */
  	public void dispose() {
  
  		if (fProjectionModelUpdater != null) {
  			fProjectionModelUpdater.uninstall();
  			fProjectionModelUpdater= null;
  		}
  
  		if (fProjectionSupport != null) {
  			fProjectionSupport.dispose();
  			fProjectionSupport= null;
  		}
  
  		// cancel possible running computation
  		fMarkOccurrenceAnnotations= false;
  		uninstallOccurrencesFinder();
  
  		uninstallOverrideIndicator();
  
  		uninstallSemanticHighlighting();
  
  		if (fActivationListener != null) {
  			PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
  			fActivationListener= null;
  		}
  
  		if (fEncodingSupport != null) {
  			fEncodingSupport.dispose();
  			fEncodingSupport= null;
  		}
  
  		if (fBracketMatcher != null) {
  			fBracketMatcher.dispose();
  			fBracketMatcher= null;
  		}
  
  		if (fSelectionHistory != null) {
  			fSelectionHistory.dispose();
  			fSelectionHistory= null;
  		}
  
  		if (fEditorSelectionChangedListener != null)  {
  			fEditorSelectionChangedListener.uninstall(getSelectionProvider());
  			fEditorSelectionChangedListener= null;
  		}
  
  		if (fActionGroups != null) {
  			fActionGroups.dispose();
  			fActionGroups= null;
  		}
  		
  		super.dispose();
  	}
  
  	protected void createActions() {
  		installEncodingSupport();
  		
  		super.createActions();
  
  		ActionGroup oeg, ovg, jsg;
  		fActionGroups= new CompositeActionGroup(new ActionGroup[] {
  			oeg= new OpenEditorActionGroup(this),
  			ovg= new OpenViewActionGroup(this),
  			jsg= new JavaSearchActionGroup(this)
  		});
  		fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] {oeg, ovg, jsg});
  
  		fFoldingGroup= new FoldingActionGroup(this, getViewer());
  
  		Action action= new GotoMatchingBracketAction(this);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_MATCHING_BRACKET);
  		setAction(GotoMatchingBracketAction.GOTO_MATCHING_BRACKET, action);
  
  		action= new TextOperationAction(JavaEditorMessages.getBundleForConstructedKeys(),"ShowOutline.", this, JavaSourceViewer.SHOW_OUTLINE, true); //$NON-NLS-1$
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SHOW_OUTLINE);
  		setAction(IJavaEditorActionDefinitionIds.SHOW_OUTLINE, action);
  		PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.SHOW_OUTLINE_ACTION);
  
  		action= new TextOperationAction(JavaEditorMessages.getBundleForConstructedKeys(),"OpenStructure.", this, JavaSourceViewer.OPEN_STRUCTURE, true); //$NON-NLS-1$
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.OPEN_STRUCTURE);
  		setAction(IJavaEditorActionDefinitionIds.OPEN_STRUCTURE, action);
  		PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.OPEN_STRUCTURE_ACTION);
  
  		action= new TextOperationAction(JavaEditorMessages.getBundleForConstructedKeys(),"OpenHierarchy.", this, JavaSourceViewer.SHOW_HIERARCHY, true); //$NON-NLS-1$
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.OPEN_HIERARCHY);
  		setAction(IJavaEditorActionDefinitionIds.OPEN_HIERARCHY, action);
  		PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IJavaHelpContextIds.OPEN_HIERARCHY_ACTION);
  
  		fSelectionHistory= new SelectionHistory(this);
  
  		action= new StructureSelectEnclosingAction(this, fSelectionHistory);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_ENCLOSING);
  		setAction(StructureSelectionAction.ENCLOSING, action);
  
  		action= new StructureSelectNextAction(this, fSelectionHistory);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_NEXT);
  		setAction(StructureSelectionAction.NEXT, action);
  
  		action= new StructureSelectPreviousAction(this, fSelectionHistory);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_PREVIOUS);
  		setAction(StructureSelectionAction.PREVIOUS, action);
  
  		StructureSelectHistoryAction historyAction= new StructureSelectHistoryAction(this, fSelectionHistory);
  		historyAction.setActionDefinitionId(IJavaEditorActionDefinitionIds.SELECT_LAST);
  		setAction(StructureSelectionAction.HISTORY, historyAction);
  		fSelectionHistory.setHistoryAction(historyAction);
  
  		action= GoToNextPreviousMemberAction.newGoToNextMemberAction(this);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_NEXT_MEMBER);
  		setAction(GoToNextPreviousMemberAction.NEXT_MEMBER, action);
  
  		action= GoToNextPreviousMemberAction.newGoToPreviousMemberAction(this);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.GOTO_PREVIOUS_MEMBER);
  		setAction(GoToNextPreviousMemberAction.PREVIOUS_MEMBER, action);
  
  		action= new FormatElementAction();
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.QUICK_FORMAT);
  		setAction("QuickFormat", action); //$NON-NLS-1$
  		markAsStateDependentAction("QuickFormat", true); //$NON-NLS-1$
  
  		action= new RemoveOccurrenceAnnotations(this);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.REMOVE_OCCURRENCE_ANNOTATIONS);
  		setAction("RemoveOccurrenceAnnotations", action); //$NON-NLS-1$
  
  		// add annotation actions for roll-over expand hover
  		action= new JavaSelectMarkerRulerAction2(JavaEditorMessages.getBundleForConstructedKeys(), "Editor.RulerAnnotationSelection.", this); //$NON-NLS-1$
  		setAction("AnnotationAction", action); //$NON-NLS-1$
  		
  		action= new ShowInPackageViewAction(this);
  		action.setActionDefinitionId(IJavaEditorActionDefinitionIds.SHOW_IN_PACKAGE_VIEW);
  		setAction("ShowInPackageView", action); //$NON-NLS-1$
  		
  
  		// replace cut/copy paste actions with a version that implement 'add imports on paste'
  
  		action= new ClipboardOperationAction(JavaEditorMessages.getBundleForConstructedKeys(), "Editor.Cut.", this, ITextOperationTarget.CUT); //$NON-NLS-1$
  		setAction(ITextEditorActionConstants.CUT, action);
  
  		action= new ClipboardOperationAction(JavaEditorMessages.getBundleForConstructedKeys(), "Editor.Copy.", this, ITextOperationTarget.COPY); //$NON-NLS-1$
  		setAction(ITextEditorActionConstants.COPY, action);
  
  		action= new ClipboardOperationAction(JavaEditorMessages.getBundleForConstructedKeys(), "Editor.Paste.", this, ITextOperationTarget.PASTE); //$NON-NLS-1$
  		setAction(ITextEditorActionConstants.PASTE, action);
  		
  		action= new CopyQualifiedNameAction(this);
  		setAction(IJavaEditorActionConstants.COPY_QUALIFIED_NAME, action);
  	}
  	
  	/**
  	 * Installs the encoding support on the given text editor.
  	 * <p>
   	 * Subclasses may override to install their own encoding
   	 * support or to disable the default encoding support.
   	 * </p>
  	 * 
  	 */
  	protected void installEncodingSupport() {
  		fEncodingSupport= new DefaultEncodingSupport();
  		fEncodingSupport.initialize(this);
  	}
  	
  
  	public void updatedTitleImage(Image image) {
  		setTitleImage(image);
  	}
  
  	/*
  	 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
  	 */
  	protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
  
  		String property= event.getProperty();
  
  		if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH.equals(property)) {
  			/*
  			 * Ignore tab setting since we rely on the formatter preferences.
  			 * We do this outside the try-finally block to avoid that EDITOR_TAB_WIDTH
  			 * is handled by the sub-class (AbstractDecoratedTextEditor).
  			 */
  			return;
  		}
  
  		try {
  
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer == null)
  				return;
  
  			if (isJavaEditorHoverProperty(property))
  				updateHoverBehavior();
  
  			boolean newBooleanValue= false;
  			Object newValue= event.getNewValue();
  			if (newValue != null)
  				newBooleanValue= Boolean.valueOf(newValue.toString()).booleanValue();
  
  			if (PreferenceConstants.EDITOR_SYNC_OUTLINE_ON_CURSOR_MOVE.equals(property)) {
  				if (newBooleanValue)
  					selectionChanged();
  				return;
  			}
  
  			if (PreferenceConstants.EDITOR_MARK_OCCURRENCES.equals(property)) {
  				if (newBooleanValue != fMarkOccurrenceAnnotations) {
  					fMarkOccurrenceAnnotations= newBooleanValue;
  					if (!fMarkOccurrenceAnnotations)
  						uninstallOccurrencesFinder();
  					else
  						installOccurrencesFinder(true);
  				}
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_TYPE_OCCURRENCES.equals(property)) {
  				fMarkTypeOccurrences= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_METHOD_OCCURRENCES.equals(property)) {
  				fMarkMethodOccurrences= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_CONSTANT_OCCURRENCES.equals(property)) {
  				fMarkConstantOccurrences= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_FIELD_OCCURRENCES.equals(property)) {
  				fMarkFieldOccurrences= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_LOCAL_VARIABLE_OCCURRENCES.equals(property)) {
  				fMarkLocalVariableypeOccurrences= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_EXCEPTION_OCCURRENCES.equals(property)) {
  				fMarkExceptions= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_METHOD_EXIT_POINTS.equals(property)) {
  				fMarkMethodExitPoints= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_BREAK_CONTINUE_TARGETS.equals(property)) {
  				fMarkBreakContinueTargets= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_MARK_IMPLEMENTORS.equals(property)) {
  				fMarkImplementors= newBooleanValue;
  				return;
  			}
  			if (PreferenceConstants.EDITOR_STICKY_OCCURRENCES.equals(property)) {
  				fStickyOccurrenceAnnotations= newBooleanValue;
  				return;
  			}
  			if (SemanticHighlightings.affectsEnablement(getPreferenceStore(), event)) {
  				if (isSemanticHighlightingEnabled())
  					installSemanticHighlighting();
  				else
  					uninstallSemanticHighlighting();
  				return;
  			}
  
  			if (JavaScriptCore.COMPILER_SOURCE.equals(property)) {
  				if (event.getNewValue() instanceof String)
  					fBracketMatcher.setSourceVersion((String) event.getNewValue());
  				// fall through as others are interested in source change as well.
  			}
  
  			((JavaScriptSourceViewerConfiguration)getSourceViewerConfiguration()).handlePropertyChangeEvent(event);
  
  			if (affectsOverrideIndicatorAnnotations(event)) {
  				if (isShowingOverrideIndicators()) {
  					if (fOverrideIndicatorManager == null)
  						installOverrideIndicator(true);
  				} else {
  					if (fOverrideIndicatorManager != null)
  						uninstallOverrideIndicator();
  				}
  				return;
  			}
  
  			if (PreferenceConstants.EDITOR_FOLDING_PROVIDER.equals(property)) {
  				if (sourceViewer instanceof ProjectionViewer) {
  					ProjectionViewer projectionViewer= (ProjectionViewer) sourceViewer;
  					if (fProjectionModelUpdater != null)
  						fProjectionModelUpdater.uninstall();
  					// either freshly enabled or provider changed
  					fProjectionModelUpdater= JavaScriptPlugin.getDefault().getFoldingStructureProviderRegistry().getCurrentFoldingProvider();
  					if (fProjectionModelUpdater != null) {
  						fProjectionModelUpdater.install(this, projectionViewer);
  					}
  				}
  				return;
  			}
  
  			if (DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE.equals(property)
  					|| DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE.equals(property)
  					|| DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR.equals(property)) {
  				StyledText textWidget= sourceViewer.getTextWidget();
  				int tabWidth= getSourceViewerConfiguration().getTabWidth(sourceViewer);
  				if (textWidget.getTabs() != tabWidth)
  					textWidget.setTabs(tabWidth);
  				return;
  			}
  
  			if (PreferenceConstants.EDITOR_FOLDING_ENABLED.equals(property)) {
  				if (sourceViewer instanceof ProjectionViewer) {
  					new ToggleFoldingRunner().runWhenNextVisible();
  				}
  				return;
  			}
  
  		} finally {
  			super.handlePreferenceStoreChanged(event);
  		}
  		
  		if (AbstractDecoratedTextEditorPreferenceConstants.SHOW_RANGE_INDICATOR.equals(property)) {
  			// superclass already installed the range indicator
  			Object newValue= event.getNewValue();
  			ISourceViewer viewer= getSourceViewer();
  			if (newValue != null && viewer != null) {
  				if (Boolean.valueOf(newValue.toString()).booleanValue()) {
  					// adjust the highlightrange in order to get the magnet right after changing the selection
  					Point selection= viewer.getSelectedRange();
  					adjustHighlightRange(selection.x, selection.y);
  				}
  			}
  
  		}
  	}
  
  	/**
  	 * Initializes the given viewer's colors.
  	 *
  	 * @param viewer the viewer to be initialized
  	 * 
  	 */
  	protected void initializeViewerColors(ISourceViewer viewer) {
  		// is handled by JavaSourceViewer
  	}
  
  	private boolean isJavaEditorHoverProperty(String property) {
  		return	PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS.equals(property);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#updatePropertyDependentActions()
  	 */
  	protected void updatePropertyDependentActions() {
  		super.updatePropertyDependentActions();
  		if (fEncodingSupport != null)
  			fEncodingSupport.reset();
  	}
  
  	/*
  	 * Update the hovering behavior depending on the preferences.
  	 */
  	private void updateHoverBehavior() {
  		SourceViewerConfiguration configuration= getSourceViewerConfiguration();
  		String[] types= configuration.getConfiguredContentTypes(getSourceViewer());
  
  		for (int i= 0; i < types.length; i++) {
  
  			String t= types[i];
  
  			ISourceViewer sourceViewer= getSourceViewer();
  			if (sourceViewer instanceof ITextViewerExtension2) {
  				// Remove existing hovers
  				((ITextViewerExtension2)sourceViewer).removeTextHovers(t);
  
  				int[] stateMasks= configuration.getConfiguredTextHoverStateMasks(getSourceViewer(), t);
  
  				if (stateMasks != null) {
  					for (int j= 0; j < stateMasks.length; j++)	{
  						int stateMask= stateMasks[j];
  						ITextHover textHover= configuration.getTextHover(sourceViewer, t, stateMask);
  						((ITextViewerExtension2)sourceViewer).setTextHover(textHover, t, stateMask);
  					}
  				} else {
  					ITextHover textHover= configuration.getTextHover(sourceViewer, t);
  					((ITextViewerExtension2)sourceViewer).setTextHover(textHover, t, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK);
  				}
  			} else
  				sourceViewer.setTextHover(configuration.getTextHover(sourceViewer, t), t);
  		}
  	}
  
  	/*
  	 * @see org.eclipse.wst.jsdt.internal.ui.viewsupport.IViewPartInputProvider#getViewPartInput()
  	 */
  	public Object getViewPartInput() {
  		return getEditorInput().getAdapter(IJavaScriptElement.class);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetSelection(ISelection)
  	 */
  	protected void doSetSelection(ISelection selection) {
  		super.doSetSelection(selection);
  		synchronizeOutlinePageSelection();
  	}
  
  	boolean isFoldingEnabled() {
  		return JavaScriptPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_FOLDING_ENABLED);
  	}
  
  	/*
  	 * @see org.eclipse.ui.part.WorkbenchPart#getOrientation()
  	 * 
  	 */
  	public int getOrientation() {
  		return SWT.LEFT_TO_RIGHT;	//Java editors are always left to right by default
  	}
  
  	/*
  	 * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
  	 */
  	public void createPartControl(Composite parent) {
  		super.createPartControl(parent);
  
  		fEditorSelectionChangedListener= new EditorSelectionChangedListener();
  		fEditorSelectionChangedListener.install(getSelectionProvider());
  
  		if (isSemanticHighlightingEnabled())
  			installSemanticHighlighting();
  
  		PlatformUI.getWorkbench().addWindowListener(fActivationListener);
  	}
  
  	protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
  
  		fBracketMatcher.setSourceVersion(getPreferenceStore().getString(JavaScriptCore.COMPILER_SOURCE));
  		support.setCharacterPairMatcher(fBracketMatcher);
  		support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR);
  
  		super.configureSourceViewerDecorationSupport(support);
  	}
  
  	/**
  	 * Returns the lock object for the given annotation model.
  	 *
  	 * @param annotationModel the annotation model
  	 * @return the annotation model's lock object
  	 * 
  	 */
  	private Object getLockObject(IAnnotationModel annotationModel) {
  		if (annotationModel instanceof ISynchronizable) {
  			Object lock= ((ISynchronizable)annotationModel).getLockObject();
  			if (lock != null)
  				return lock;
  		}
  		return annotationModel;
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#updateMarkerViews(org.eclipse.jface.text.source.Annotation)
  	 * 
  	 */
  	protected void updateMarkerViews(Annotation annotation) {
  		if (annotation instanceof IJavaAnnotation) {
  			Iterator e= ((IJavaAnnotation) annotation).getOverlaidIterator();
  			if (e != null) {
  				while (e.hasNext()) {
  					Object o= e.next();
  					if (o instanceof MarkerAnnotation) {
  						super.updateMarkerViews((MarkerAnnotation)o);
  						return;
  					}
  				}
  			}
  			return;
  		}
  		super.updateMarkerViews(annotation);
  	}
  
  	/**
  	 * Finds and marks occurrence annotations.
  	 *
  	 * 
  	 */
  	class OccurrencesFinderJob extends Job {
  
  		private IDocument fDocument;
  		private ISelection fSelection;
  		private ISelectionValidator fPostSelectionValidator;
  		private boolean fCanceled= false;
  		private IProgressMonitor fProgressMonitor;
  		private Position[] fPositions;
  
  		public OccurrencesFinderJob(IDocument document, Position[] positions, ISelection selection) {
  			super(JavaEditorMessages.JavaEditor_markOccurrences_job_name);
  			fDocument= document;
  			fSelection= selection;
  			fPositions= positions;
  
  			if (getSelectionProvider() instanceof ISelectionValidator)
  				fPostSelectionValidator= (ISelectionValidator)getSelectionProvider();
  		}
  
  		// cannot use cancel() because it is declared final
  		void doCancel() {
  			fCanceled= true;
  			cancel();
  		}
  
  		private boolean isCanceled() {
  			return fCanceled || fProgressMonitor.isCanceled()
  				||  fPostSelectionValidator != null && !(fPostSelectionValidator.isValid(fSelection) || fForcedMarkOccurrencesSelection == fSelection)
  				|| LinkedModeModel.hasInstalledModel(fDocument);
  		}
  
  		/*
  		 * @see Job#run(org.eclipse.core.runtime.IProgressMonitor)
  		 */
  		public IStatus run(IProgressMonitor progressMonitor) {
  
  			fProgressMonitor= progressMonitor;
  
  			if (isCanceled())
  				return Status.CANCEL_STATUS;
  
  			ITextViewer textViewer= getViewer();
  			if (textViewer == null)
  				return Status.CANCEL_STATUS;
  
  			IDocument document= textViewer.getDocument();
  			if (document == null)
  				return Status.CANCEL_STATUS;
  
  			IDocumentProvider documentProvider= getDocumentProvider();
  			if (documentProvider == null)
  				return Status.CANCEL_STATUS;
  
  			IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput());
  			if (annotationModel == null)
  				return Status.CANCEL_STATUS;
  
  			// Add occurrence annotations
  			int length= fPositions.length;
  			Map annotationMap= new HashMap(length);
  			for (int i= 0; i < length; i++) {
  
  				if (isCanceled())
  					return Status.CANCEL_STATUS;
  
  				String message;
  				Position position= fPositions[i];
  
  				// Create & add annotation
  				try {
  					message= document.get(position.offset, position.length);
  				} catch (BadLocationException ex) {
  					// Skip this match
  					continue;
  				}
  				annotationMap.put(
  						new Annotation("org.eclipse.wst.jsdt.ui.occurrences", false, message), //$NON-NLS-1$
  						position);
  			}
  
  			if (isCanceled())
  				return Status.CANCEL_STATUS;
  
  			synchronized (getLockObject(annotationModel)) {
  				if (annotationModel instanceof IAnnotationModelExtension) {
  					((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap);
  				} else {
  					removeOccurrenceAnnotations();
  					Iterator iter= annotationMap.entrySet().iterator();
  					while (iter.hasNext()) {
  						Map.Entry mapEntry= (Map.Entry)iter.next();
  						annotationModel.addAnnotation((Annotation)mapEntry.getKey(), (Position)mapEntry.getValue());
  					}
  				}
  				fOccurrenceAnnotations= (Annotation[])annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]);
  			}
  
  			return Status.OK_STATUS;
  		}
  	}
  
  	/**
  	 * Updates the occurrences annotations based
  	 * on the current selection.
  	 *
  	 * @param selection the text selection
  	 * @param astRoot the compilation unit AST
  	 * 
  	 */
  	protected void updateOccurrenceAnnotations(ITextSelection selection, JavaScriptUnit astRoot) {
  
  		if (fOccurrencesFinderJob != null)
  			fOccurrencesFinderJob.cancel();
  
  		if (!fMarkOccurrenceAnnotations)
  			return;
  
  		if (astRoot == null || selection == null)
  			return;
  
  		IDocument document= getSourceViewer().getDocument();
  		if (document == null)
  			return;
  
  		if (document instanceof IDocumentExtension4) {
  			int offset= selection.getOffset();
  			long currentModificationStamp= ((IDocumentExtension4)document).getModificationStamp();
  			IRegion markOccurrenceTargetRegion= fMarkOccurrenceTargetRegion; 
  			if (markOccurrenceTargetRegion != null && currentModificationStamp == fMarkOccurrenceModificationStamp) {
  				if (markOccurrenceTargetRegion.getOffset() <= offset && offset <= markOccurrenceTargetRegion.getOffset() + markOccurrenceTargetRegion.getLength())
  					return;
  			}
  			fMarkOccurrenceTargetRegion= JavaWordFinder.findWord(document, offset);
  			fMarkOccurrenceModificationStamp= currentModificationStamp;
  		}
  
  		List matches= null;
  		
  		ASTNode selectedNode= NodeFinder.perform(astRoot, selection.getOffset(), selection.getLength());
  		
  		if (fMarkExceptions || fMarkTypeOccurrences) {
  			ExceptionOccurrencesFinder exceptionFinder= new ExceptionOccurrencesFinder();
  			String message= exceptionFinder.initialize(astRoot, selectedNode);
  			if (message == null) {
  				matches= exceptionFinder.perform();
  				if (!fMarkExceptions && !matches.isEmpty())
  					matches.clear();
  			}
  		}
  
  		if ((matches == null || matches.isEmpty()) && (fMarkMethodExitPoints || fMarkTypeOccurrences)) {
  			MethodExitsFinder finder= new MethodExitsFinder();
  			String message= finder.initialize(astRoot, selectedNode);
  			if (message == null) {
  				matches= finder.perform();
  				if (!fMarkMethodExitPoints && !matches.isEmpty())
  					matches.clear();
  			}
  		}
  
  		if ((matches == null || matches.isEmpty()) && (fMarkBreakContinueTargets || fMarkTypeOccurrences)) {
  			BreakContinueTargetFinder finder= new BreakContinueTargetFinder();
  			String message= finder.initialize(astRoot, selectedNode);
  			if (message == null) {
  				matches= finder.perform();
  				if (!fMarkBreakContinueTargets && !matches.isEmpty())
  					matches.clear();
  			}
  		}
  
  		if ((matches == null || matches.isEmpty()) && (fMarkImplementors || fMarkTypeOccurrences)) {
  			ImplementOccurrencesFinder finder= new ImplementOccurrencesFinder();
  			String message= finder.initialize(astRoot, selectedNode);
  			if (message == null) {
  				matches= finder.perform();
  				if (!fMarkImplementors && !matches.isEmpty())
  					matches.clear();
  			}
  		}
  
  		if (matches == null) {
  			IBinding binding= null;
  			if (selectedNode instanceof Name)
  				binding= ((Name)selectedNode).resolveBinding();
  
  			if (binding != null && markOccurrencesOfType(binding)) {
  				// Find the matches && extract positions so we can forget the AST
  				OccurrencesFinder finder = new OccurrencesFinder(binding);
  				String message= finder.initialize(astRoot, selectedNode);
  				if (message == null)
  					matches= finder.perform();
  			}
  		}
  
  		if (matches == null || matches.size() == 0) {
  			if (!fStickyOccurrenceAnnotations)
  				removeOccurrenceAnnotations();
  			return;
  		}
  
  		Position[] positions= new Position[matches.size()];
  		int i= 0;
  		for (Iterator each= matches.iterator(); each.hasNext();) {
  			ASTNode currentNode= (ASTNode)each.next();
  			positions[i++]= new Position(currentNode.getStartPosition(), currentNode.getLength());
  		}
  
  		fOccurrencesFinderJob= new OccurrencesFinderJob(document, positions, selection);
  		//fOccurrencesFinderJob.setPriority(Job.DECORATE);
  		//fOccurrencesFinderJob.setSystem(true);
  		//fOccurrencesFinderJob.schedule();
  		fOccurrencesFinderJob.run(new NullProgressMonitor());
  	}
  
  	protected void installOccurrencesFinder(boolean forceUpdate) {
  		fMarkOccurrenceAnnotations= true;
  
  		fPostSelectionListenerWithAST= new ISelectionListenerWithAST() {
  			public void selectionChanged(IEditorPart part, ITextSelection selection, JavaScriptUnit astRoot) {
  				updateOccurrenceAnnotations(selection, astRoot);
  			}
  		};
  		SelectionListenerWithASTManager.getDefault().addListener(this, fPostSelectionListenerWithAST);
  		if (forceUpdate && getSelectionProvider() != null) {
  			fForcedMarkOccurrencesSelection= getSelectionProvider().getSelection();
  			updateOccurrenceAnnotations((ITextSelection)fForcedMarkOccurrencesSelection, JavaScriptPlugin.getDefault().getASTProvider().getAST(getInputJavaElement(), ASTProvider.WAIT_NO, getProgressMonitor()));
  		}
  
  		if (fOccurrencesFinderJobCanceler == null) {
  			fOccurrencesFinderJobCanceler= new OccurrencesFinderJobCanceler();
  			fOccurrencesFinderJobCanceler.install();
  		}
  	}
  
  	protected void uninstallOccurrencesFinder() {
  		fMarkOccurrenceAnnotations= false;
  
  		if (fOccurrencesFinderJob != null) {
  			fOccurrencesFinderJob.cancel();
  			fOccurrencesFinderJob= null;
  		}
  
  		if (fOccurrencesFinderJobCanceler != null) {
  			fOccurrencesFinderJobCanceler.uninstall();
  			fOccurrencesFinderJobCanceler= null;
  		}
  
  		if (fPostSelectionListenerWithAST != null) {
  			SelectionListenerWithASTManager.getDefault().removeListener(this, fPostSelectionListenerWithAST);
  			fPostSelectionListenerWithAST= null;
  		}
  
  		removeOccurrenceAnnotations();
  	}
  
  	protected boolean isMarkingOccurrences() {
  		IPreferenceStore store= getPreferenceStore();
  		return store != null && store.getBoolean(PreferenceConstants.EDITOR_MARK_OCCURRENCES);
  	}
  
  	boolean markOccurrencesOfType(IBinding binding) {
  
  		if (binding == null)
  			return false;
  
  		int kind= binding.getKind();
  
  		if (fMarkTypeOccurrences && kind == IBinding.TYPE)
  			return true;
  
  		if (fMarkMethodOccurrences && kind == IBinding.METHOD)
  			return true;
  
  		if (kind == IBinding.VARIABLE) {
  			IVariableBinding variableBinding= (IVariableBinding)binding;
  			if (variableBinding.isField()) {
  				int constantModifier= IModifierConstants.ACC_STATIC | IModifierConstants.ACC_FINAL;
  				boolean isConstant= (variableBinding.getModifiers() & constantModifier) == constantModifier;
  				if (isConstant)
  					return fMarkConstantOccurrences;
  				else
  					return fMarkFieldOccurrences;
  			}
  
  			return fMarkLocalVariableypeOccurrences;
  		}
  
  		return false;
  	}
  
  	void removeOccurrenceAnnotations() {
  		fMarkOccurrenceModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
  		fMarkOccurrenceTargetRegion= null;
  
  		IDocumentProvider documentProvider= getDocumentProvider();
  		if (documentProvider == null)
  			return;
  
  		IAnnotationModel annotationModel= documentProvider.getAnnotationModel(getEditorInput());
  		if (annotationModel == null || fOccurrenceAnnotations == null)
  			return;
  
  		synchronized (getLockObject(annotationModel)) {
  			if (annotationModel instanceof IAnnotationModelExtension) {
  				((IAnnotationModelExtension)annotationModel).replaceAnnotations(fOccurrenceAnnotations, null);
  			} else {
  				for (int i= 0, length= fOccurrenceAnnotations.length; i < length; i++)
  					annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
  			}
  			fOccurrenceAnnotations= null;
  		}
  	}
  
  	protected void uninstallOverrideIndicator() {
  		if (fOverrideIndicatorManager != null) {
  			fOverrideIndicatorManager.removeAnnotations();
  			fOverrideIndicatorManager= null;
  		}
  	}
  
  	protected void installOverrideIndicator(boolean provideAST) {
  		uninstallOverrideIndicator();
  		IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput());
  		final IJavaScriptElement inputElement= getInputJavaElement();
  
  		if (model == null || inputElement == null)
  			return;
  
  		fOverrideIndicatorManager= new OverrideIndicatorManager(model, inputElement, null);
  		
  		if (provideAST) {
  			JavaScriptUnit ast= JavaScriptPlugin.getDefault().getASTProvider().getAST(inputElement, ASTProvider.WAIT_ACTIVE_ONLY, getProgressMonitor());
  			fOverrideIndicatorManager.reconciled(ast, true, getProgressMonitor());
  		}
  	}
  
  	/**
  	 * Tells whether override indicators are shown.
  	 *
  	 * @return <code>true</code> if the override indicators are shown
  	 * 
  	 */
  	protected boolean isShowingOverrideIndicators() {
  		AnnotationPreference preference= getAnnotationPreferenceLookup().getAnnotationPreference(OverrideIndicatorManager.ANNOTATION_TYPE);
  		IPreferenceStore store= getPreferenceStore();
  		return getBoolean(store, preference.getHighlightPreferenceKey())
  			|| getBoolean(store, preference.getVerticalRulerPreferenceKey())
  			|| getBoolean(store, preference.getOverviewRulerPreferenceKey())
  			|| getBoolean(store, preference.getTextPreferenceKey());
  	}
  
  	/**
  	 * Returns the boolean preference for the given key.
  	 *
  	 * @param store the preference store
  	 * @param key the preference key
  	 * @return <code>true</code> if the key exists in the store and its value is <code>true</code>
  	 * 
  	 */
  	private boolean getBoolean(IPreferenceStore store, String key) {
  		return key != null && store.getBoolean(key);
  	}
  
  	/**
  	 * Determines whether the preference change encoded by the given event
  	 * changes the override indication.
  	 *
  	 * @param event the event to be investigated
  	 * @return <code>true</code> if event causes a change
  	 * 
  	 */
  	protected boolean affectsOverrideIndicatorAnnotations(PropertyChangeEvent event) {
  		String key= event.getProperty();
  		AnnotationPreference preference= getAnnotationPreferenceLookup().getAnnotationPreference(OverrideIndicatorManager.ANNOTATION_TYPE);
  		if (key == null || preference == null)
  			return false;
  
  		return key.equals(preference.getHighlightPreferenceKey())
  			|| key.equals(preference.getVerticalRulerPreferenceKey())
  			|| key.equals(preference.getOverviewRulerPreferenceKey())
  			|| key.equals(preference.getTextPreferenceKey());
  	}
  
  	/**
  	 * @return <code>true</code> if Semantic Highlighting is enabled.
  	 *
  	 * 
  	 */
  	private boolean isSemanticHighlightingEnabled() {
  		return SemanticHighlightings.isEnabled(getPreferenceStore());
  	}
  
  	/**
  	 * Install Semantic Highlighting.
  	 *
  	 * 
  	 */
  	private void installSemanticHighlighting() {
  		if (fSemanticManager == null) {
  			fSemanticManager= new SemanticHighlightingManager();
  			fSemanticManager.install(this, (JavaSourceViewer) getSourceViewer(), JavaScriptPlugin.getDefault().getJavaTextTools().getColorManager(), getPreferenceStore());
  		}
  	}
  
  	/**
  	 * Uninstall Semantic Highlighting.
  	 *
  	 * 
  	 */
  	private void uninstallSemanticHighlighting() {
  		if (fSemanticManager != null) {
  			fSemanticManager.uninstall();
  			fSemanticManager= null;
  		}
  	}
  
  	/**
  	 * Returns the Java element wrapped by this editors input.
  	 *
  	 * @return the Java element wrapped by this editors input.
  	 * 
  	 */
  	protected IJavaScriptElement getInputJavaElement() {
  		return EditorUtility.getEditorInputJavaElement(this, false);
  	}
  
  	protected void updateStatusLine() {
  		ITextSelection selection= (ITextSelection) getSelectionProvider().getSelection();
  		Annotation annotation= getAnnotation(selection.getOffset(), selection.getLength());
  		setStatusLineErrorMessage(null);
  		setStatusLineMessage(null);
  		if (annotation != null) {
  			updateMarkerViews(annotation);
  			if (annotation instanceof IJavaAnnotation && ((IJavaAnnotation) annotation).isProblem())
  				setStatusLineMessage(annotation.getText());
  		}
  	}
  
  	/**
  	 * Jumps to the matching bracket.
  	 */
  	public void gotoMatchingBracket() {
  
  		ISourceViewer sourceViewer= getSourceViewer();
  		IDocument document= sourceViewer.getDocument();
  		if (document == null)
  			return;
  
  		IRegion selection= getSignedSelection(sourceViewer);
  
  		int selectionLength= Math.abs(selection.getLength());
  		if (selectionLength > 1) {
  			setStatusLineErrorMessage(JavaEditorMessages.GotoMatchingBracket_error_invalidSelection);
  			sourceViewer.getTextWidget().getDisplay().beep();
  			return;
  		}
  
  		// #26314
  		int sourceCaretOffset= selection.getOffset() + selection.getLength();
  		if (isSurroundedByBrackets(document, sourceCaretOffset))
  			sourceCaretOffset -= selection.getLength();
  
  		IRegion region= fBracketMatcher.match(document, sourceCaretOffset);
  		if (region == null) {
  			setStatusLineErrorMessage(JavaEditorMessages.GotoMatchingBracket_error_noMatchingBracket);
  			sourceViewer.getTextWidget().getDisplay().beep();
  			return;
  		}
  
  		int offset= region.getOffset();
  		int length= region.getLength();
  
  		if (length < 1)
  			return;
  
  		int anchor= fBracketMatcher.getAnchor();
  		// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195
  		int targetOffset= (ICharacterPairMatcher.RIGHT == anchor) ? offset + 1: offset + length;
  
  		boolean visible= false;
  		if (sourceViewer instanceof ITextViewerExtension5) {
  			ITextViewerExtension5 extension= (ITextViewerExtension5) sourceViewer;
  			visible= (extension.modelOffset2WidgetOffset(targetOffset) > -1);
  		} else {
  			IRegion visibleRegion= sourceViewer.getVisibleRegion();
  			// http://dev.eclipse.org/bugs/show_bug.cgi?id=34195
  			visible= (targetOffset >= visibleRegion.getOffset() && targetOffset <= visibleRegion.getOffset() + visibleRegion.getLength());
  		}
  
  		if (!visible) {
  			setStatusLineErrorMessage(JavaEditorMessages.GotoMatchingBracket_error_bracketOutsideSelectedElement);
  			sourceViewer.getTextWidget().getDisplay().beep();
  			return;
  		}
  
  		if (selection.getLength() < 0)
  			targetOffset -= selection.getLength();
  
  		sourceViewer.setSelectedRange(targetOffset, selection.getLength());
  		sourceViewer.revealRange(targetOffset, selection.getLength());
  	}
  
  	/**
  	 * Returns the signed current selection.
  	 * The length will be negative if the resulting selection
  	 * is right-to-left (RtoL).
  	 * <p>
  	 * The selection offset is model based.
  	 * </p>
  	 *
  	 * @param sourceViewer the source viewer
  	 * @return a region denoting the current signed selection, for a resulting RtoL selections length is < 0
  	 */
  	protected IRegion getSignedSelection(ISourceViewer sourceViewer) {
  		StyledText text= sourceViewer.getTextWidget();
  		Point selection= text.getSelectionRange();
  
  		if (text.getCaretOffset() == selection.x) {
  			selection.x= selection.x + selection.y;
  			selection.y= -selection.y;
  		}
  
  		selection.x= widgetOffset2ModelOffset(sourceViewer, selection.x);
  
  		return new Region(selection.x, selection.y);
  	}
  
  	/**
  	 * Returns the cached selected range, which allows
  	 * to query it from a non-UI thread.
  	 * <p>
  	 * The result might be outdated if queried from a non-UI thread.</em></p>
  	 *
  	 * @return the caret offset in the master document
  	 * @see ITextViewer#getSelectedRange()
  	 * 
  	 */
  	public Point getCachedSelectedRange() {
  		return fCachedSelectedRange;
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged()
  	 * 
  	 */
  	protected void handleCursorPositionChanged() {
  		super.handleCursorPositionChanged();
  		fCachedSelectedRange= getViewer().getSelectedRange();
  	}
  
  	private static boolean isBracket(char character) {
  		for (int i= 0; i != BRACKETS.length; ++i)
  			if (character == BRACKETS[i])
  				return true;
  		return false;
  	}
  
  	private static boolean isSurroundedByBrackets(IDocument document, int offset) {
  		if (offset == 0 || offset == document.getLength())
  			return false;
  
  		try {
  			return
  				isBracket(document.getChar(offset - 1)) &&
  				isBracket(document.getChar(offset));
  
  		} catch (BadLocationException e) {
  			return false;
  		}
  	}
  
  	/**
  	 * {@inheritDoc}
  	 * <p>
  	 * Overrides the default implementation to handle {@link IJavaAnnotation}.
  	 * </p>
  	 *
  	 * @param offset the region offset
  	 * @param length the region length
  	 * @param forward <code>true</code> for forwards, <code>false</code> for backward
  	 * @param annotationPosition the position of the found annotation
  	 * @return the found annotation
  	 * 
  	 */
  	protected Annotation findAnnotation(final int offset, final int length, boolean forward, Position annotationPosition) {
  
  		Annotation nextAnnotation= null;
  		Position nextAnnotationPosition= null;
  		Annotation containingAnnotation= null;
  		Position containingAnnotationPosition= null;
  		boolean currentAnnotation= false;
  
  		IDocument document= getDocumentProvider().getDocument(getEditorInput());
  		int endOfDocument= document.getLength();
  		int distance= Integer.MAX_VALUE;
  
  		IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput());
  		Iterator e= new JavaAnnotationIterator(model, true, true);
  		while (e.hasNext()) {
  			Annotation a= (Annotation) e.next();
  			if ((a instanceof IJavaAnnotation) && ((IJavaAnnotation)a).hasOverlay() || !isNavigationTarget(a))
  				continue;
  
  			Position p= model.getPosition(a);
  			if (p == null)
  				continue;
  
  			if (forward && p.offset == offset || !forward && p.offset + p.getLength() == offset + length) {// || p.includes(offset)) {
  				if (containingAnnotation == null || (forward && p.length >= containingAnnotationPosition.length || !forward && p.length >= containingAnnotationPosition.length)) {
  					containingAnnotation= a;
  					containingAnnotationPosition= p;
  					currentAnnotation= p.length == length;
  				}
  			} else {
  				int currentDistance= 0;
  
  				if (forward) {
  					currentDistance= p.getOffset() - offset;
  					if (currentDistance < 0)
  						currentDistance= endOfDocument + currentDistance;
  
  					if (currentDistance < distance || currentDistance == distance && p.length < nextAnnotationPosition.length) {
  						distance= currentDistance;
  						nextAnnotation= a;
  						nextAnnotationPosition= p;
  					}
  				} else {
  					currentDistance= offset + length - (p.getOffset() + p.length);
  					if (currentDistance < 0)
  						currentDistance= endOfDocument + currentDistance;
  
  					if (currentDistance < distance || currentDistance == distance && p.length < nextAnnotationPosition.length) {
  						distance= currentDistance;
  						nextAnnotation= a;
  						nextAnnotationPosition= p;
  					}
  				}
  			}
  		}
  		if (containingAnnotationPosition != null && (!currentAnnotation || nextAnnotation == null)) {
  			annotationPosition.setOffset(containingAnnotationPosition.getOffset());
  			annotationPosition.setLength(containingAnnotationPosition.getLength());
  			return containingAnnotation;
  		}
  		if (nextAnnotationPosition != null) {
  			annotationPosition.setOffset(nextAnnotationPosition.getOffset());
  			annotationPosition.setLength(nextAnnotationPosition.getLength());
  		}
  
  		return nextAnnotation;
  	}
  
  	/**
  	 * Returns the annotation overlapping with the given range or <code>null</code>.
  	 *
  	 * @param offset the region offset
  	 * @param length the region length
  	 * @return the found annotation or <code>null</code>
  	 * 
  	 */
  	private Annotation getAnnotation(int offset, int length) {
  		IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput());
  		Iterator e= new JavaAnnotationIterator(model, true, false);
  		while (e.hasNext()) {
  			Annotation a= (Annotation) e.next();
  			Position p= model.getPosition(a);
  			if (p != null && p.overlapsWith(offset, length))
  				return a;
  		}
  		return null;
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#gotoAnnotation(boolean)
  	 * 
  	 */
  	public Annotation gotoAnnotation(boolean forward) {
  		fSelectionChangedViaGotoAnnotation= true;
  		return super.gotoAnnotation(forward);
  	}
  	
  	/**
  	 * Computes and returns the source reference that includes the caret and
  	 * serves as provider for the outline page selection and the editor range
  	 * indication.
  	 *
  	 * @return the computed source reference
  	 * 
  	 */
  	protected ISourceReference computeHighlightRangeSourceReference() {
  		ISourceViewer sourceViewer= getSourceViewer();
  		if (sourceViewer == null)
  			return null;
  
  		StyledText styledText= sourceViewer.getTextWidget();
  		if (styledText == null)
  			return null;
  
  		int caret= 0;
  		if (sourceViewer instanceof ITextViewerExtension5) {
  			ITextViewerExtension5 extension= (ITextViewerExtension5)sourceViewer;
  			caret= extension.widgetOffset2ModelOffset(styledText.getCaretOffset());
  		} else {
  			int offset= sourceViewer.getVisibleRegion().getOffset();
  			caret= offset + styledText.getCaretOffset();
  		}
  
  		IJavaScriptElement element= getElementAt(caret, false);
  
  		if ( !(element instanceof ISourceReference))
  			return null;
  
  		if (element.getElementType() == IJavaScriptElement.IMPORT_DECLARATION) {
  
  			IImportDeclaration declaration= (IImportDeclaration) element;
  			IImportContainer container= (IImportContainer) declaration.getParent();
  			ISourceRange srcRange= null;
  
  			try {
  				srcRange= container.getSourceRange();
  			} catch (JavaScriptModelException e) {
  			}
  
  			if (srcRange != null && srcRange.getOffset() == caret)
  				return container;
  		}
  
  		return (ISourceReference) element;
  	}
  
  	/**
  	 * Returns the most narrow java element including the given offset.
  	 *
  	 * @param offset the offset inside of the requested element
  	 * @param reconcile <code>true</code> if editor input should be reconciled in advance
  	 * @return the most narrow java element
  	 * 
  	 */
  	protected IJavaScriptElement getElementAt(int offset, boolean reconcile) {
  		return getElementAt(offset);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createChangeHover()
  	 */
  	protected LineChangeHover createChangeHover() {
  		return new JavaChangeHover(IJavaScriptPartitions.JAVA_PARTITIONING, getOrientation());
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions()
  	 */
  	protected void createNavigationActions() {
  		super.createNavigationActions();
  
  		final StyledText textWidget= getSourceViewer().getTextWidget();
  
  		IAction action= new SmartLineStartAction(textWidget, false);
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.LINE_START);
  		setAction(ITextEditorActionDefinitionIds.LINE_START, action);
  
  		action= new SmartLineStartAction(textWidget, true);
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_LINE_START);
  		setAction(ITextEditorActionDefinitionIds.SELECT_LINE_START, action);
  
  		action= new NavigatePreviousSubWordAction();
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
  		setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
  		textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
  
  		action= new NavigateNextSubWordAction();
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
  		setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
  		textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
  
  		action= new SelectPreviousSubWordAction();
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
  		setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
  		textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
  
  		action= new SelectNextSubWordAction();
  		action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
  		setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
  		textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createAnnotationRulerColumn(org.eclipse.jface.text.source.CompositeRuler)
  	 * 
  	 */
  	protected IVerticalRulerColumn createAnnotationRulerColumn(CompositeRuler ruler) {
  		if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER))
  			return super.createAnnotationRulerColumn(ruler);
  
  		AnnotationRulerColumn column= new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess());
  		column.setHover(new JavaExpandHover(ruler, getAnnotationAccess(), new IDoubleClickListener() {
  
  			public void doubleClick(DoubleClickEvent event) {
  				// for now: just invoke ruler double click action
  				triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
  			}
  
  			private void triggerAction(String actionID) {
  				IAction action= getAction(actionID);
  				if (action != null) {
  					if (action instanceof IUpdate)
  						((IUpdate) action).update();
  					// hack to propagate line change
  					if (action instanceof ISelectionListener) {
  						((ISelectionListener)action).selectionChanged(null, null);
  					}
  					if (action.isEnabled())
  						action.run();
  				}
  			}
  
  		}));
  		
  		return column;
  	}
  
  	/**
  	 * Returns the folding action group, or <code>null</code> if there is none.
  	 *
  	 * @return the folding action group, or <code>null</code> if there is none
  	 * 
  	 */
  	protected FoldingActionGroup getFoldingActionGroup() {
  		return fFoldingGroup;
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#performRevert()
  	 */
  	protected void performRevert() {
  		ProjectionViewer projectionViewer= (ProjectionViewer) getSourceViewer();
  		projectionViewer.setRedraw(false);
  		try {
  
  			boolean projectionMode= projectionViewer.isProjectionMode();
  			if (projectionMode) {
  				projectionViewer.disableProjection();
  				if (fProjectionModelUpdater != null)
  					fProjectionModelUpdater.uninstall();
  			}
  
  			super.performRevert();
  
  			if (projectionMode) {
  				if (fProjectionModelUpdater != null)
  					fProjectionModelUpdater.install(this, projectionViewer);
  				projectionViewer.enableProjection();
  			}
  
  		} finally {
  			projectionViewer.setRedraw(true);
  		}
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#rulerContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager)
  	 */
  	protected void rulerContextMenuAboutToShow(IMenuManager menu) {
  		super.rulerContextMenuAboutToShow(menu);
  		IMenuManager foldingMenu= new MenuManager(JavaEditorMessages.Editor_FoldingMenu_name, "projection"); //$NON-NLS-1$
  		menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, foldingMenu);
  
  		IAction action= getAction("FoldingToggle"); //$NON-NLS-1$
  		foldingMenu.add(action);
  		action= getAction("FoldingExpandAll"); //$NON-NLS-1$
  		foldingMenu.add(action);
  		action= getAction("FoldingCollapseAll"); //$NON-NLS-1$
  		foldingMenu.add(action);
  		action= getAction("FoldingRestore"); //$NON-NLS-1$
  		foldingMenu.add(action);
  		action= getAction("FoldingCollapseMembers"); //$NON-NLS-1$
  		foldingMenu.add(action);
  		action= getAction("FoldingCollapseComments"); //$NON-NLS-1$
  		foldingMenu.add(action);
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#collectContextMenuPreferencePages()
  	 * 
  	 */
  	protected String[] collectContextMenuPreferencePages() {
  		String[] inheritedPages= super.collectContextMenuPreferencePages();
  		int length= 10;
  		String[] result= new String[inheritedPages.length + length];
  		result[0]= "org.eclipse.wst.jsdt.ui.preferences.JavaEditorPreferencePage"; //$NON-NLS-1$
  		result[1]= "org.eclipse.wst.jsdt.ui.preferences.JavaTemplatePreferencePage"; //$NON-NLS-1$
  		result[2]= "org.eclipse.wst.jsdt.ui.preferences.CodeAssistPreferencePage"; //$NON-NLS-1$
  		result[3]= "org.eclipse.wst.jsdt.ui.preferences.CodeAssistPreferenceAdvanced"; //$NON-NLS-1$
  		result[4]= "org.eclipse.wst.jsdt.ui.preferences.JavaEditorHoverPreferencePage"; //$NON-NLS-1$
  		result[5]= "org.eclipse.wst.jsdt.ui.preferences.JavaEditorColoringPreferencePage"; //$NON-NLS-1$
  		result[6]= "org.eclipse.wst.jsdt.ui.preferences.FoldingPreferencePage"; //$NON-NLS-1$
  		result[7]= "org.eclipse.wst.jsdt.ui.preferences.MarkOccurrencesPreferencePage"; //$NON-NLS-1$
  		result[8]= "org.eclipse.wst.jsdt.ui.preferences.SmartTypingPreferencePage"; //$NON-NLS-1$
  		result[9]= "org.eclipse.wst.jsdt.ui.preferences.SaveParticipantPreferencePage"; //$NON-NLS-1$
  		System.arraycopy(inheritedPages, 0, result, length, inheritedPages.length);
  		return result;
  	}
  	
  	/*
  	 * @see AbstractTextEditor#getUndoRedoOperationApprover(IUndoContext)
  	 * 
  	 */
  	protected IOperationApprover getUndoRedoOperationApprover(IUndoContext undoContext) {
  		// since IResource is a more general way to compare java elements, we
  		// use this as the preferred class for comparing objects.
  		return new NonLocalUndoUserApprover(undoContext, this, new Object [] { getInputJavaElement() }, IResource.class);
  	}
  
  	/**
  	 * Resets the foldings structure according to the folding
  	 * preferences.
  	 * 
  	 * 
  	 */
  	public void resetProjection() {
  		if (fProjectionModelUpdater != null) {
  			fProjectionModelUpdater.initialize();
  		}
  	}
  	
  	/**
  	 * Collapses all foldable members if supported by the folding
  	 * structure provider.
  	 * 
  	 * 
  	 */
  	public void collapseMembers() {
  		if (fProjectionModelUpdater instanceof IJavaFoldingStructureProviderExtension) {
  			IJavaFoldingStructureProviderExtension extension= (IJavaFoldingStructureProviderExtension) fProjectionModelUpdater;
  			extension.collapseMembers();
  		}
  	}
  	
  	/**
  	 * Collapses all foldable comments if supported by the folding
  	 * structure provider.
  	 * 
  	 * 
  	 */
  	public void collapseComments() {
  		if (fProjectionModelUpdater instanceof IJavaFoldingStructureProviderExtension) {
  			IJavaFoldingStructureProviderExtension extension= (IJavaFoldingStructureProviderExtension) fProjectionModelUpdater;
  			extension.collapseComments();
  		}
  	}
  }
  