/*******************************************************************************
 * Copyright (c) 2001, 2020 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Jens Lukowski/Innoopract - initial renaming/restructuring
 *     
 *******************************************************************************/
package org.eclipse.wst.sse.ui;

import java.io.IOException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.content.IContentTypeSettings;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
import org.eclipse.emf.common.command.Command;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.text.AbstractInformationControlManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IBlockTextSelection;
import org.eclipse.jface.text.IDocument;
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.ITextHover;
import org.eclipse.jface.text.ITextOperationTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.contentassist.ContentAssistEvent;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.ICompletionListener;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.information.IInformationPresenter;
import org.eclipse.jface.text.information.IInformationProvider;
import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.ContentAssistantFacade;
import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
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.util.SafeRunnable;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
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.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.VerifyKeyListener;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dnd.IDragAndDropService;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.editors.text.ITextEditorHelpContextIds;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.help.IWorkbenchHelpSystem;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.DefaultRangeIndicator;
import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IStatusField;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.ITextEditorExtension;
import org.eclipse.ui.texteditor.ITextEditorExtension2;
import org.eclipse.ui.texteditor.ITextEditorExtension3;
import org.eclipse.ui.texteditor.ITextEditorExtension4;
import org.eclipse.ui.texteditor.ITextEditorExtension5;
import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextOperationAction;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.document.IDocumentCharsetDetector;
import org.eclipse.wst.sse.core.internal.encoding.EncodingMemento;
import org.eclipse.wst.sse.core.internal.provisional.IModelStateListener;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.text.IExecutionDelegatable;
import org.eclipse.wst.sse.core.internal.undo.IStructuredTextUndoManager;
import org.eclipse.wst.sse.core.utils.StringUtils;
import org.eclipse.wst.sse.ui.internal.DefaultTextTransferDropTargetAdapterProxy;
import org.eclipse.wst.sse.ui.internal.ExtendedConfigurationBuilder;
import org.eclipse.wst.sse.ui.internal.ExtendedEditorActionBuilder;
import org.eclipse.wst.sse.ui.internal.ExtendedEditorDropTargetAdapter;
import org.eclipse.wst.sse.ui.internal.IExtendedContributor;
import org.eclipse.wst.sse.ui.internal.IModelProvider;
import org.eclipse.wst.sse.ui.internal.IPopupMenuContributor;
import org.eclipse.wst.sse.ui.internal.IStructuredTextEditorActionConstants;
import org.eclipse.wst.sse.ui.internal.Logger;
import org.eclipse.wst.sse.ui.internal.ReadOnlyAwareDropTargetAdapter;
import org.eclipse.wst.sse.ui.internal.SSEUIMessages;
import org.eclipse.wst.sse.ui.internal.SSEUIPlugin;
import org.eclipse.wst.sse.ui.internal.StorageModelProvider;
import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
import org.eclipse.wst.sse.ui.internal.UnknownContentTypeDialog;
import org.eclipse.wst.sse.ui.internal.UnknownContentTypeDialog2;
import org.eclipse.wst.sse.ui.internal.actions.ActionDefinitionIds;
import org.eclipse.wst.sse.ui.internal.actions.StructuredTextEditorActionConstants;
import org.eclipse.wst.sse.ui.internal.contentoutline.ConfigurableContentOutlinePage;
import org.eclipse.wst.sse.ui.internal.debug.BreakpointRulerAction;
import org.eclipse.wst.sse.ui.internal.debug.EditBreakpointAction;
import org.eclipse.wst.sse.ui.internal.debug.ManageBreakpointAction;
import org.eclipse.wst.sse.ui.internal.debug.ToggleBreakpointAction;
import org.eclipse.wst.sse.ui.internal.debug.ToggleBreakpointsTarget;
import org.eclipse.wst.sse.ui.internal.derived.HTMLTextPresenter;
import org.eclipse.wst.sse.ui.internal.editor.EditorModelUtil;
import org.eclipse.wst.sse.ui.internal.editor.IHelpContextIds;
import org.eclipse.wst.sse.ui.internal.editor.StructuredModelDocumentProvider;
import org.eclipse.wst.sse.ui.internal.extension.BreakpointProviderBuilder;
import org.eclipse.wst.sse.ui.internal.handlers.AddBlockCommentHandler;
import org.eclipse.wst.sse.ui.internal.handlers.RemoveBlockCommentHandler;
import org.eclipse.wst.sse.ui.internal.handlers.ToggleLineCommentHandler;
import org.eclipse.wst.sse.ui.internal.hyperlink.OpenHyperlinkAction;
import org.eclipse.wst.sse.ui.internal.preferences.EditorPreferenceNames;
import org.eclipse.wst.sse.ui.internal.properties.ConfigurablePropertySheetPage;
import org.eclipse.wst.sse.ui.internal.properties.ShowPropertiesAction;
import org.eclipse.wst.sse.ui.internal.provisional.extensions.ConfigurationPointCalculator;
import org.eclipse.wst.sse.ui.internal.provisional.extensions.ISourceEditingTextTools;
import org.eclipse.wst.sse.ui.internal.provisional.extensions.breakpoint.NullSourceEditingTextTools;
import org.eclipse.wst.sse.ui.internal.provisional.preferences.CommonEditorPreferenceNames;
import org.eclipse.wst.sse.ui.internal.quickoutline.QuickOutlineHandler;
import org.eclipse.wst.sse.ui.internal.quickoutline.QuickOutlinePopupDialog;
import org.eclipse.wst.sse.ui.internal.reconcile.DirtyRegionProcessor;
import org.eclipse.wst.sse.ui.internal.reconcile.DocumentRegionProcessor;
import org.eclipse.wst.sse.ui.internal.selection.SelectionHistory;
import org.eclipse.wst.sse.ui.internal.style.SemanticHighlightingManager;
import org.eclipse.wst.sse.ui.internal.text.DocumentRegionEdgeMatcher;
import org.eclipse.wst.sse.ui.internal.text.SourceInfoProvider;
import org.eclipse.wst.sse.ui.internal.util.Assert;
import org.eclipse.wst.sse.ui.internal.util.EditorUtility;
import org.eclipse.wst.sse.ui.preferences.AppearancePreferenceNames;
import org.eclipse.wst.sse.ui.preferences.StructuredTextEditorPreferencePage;
import org.eclipse.wst.sse.ui.quickoutline.AbstractQuickOutlineConfiguration;
import org.eclipse.wst.sse.ui.reconcile.ISourceReconcilingListener;
import org.eclipse.wst.sse.ui.typing.AbstractCharacterPairInserter;
import org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration;
import org.eclipse.wst.sse.ui.views.properties.PropertySheetConfiguration;

/**
 * A Text Editor for editing structured models and structured documents.
 * <p>This class is not meant to be subclassed.</p>
 * <p>
 * New content types may associate source viewer, content outline, and
 * property sheet configurations to extend the existing functionality.
 * </p>
 * 
 * @see org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration
 * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration
 * @see org.eclipse.wst.sse.ui.views.properties.PropertySheetConfiguration
 * 
 * @since 1.0
 */
public class StructuredTextEditor extends TextEditor {
	private class GotoMatchingBracketHandler extends AbstractHandler {
		@Override
		public Object execute(ExecutionEvent event) throws ExecutionException {
			gotoMatchingBracket();
			return null;
		}
	}

	private class InternalModelStateListener implements IModelStateListener {
		@Override
		public void modelAboutToBeChanged(IStructuredModel model) {
			if (getTextViewer() != null) {
				// getTextViewer().setRedraw(false);
			}
		}

		@Override
		public void modelAboutToBeReinitialized(IStructuredModel structuredModel) {
			if (getTextViewer() != null) {
				// getTextViewer().setRedraw(false);
				getTextViewer().unconfigure();
				setStatusLineMessage(null);
			}
		}

		@Override
		public void modelChanged(IStructuredModel model) {
			if (getSourceViewer() != null) {
				// getTextViewer().setRedraw(true);
				// Since the model can be changed on a background
				// thread, we will update menus on display thread,
				// if we are not already on display thread,
				// and if there is not an update already pending.
				// (we can get lots of 'modelChanged' events in rapid
				// succession, so only need to do one.
				if (!fUpdateMenuTextPending) {
					runOnDisplayThreadIfNeededed(new Runnable() {
						@Override
						public void run() {
							updateMenuText();
							fUpdateMenuTextPending = false;
						}
					});
				}

			}
		}

		@Override
		public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) {
			// do nothing
		}

		@Override
		public void modelReinitialized(IStructuredModel structuredModel) {
			try {
				if (getSourceViewer() != null) {
					SourceViewerConfiguration cfg = getSourceViewerConfiguration();
					getSourceViewer().configure(cfg);
				}
			}
			catch (Exception e) {
				// https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=1166
				// investigate each error case post beta
				Logger.logException("problem trying to configure after model change", e); //$NON-NLS-1$
			}
			finally {
				// so we don't freeze workbench (eg. during page language or
				// content type change)
				((ITextViewerExtension) getSourceViewer()).setRedraw(true);
				
				IWorkbenchSiteProgressService service = getSite().getService(IWorkbenchSiteProgressService.class);
				if (service != null) {
					service.warnOfContentChange();
				}
			}
		}// Note: this one should probably be used to
		// control viewer
		// instead of viewer having its own listener
		@Override
		public void modelResourceDeleted(IStructuredModel model) {
			// do nothing
		}

		@Override
		public void modelResourceMoved(IStructuredModel originalmodel, IStructuredModel movedmodel) {
			// do nothing
		}

		/**
		 * This 'Runnable' should be very brief, and should not "call out" to
		 * other code especially if it depends on the state of the model.
		 * 
		 * @param r
		 */
		private void runOnDisplayThreadIfNeededed(Runnable r) {
			// if there is no Display at all (that is, running headless),
			// or if we are already running on the display thread, then
			// simply execute the runnable.
			if (getDisplay() == null || (Thread.currentThread() == getDisplay().getThread())) {
				r.run();
			}
			else {
				// otherwise force the runnable to run on the display thread.
				getDisplay().asyncExec(r);
			}
		}
	}
	
	/**
	 * Listens to double-click and selection from the outline page
	 */
	private class OutlinePageListener implements IDoubleClickListener, ISelectionChangedListener {
		@Override
		public void doubleClick(DoubleClickEvent event) {
			if (event.getSelection().isEmpty())
				return;

			int start = -1;
			int length = 0;
			if (event.getSelection() instanceof IStructuredSelection) {
				ISelection currentSelection = getSelectionProvider().getSelection();
				if (currentSelection instanceof IStructuredSelection) {
					Object[] newObjects = ((IStructuredSelection) event.getSelection()).toArray();
					if (newObjects.length > 0) {
						IRegion highlightRange = fStructuredSelectionProvider.selectionConverter.getRegion(newObjects[0]);
						start = highlightRange.getOffset();
						length = highlightRange.getLength();
					}
				}
			}
			else if (event.getSelection() instanceof ITextSelection) {
				start = ((ITextSelection) event.getSelection()).getOffset();
				length = ((ITextSelection) event.getSelection()).getLength();
			}
			if (start > -1) {
				getSourceViewer().setRangeIndication(start, length, false);
				selectAndReveal(start, length);
			}
		}

		@Override
		public void selectionChanged(SelectionChangedEvent event) {
			/*
			 * Do not allow selection from other parts to affect selection in
			 * the text widget if it has focus, or if we're still firing a
			 * change of selection. Selection events "bouncing" off of other
			 * parts are all that we can receive if we have focus (since we
			 * forwarded our selection to the service just a moment ago), and
			 * only the user should affect selection if we have focus.
			 */

			/* The isFiringSelection check only works if a selection listener */
			if (event.getSelection().isEmpty() || fStructuredSelectionProvider.isFiringSelection())
				return;

			if (getSourceViewer() != null && getSourceViewer().getTextWidget() != null && !getSourceViewer().getTextWidget().isDisposed() && !getSourceViewer().getTextWidget().isFocusControl()) {
				int start = -1;
				int length = 0;
				IRegion selectionRegion = null;
				if (event.getSelection() instanceof IStructuredSelection) {
					ISelection current = getSelectionProvider().getSelection();
					if (current instanceof IStructuredSelection) {
						Object[] currentObjects = ((IStructuredSelection) current).toArray();
						Object[] newObjects = ((IStructuredSelection) event.getSelection()).toArray();
						if (!Arrays.equals(currentObjects, newObjects) && newObjects.length > 0) {
							// no ordering is guaranteed for multiple selection
							Object o = newObjects[0];
							IRegion region = fStructuredSelectionProvider.selectionConverter.getRegion(o);
							start = region.getOffset();
							int end = start + region.getLength();
							if (newObjects.length > 1) {
								for (int i = 1; i < newObjects.length; i++) {
									region = fStructuredSelectionProvider.selectionConverter.getRegion(newObjects[i]);
									start = Math.min(start, region.getOffset());
									end = Math.max(end, region.getOffset() + region.getLength());
								}
								length = end - start;
							}
						}
						if (newObjects.length == 1) {
							selectionRegion = fStructuredSelectionProvider.selectionConverter.getSelectionRegion(newObjects[0]);
						}
					}
				}
				else if (event.getSelection() instanceof ITextSelection) {
					start = ((ITextSelection) event.getSelection()).getOffset();
				}
				if (start > -1) {
					updateRangeIndication(event.getSelection());
					if (selectionRegion != null) {
						selectAndReveal(selectionRegion.getOffset(), selectionRegion.getLength());
					}
					else {
						selectAndReveal(start, length);
					}
				}
			}
		}
	}

	private class ShowInTargetListAdapter implements IShowInTargetList {
		/**
		 * Array of ID Strings that define the default show in targets for
		 * this editor.
		 * 
		 * @see org.eclipse.ui.part.IShowInTargetList#getShowInTargetIds()
		 * @return the array of ID Strings that define the default show in
		 *         targets for this editor.
		 */
		@Override
		public String[] getShowInTargetIds() {
			return fShowInTargetIds;
		}
	}

	/**
	 * A post selection provider that wraps the provider implemented in
	 * AbstractTextEditor to provide a StructuredTextSelection to post
	 * selection listeners. Listens to selection changes from the source
	 * viewer.
	 */
	private static class StructuredSelectionProvider implements IPostSelectionProvider, ISelectionValidator {
		/**
		 * A "hybrid" text and structured selection class containing the text
		 * selection and a list of selected model objects. The determination
		 * of which model objects matches the text selection is responsibility
		 * of the StructuredSelectionProvider which created this selection
		 * object.
		 */
		private static class StructuredTextSelection extends TextSelection implements IStructuredSelection {
			private Object[] selectedStructured;

			StructuredTextSelection(IDocument document, int offset, int length, Object[] selectedObjects) {
				super(document, offset, length);
				selectedStructured = selectedObjects;
			}

			StructuredTextSelection(IDocument document, ITextSelection selection, Object[] selectedObjects) {
				this(document, selection.getOffset(), selection.getLength(), selectedObjects);
			}

			@Override
			public Object getFirstElement() {
				Object[] selectedStructures = getSelectedStructures();
				return selectedStructures.length > 0 ? selectedStructures[0] : null;
			}

			private Object[] getSelectedStructures() {
				return (selectedStructured != null) ? selectedStructured : new Object[0];
			}

			@Override
			public boolean isEmpty() {
				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=191327
				return super.isEmpty() || getSelectedStructures().length == 0;
			}

			@Override
			public Iterator<?> iterator() {
				return toList().iterator();
			}

			@Override
			public int size() {
				return (selectedStructured != null) ? selectedStructured.length : 0;
			}

			@Override
			public Object[] toArray() {
				return getSelectedStructures();
			}

			@Override
			public List<?> toList() {
				return Arrays.asList(getSelectedStructures());
			}

			@Override
			public String toString() {
				return getOffset() + ":" + getLength() + "@" + getSelectedStructures(); //$NON-NLS-1$ //$NON-NLS-2$
			}
		}
		
		private ISelectionProvider fParentProvider = null;
		private boolean isFiringSelection = false;
		private ListenerList<ISelectionChangedListener> listeners = new ListenerList<>();
		private ListenerList<ISelectionChangedListener> postListeners = new ListenerList<>();
		private ISelection fLastSelection = null;
		private ISelectionProvider fLastSelectionProvider = null;
		private SelectionChangedEvent fLastUpdatedSelectionChangedEvent = null;
		private StructuredTextEditor fEditor;

		private ISelectionChangedListener selectionChangedListener = null;
		private ISelectionChangedListener postSelectionChangedListener = null;
		/*
		 * Responsible for finding the selected objects within a text
		 * selection. Set/reset by the StructuredTextEditor based on a
		 * per-model adapter on input.
		 */
		SelectionConverter selectionConverter = new SelectionConverter();
		
		StructuredSelectionProvider(ISelectionProvider parentProvider, StructuredTextEditor structuredTextEditor) {
			fParentProvider = parentProvider;
			fEditor = structuredTextEditor;
			selectionChangedListener = new ISelectionChangedListener() {
				@Override
				public void selectionChanged(SelectionChangedEvent event) {
					handleSelectionChanged(event);
				}
			};
			fParentProvider.addSelectionChangedListener(selectionChangedListener);
			if (fParentProvider instanceof IPostSelectionProvider) {
				postSelectionChangedListener = new ISelectionChangedListener() {
					@Override
					public void selectionChanged(SelectionChangedEvent event) {
						handlePostSelectionChanged(event);
					}
				};
				((IPostSelectionProvider) fParentProvider).addPostSelectionChangedListener(postSelectionChangedListener);
			}
		}

		@Override
		public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
			postListeners.add(listener);
		}

		@Override
		public void addSelectionChangedListener(ISelectionChangedListener listener) {
			listeners.add(listener);
		}

		public void dispose() {
			if (selectionChangedListener != null) {
				fParentProvider.removeSelectionChangedListener(selectionChangedListener);
			}
			if (postSelectionChangedListener != null) {
				((IPostSelectionProvider) fParentProvider).removePostSelectionChangedListener(postSelectionChangedListener);
			}
			fEditor = null;
			listeners.clear();
			postListeners.clear();
			selectionConverter = null;
		}

		private void fireSelectionChanged(final SelectionChangedEvent event, ListenerList<ISelectionChangedListener> listenerList) {
			Object[] listeners = listenerList.getListeners();
			isFiringSelection = true;
			for (int i = 0; i < listeners.length; ++i) {
				final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
				SafeRunner.run(new SafeRunnable() {
					@Override
					public void run() {
						l.selectionChanged(event);
					}
				});
			}
			isFiringSelection = false;
		}

		private ISelectionProvider getParentProvider() {
			return fParentProvider;
		}

		@Override
		public ISelection getSelection() {
			fLastSelection = null;
			fLastSelectionProvider = null;
			fLastUpdatedSelectionChangedEvent = null;

			/*
			 * When a client explicitly asks for selection, provide the hybrid
			 * result.
			 */
			ISelection selection = getParentProvider().getSelection();
			if (!(selection instanceof IStructuredSelection) && selection instanceof ITextSelection) {
				IStructuredModel structuredModel = null;
				StructuredTextEditor localEditor = getStructuredTextEditor();
				if (localEditor != null) {
					structuredModel = localEditor.getInternalModel();
					if (structuredModel != null) {
						if (localEditor.isBlockSelectionModeEnabled()) {
							/*
							 * Block selection handling - find the overlapping
							 * objects on each line, keeping in mind that the
							 * selected block may not overlap actual lines or
							 * columns of the document.
							 * IBlockTextSelection.getRegions() should handle
							 * that for us...
							 */
							IBlockTextSelection blockSelection = (IBlockTextSelection) selection;
							IRegion[] regions = blockSelection.getRegions();
							Set<Object> blockObjects = new LinkedHashSet<>();
							for (int i = 0; i < regions.length; i++) {
								Object[] objects = selectionConverter.getElements(structuredModel, regions[i].getOffset(), regions[i].getLength());
								for (int j = 0; j < objects.length; j++) {
									blockObjects.add(objects[j]);
								}
							}
							selection = new StructuredTextSelection(getDocument(), (ITextSelection) selection, blockObjects.toArray());
						}
						else {
							int start = ((ITextSelection) selection).getOffset();
							int end = start + ((ITextSelection) selection).getLength();
							selection = new StructuredTextSelection(getDocument(), (ITextSelection) selection, selectionConverter.getElements(structuredModel, start, end));
						}
					}
				}
			}
			
			return selection;
		}

		private StructuredTextEditor getStructuredTextEditor() {
			return fEditor;
		}

		void handlePostSelectionChanged(SelectionChangedEvent event) {
			SelectionChangedEvent updatedEvent = null;
			if (fLastSelection == event.getSelection() && fLastSelectionProvider == event.getSelectionProvider()) {
				updatedEvent = fLastUpdatedSelectionChangedEvent;
			}
			else {
				updatedEvent = updateEvent(event);
			}
			// only update the range indicator on post selection
			StructuredTextEditor localEditor = fEditor;

			if (localEditor != null) {
				localEditor.updateRangeIndication(updatedEvent.getSelection());
				fireSelectionChanged(updatedEvent, postListeners);
			}
		}

		void handleSelectionChanged(SelectionChangedEvent event) {
			SelectionChangedEvent updatedEvent = event;
			if (fLastSelection != event.getSelection() || fLastSelectionProvider != event.getSelectionProvider()) {
				fLastSelection = event.getSelection();
				fLastSelectionProvider = event.getSelectionProvider();
				fLastUpdatedSelectionChangedEvent = updatedEvent = updateEvent(event);
			}
			fireSelectionChanged(updatedEvent, listeners);
		}

		IDocument getDocument() {
			return fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
		}


		boolean isFiringSelection() {
			return isFiringSelection;
		}

		@Override
		public boolean isValid(ISelection selection) {
			// ISSUE: is not clear default behavior should be true?
			// But not clear is this default would apply for our editor.
			boolean result = true;
			// if editor is "gone", can not be valid
			StructuredTextEditor e = getStructuredTextEditor();
			if (e == null || e.fEditorDisposed) {
				result = false;
			}
			// else defer to parent
			else if (getParentProvider() instanceof ISelectionValidator) {
				result = ((ISelectionValidator) getParentProvider()).isValid(selection);
			}
			return result;
		}

		@Override
		public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
			postListeners.remove(listener);
		}

		@Override
		public void removeSelectionChangedListener(ISelectionChangedListener listener) {
			listeners.remove(listener);
		}

		@Override
		public void setSelection(ISelection selection) {
			if (isFiringSelection()) {
				return;
			}

			fLastSelection = null;
			fLastSelectionProvider = null;
			fLastUpdatedSelectionChangedEvent = null;

			ISelection textSelection = updateSelection(selection);
			getParentProvider().setSelection(textSelection);
			StructuredTextEditor localEditor = getStructuredTextEditor();
			if (localEditor != null) {
				localEditor.updateRangeIndication(textSelection);
			}
		}

		/**
		 * Create a corresponding event that contains a
		 * StructuredTextselection
		 * 
		 * @param event
		 * @return
		 */
		private SelectionChangedEvent updateEvent(SelectionChangedEvent event) {
			ISelection selection = event.getSelection();
			if (selection instanceof ITextSelection && !(selection instanceof IStructuredSelection)) {
				IStructuredModel structuredModel = null;
				StructuredTextEditor localEditor = getStructuredTextEditor();
				if (localEditor != null) {
					structuredModel = localEditor.getInternalModel();
					if (structuredModel != null) {
						int start = ((ITextSelection) selection).getOffset();
						int end = ((ITextSelection) selection).getLength() + start;
						selection = new StructuredTextSelection(getDocument(), (ITextSelection) event.getSelection(), selectionConverter.getElements(structuredModel, start, end));
					}
				}
			}
			SelectionChangedEvent newEvent = new SelectionChangedEvent(event.getSelectionProvider(), selection);
			return newEvent;
		}

		/**
		 * Create a corresponding StructuredTextselection
		 * 
		 * @param selection
		 * @return
		 */
		private ISelection updateSelection(ISelection selection) {
			ISelection updated = selection;
			if (selection instanceof IStructuredSelection && !(selection instanceof ITextSelection) && !selection.isEmpty()) {
				Object[] selectedObjects = ((IStructuredSelection) selection).toArray();
				if (selectedObjects.length > 0) {
					int start = -1;
					int length = 0;

					// no ordering is guaranteed for multiple selection
					Object o = selectedObjects[0];
					IRegion region = selectionConverter.getRegion(o);
					start = region.getOffset();
					int end = start + region.getLength();
					if (selectedObjects.length > 1) {
						for (int i = 1; i < selectedObjects.length; i++) {
							region = selectionConverter.getRegion(selectedObjects[i]);
							start = Math.min(start, region.getOffset());
							end = Math.max(end, region.getOffset() + region.getLength());
						}
						length = end - start;
					}

					if (start > -1) {
						updated = new StructuredTextSelection(getDocument(), start, length, selectedObjects);
					}
				}
			}
			return updated;
		}
	}

	class TimeOutExpired extends TimerTask {
		@Override
		public void run() {
			final byte[] result = new byte[1]; // Did the busy state end successfully?
			getDisplay().syncExec(new Runnable() {
				@Override
				public void run() {
					if (getDisplay() != null && !getDisplay().isDisposed())
						endBusyStateInternal(result);
				}
			});
			if (result[0] == 1) {
				fBusyTimer.cancel();
			}
		}

	}

	private class ConfigurationAndTarget {
		private String fTargetId;
		private StructuredTextViewerConfiguration fConfiguration;

		public ConfigurationAndTarget(String targetId, StructuredTextViewerConfiguration config) {
			fTargetId = targetId;
			fConfiguration = config;
		}

		public String getTargetId() {
			return fTargetId;
		}

		public StructuredTextViewerConfiguration getConfiguration() {
			return fConfiguration;
		}
	}

	private class CharacterPairListener implements VerifyKeyListener {
		private CharacterPairing[] fInserters = new CharacterPairing[0];
		private ICompletionListener fCompletionListener;
		private boolean fIsCompleting = false;

		public void installCompletionListener() {
			ISourceViewer viewer = getSourceViewer();
			if (viewer instanceof StructuredTextViewer) {
				fCompletionListener = new ICompletionListener() {

					@Override
					public void assistSessionStarted(ContentAssistEvent event) {
						fIsCompleting = true;
					}

					@Override
					public void assistSessionEnded(ContentAssistEvent event) {
						fIsCompleting = false;
					}

					@Override
					public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
					}
					
				};
				ContentAssistantFacade facade = ((StructuredTextViewer) viewer).getContentAssistFacade();
				if (facade != null)
					facade.addCompletionListener(fCompletionListener);
			}
		}

		/**
		 * Add the pairing to the list of inserters
		 * @param pairing
		 */
		void addInserter(CharacterPairing pairing) {
			List<CharacterPairing> pairings = new ArrayList<>(Arrays.asList(fInserters));
			pairings.add(pairing);
			fInserters = pairings.toArray(new CharacterPairing[pairings.size()]);
		}

		void prioritize() {
			Arrays.sort(fInserters);
		}

		/**
		 * Perform cleanup on the character pair inserters
		 */
		void dispose() {
			ISourceViewer viewer = getSourceViewer();
			if (viewer instanceof StructuredTextViewer) {
				ContentAssistantFacade facade = ((StructuredTextViewer) viewer).getContentAssistFacade();
				if (facade != null)
					facade.removeCompletionListener(fCompletionListener);
			}

			for (int i = 0; i < fInserters.length; i++) {
				final AbstractCharacterPairInserter inserter = fInserters[i].inserter;
				SafeRunner.run(new ISafeRunnable() {
					@Override
					public void handleException(Throwable exception) {
						// rely on default logging
					}

					@Override
					public void run() throws Exception {
						inserter.dispose();
					}
				});
			}
		}

		@Override
		public void verifyKey(final VerifyEvent event) {
			if (!event.doit || getInsertMode() != SMART_INSERT || fIsCompleting || isBlockSelectionModeEnabled() && isMultilineSelection())
				return;
			final boolean[] paired = { false };
			for (int i = 0; i < fInserters.length; i++) {
				final CharacterPairing pairing = fInserters[i];
				// use a SafeRunner -- this is a critical function (typing)
				SafeRunner.run(new ISafeRunnable() {
					@Override
					public void run() throws Exception {
						final AbstractCharacterPairInserter inserter = pairing.inserter;
						if (inserter.hasPair(event.character)) {
							if (pair(event, inserter, pairing.partitions))
								paired[0] = true;
						}
					}

					@Override
					public void handleException(Throwable exception) {
						// rely on default logging
					}
				});
				if (paired[0])
					return;
			}
		}

		private boolean pair(VerifyEvent event, AbstractCharacterPairInserter inserter, Set<String> partitions) {
			final ISourceViewer viewer = getSourceViewer();
			final IDocument document = getSourceViewer().getDocument();
			if (document != null) {
				try {
					final Point selection = viewer.getSelectedRange();
					final int offset = selection.x;
					final ITypedRegion partition = document.getPartition(offset);
					if (partitions.contains(partition.getType())) {
						// Don't modify if the editor input cannot be changed
						if (!validateEditorInputState())
							return false;
						event.doit = !inserter.pair(viewer, event.character);
						return true;
					}
				} catch (BadLocationException e) {
				}
			}
			return false;
		}

		private boolean isMultilineSelection() {
			ISelection selection = getSelectionProvider().getSelection();
			if (selection instanceof ITextSelection) {
				ITextSelection ts = (ITextSelection) selection;
				return ts.getStartLine() != ts.getEndLine();
			}
			return false;
		}
	}

	/**
	 * Representation of a character pairing that includes its priority based on
	 * its content type and how close it is to the content type of the file
	 * in the editor.
	 */
	private class CharacterPairing implements Comparable<CharacterPairing> {
		int priority;
		AbstractCharacterPairInserter inserter;
		Set<String> partitions;

		@Override
		public int compareTo(CharacterPairing o) {
			if (o == this)
				return 0;
			return this.priority - o.priority;
		}
	}
	
	private class PartListener implements IPartListener {

		private ITextEditor fEditor;

		public PartListener(ITextEditor editor) {
			fEditor = editor;
		}

		@Override
		public void partActivated(IWorkbenchPart part) {
			if (part.getAdapter(ITextEditor.class) == fEditor) {
				SourceViewerConfiguration sourceViewerConfiguration = getSourceViewerConfiguration();
				/*
				 * Guard against possible tight timing between part creation
				 * and viewer configuration
				 */
				if (sourceViewerConfiguration != null) {
					IReconciler reconciler = sourceViewerConfiguration.getReconciler(getSourceViewer());
					if (reconciler instanceof DocumentRegionProcessor) {
						((DocumentRegionProcessor) reconciler).forceReconciling();
					}
				}
			}
		}

		@Override
		public void partBroughtToTop(IWorkbenchPart part) {
		}

		@Override
		public void partClosed(IWorkbenchPart part) {
		}

		@Override
		public void partDeactivated(IWorkbenchPart part) {
		}

		@Override
		public void partOpened(IWorkbenchPart part) {
		}
		
	}

	/**
	 * Internal property change listener for handling changes in a preferences.
	 */
	private class PropertyChangeListener implements IPropertyChangeListener {
		@Override
		public void propertyChange(PropertyChangeEvent event) {
			handlePreferenceStoreChanged(event);
		}
	}

	/**
	 * Not API. May be removed in the future.
	 */
	protected final static char[] BRACKETS = {'{', '}', '(', ')', '[', ']'};

	private static final long BUSY_STATE_DELAY = 1000;
	/**
	 * Not API. May be removed in the future.
	 */
	protected static final String DOT = "."; //$NON-NLS-1$
	private static final String EDITOR_CONTEXT_MENU_ID = "org.eclipse.wst.sse.ui.StructuredTextEditor.EditorContext"; //$NON-NLS-1$
	private static final String EDITOR_CONTEXT_MENU_SUFFIX = ".source.EditorContext"; //$NON-NLS-1$

	/** Non-NLS strings */
	private static final String EDITOR_KEYBINDING_SCOPE_ID = "org.eclipse.wst.sse.ui.structuredTextEditorScope"; //$NON-NLS-1$
	/**
	 * Not API. May be removed in the future.
	 */
	public static final String GROUP_NAME_ADDITIONS = IWorkbenchActionConstants.MB_ADDITIONS; 

	private static final String REDO_ACTION_DESC = SSEUIMessages.Redo___0___UI_; // = "Redo: {0}."
	private static final String REDO_ACTION_DESC_DEFAULT = SSEUIMessages.Redo_Text_Change__UI_; // = "Redo Text Change."
	private static final String REDO_ACTION_TEXT = SSEUIMessages._Redo__0___Ctrl_Y_UI_; // = "&Redo {0} @Ctrl+Y"
	private static final String REDO_ACTION_TEXT_DEFAULT = SSEUIMessages._Redo_Text_Change__Ctrl_Y_UI_; // = "&Redo Text Change @Ctrl+Y"
	private static final String RULER_CONTEXT_MENU_ID = "org.eclipse.wst.sse.ui.StructuredTextEditor.RulerContext"; //$NON-NLS-1$
	private static final String RULER_CONTEXT_MENU_SUFFIX = ".source.RulerContext"; //$NON-NLS-1$

	private static final String UNDERSCORE = "_"; //$NON-NLS-1$
	/** Translatable strings */
	private static final String UNDO_ACTION_DESC = SSEUIMessages.Undo___0___UI_; // = "Undo: {0}."

	private static final String UNDO_ACTION_DESC_DEFAULT = SSEUIMessages.Undo_Text_Change__UI_; // = "Undo Text Change."
	private static final String UNDO_ACTION_TEXT = SSEUIMessages._Undo__0___Ctrl_Z_UI_; // = "&Undo {0} @Ctrl+Z"
	private static final String UNDO_ACTION_TEXT_DEFAULT = SSEUIMessages._Undo_Text_Change__Ctrl_Z_UI_; // = "&Undo Text Change @Ctrl+Z"

	/*
	 * The user will be prompted to associate the input's name with the
	 * content type matching this initialiation data value, if a model could
	 * not be built for the input, a value is given, and a content type was
	 * found for it.
	 */
	private static final String PREFERRED_CONTENT_TYPE_WHEN_UNSUPPORTED = "org.eclipse.wst.sse.ui.unsupported_preferred_default"; //$NON-NLS-1$

	// development time/debug variables only
	private int adapterRequests;

	private long adapterTime;
	private boolean fBackgroundJobEnded;
	private boolean fBusyState;
	private Timer fBusyTimer;
	boolean fDirtyBeforeDocumentEvent = false;
	int validateEditCount = 0;
	private ExtendedEditorDropTargetAdapter fDropAdapter;
	boolean fEditorDisposed = false;
	private IEditorPart fEditorPart;
	private InternalModelStateListener fInternalModelStateListener;
	private IContentOutlinePage fOutlinePage;

	private OutlinePageListener fOutlinePageListener = null;
	/** This editor's projection support */
	private ProjectionSupport fProjectionSupport;
	private IPropertySheetPage fPropertySheetPage;

	private ISourceReconcilingListener[] fReconcilingListeners = new ISourceReconcilingListener[0]; 
	private IPartListener fPartListener;

	/** The ruler context menu to be disposed. */
	private Menu fRulerContextMenu;
	/** The ruler context menu manager to be disposed. */
	private MenuManager fRulerContextMenuManager;

	String[] fShowInTargetIds = new String[]{IPageLayout.ID_OUTLINE, IPageLayout.ID_PROP_SHEET, IPageLayout.ID_MINIMAP_VIEW};

	private IAction fShowPropertiesAction = null;
	private IStructuredModel fStructuredModel;
	StructuredSelectionProvider fStructuredSelectionProvider = null;
	/** The text context menu to be disposed. */
	private Menu fTextContextMenu;
	/** The text context menu manager to be disposed. */
	private MenuManager fTextContextMenuManager;
	private String fViewerConfigurationTargetId;
	/** The selection history of the editor */
	private SelectionHistory fSelectionHistory;
	/** The information presenter. */
	private InformationPresenter fInformationPresenter;
	private boolean fUpdateMenuTextPending;
	/** The quick outline handler */
	private QuickOutlineHandler fOutlineHandler;

	/** initialization data from this instance's editor extension */
	private Map<?, ?> fInitializationData = null;

	private boolean shouldClose = false;
	private long startPerfTime;
	private boolean fisReleased;
	/**
	 * The action group for folding.
	 */
	private FoldingActionGroup fFoldingGroup;
	/**
	 * The specific preference store for appearance settings, since
	 * ChainedPreferenceStores are not writeable
	 */
	private IPreferenceStore fAppearancePreferenceStore;
	private IPropertyChangeListener fAppearancePropertyChangeListener;

	private ILabelProvider fStatusLineLabelProvider;

	private SemanticHighlightingManager fSemanticManager;
	
	private boolean fSelectionChangedFromGoto = false;

	private CharacterPairListener fPairInserter = new CharacterPairListener();


	/**
	 * Creates a new Structured Text Editor.
	 */
	public StructuredTextEditor() {
		super();
		initializeDocumentProvider(null);
	}

	private IStructuredModel aboutToSaveModel() {
		IStructuredModel model = getInternalModel();
		if (model != null) {
			model.aboutToChangeModel();
		}
		return model;
	}

	protected void addSourceMenuActions(IMenuManager menu) {
		IMenuManager subMenu= new MenuManager(SSEUIMessages.SourceMenu_label, IStructuredTextEditorActionConstants.SOURCE_CONTEXT_MENU_ID);
		subMenu.add(new Separator(IStructuredTextEditorActionConstants.SOURCE_BEGIN));
		subMenu.add(new Separator(IStructuredTextEditorActionConstants.SOURCE_ADDITIONS));
		subMenu.add(new Separator(IStructuredTextEditorActionConstants.SOURCE_END));
		menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, subMenu);
	}

	protected void addRefactorMenuActions(IMenuManager menu) {
		IMenuManager subMenu = new MenuManager(SSEUIMessages.RefactorMenu_label, IStructuredTextEditorActionConstants.REFACTOR_CONTEXT_MENU_ID);
		menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, subMenu);
	}

	protected void addContextMenuActions(IMenuManager menu) {
		// Only offer actions that affect the text if the viewer allows
		// modification and supports any of these operations

		// Some Design editors (DTD) rely on this view for their own uses
		menu.appendToGroup(IWorkbenchActionConstants.GROUP_ADD, fShowPropertiesAction);
	}

	private void addExtendedContextMenuActions(IMenuManager menu) {
		IEditorActionBarContributor c = getEditorSite().getActionBarContributor();
		if (c instanceof IPopupMenuContributor) {
			((IPopupMenuContributor) c).contributeToPopupMenu(menu);
		}
		else {
			ExtendedEditorActionBuilder builder = new ExtendedEditorActionBuilder();
			IExtendedContributor pmc = builder.readActionExtensions(getConfigurationPoints());
			if (pmc != null) {
				pmc.setActiveEditor(this);
				pmc.contributeToPopupMenu(menu);
			}
		}
	}

	protected void addExtendedRulerContextMenuActions(IMenuManager menu) {
		// none at this level
	}



	/**
	 * Starts background mode.
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 */
	void beginBackgroundOperation() {
		fBackgroundJobEnded = false;
		// if already in busy state, no need to do anything
		// and, we only start, or reset, the timed busy
		// state when we get the "endBackgroundOperation" call.
		if (!inBusyState()) {
			beginBusyStateInternal();
		}
	}

	private void beginBusyStateInternal() {

		fBusyState = true;
		startBusyTimer();

		ISourceViewer viewer = getSourceViewer();
		if (viewer instanceof StructuredTextViewer) {
			((StructuredTextViewer) viewer).beginBackgroundUpdate();

		}
		showBusy(true);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.ITextEditor#close(boolean)
	 */
	@Override
	public void close(final boolean save) {
		/*
		 * Instead of us closing directly, we have to close with our
		 * containing (multipage) editor, if it exists.
		 */
		if (getSite() == null) {
			// if site hasn't been set yet, then we're not
			// completely open
			// so set a flag not to open
			shouldClose = true;
		}
		else {
			final IEditorPart editorPart = getEditorPart();
			if (editorPart != null) {
				Display display = Display.getCurrent();
				if (display == null) {
					display = PlatformUI.getWorkbench().getDisplay();
				}
				if (!display.isDisposed()) {
					display.asyncExec(new Runnable() {
						/*
						 * There's really no way to tell how much later this
						 * might take place. Be paranoid.
						 */
						@Override
						public void run() {
							if (!PlatformUI.getWorkbench().isClosing()) {
								IWorkbenchPartSite site = editorPart.getSite();
								if (site != null) {
									IWorkbenchPage page = site.getPage();
									if (page != null) {
										page.closeEditor(editorPart, save);
									}
								}
							}
						}
					});
				}
			}
			else {
				super.close(save);
			}
		}
	}
	
	private void activateContexts(IContextService service) {
		if(service == null)
			return;
		
		String[] definitions = getDefinitions(getConfigurationPoints());
		
		if(definitions != null) {
			String[] contexts = null;
			for(int i = 0; i < definitions.length; i++) {
				contexts = StringUtils.unpack(definitions[i]);
				for(int j = 0; j < contexts.length; j++)
					service.activateContext(contexts[j].trim());
			}
		}
		
	}
	
	private String[] getDefinitions(String[] ids) {
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] definitions = null;
		
		/* Iterate through the configuration ids until one is found that has
		 * an activecontexts definition
		 */
		for(int i = 0; i < ids.length; i++) {
			definitions = builder.getDefinitions("activecontexts", ids[i]); //$NON-NLS-1$
			if(definitions != null && definitions.length > 0)
				return definitions;
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#collectContextMenuPreferencePages()
	 */
	@Override
	protected String[] collectContextMenuPreferencePages() {
		List<String> allIds = new ArrayList<>(0);

		// get contributed preference pages
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] configurationIds = getConfigurationPoints();
		for (int i = 0; i < configurationIds.length; i++) {
			String[] definitions = builder.getDefinitions("preferencepages", configurationIds[i]); //$NON-NLS-1$
			for (int j = 0; j < definitions.length; j++) {
				String someIds = definitions[j];
				if (someIds != null && someIds.length() > 0) {
					// supports multiple comma-delimited page IDs in one
					// element
					String[] ids = StringUtils.unpack(someIds);
					for (int k = 0; k < ids.length; k++) {
						// trim, just to keep things clean
						String id = ids[k].trim();
						if (!allIds.contains(id)) {
							allIds.add(id);
						}
					}
				}
			}
		}

		// add pages contributed by super
		String[] superPages = super.collectContextMenuPreferencePages();
		for (int m = 0; m < superPages.length; m++) {
			// trim, just to keep things clean
			String id = superPages[m].trim();
			if (!allIds.contains(id)) {
				allIds.add(id);
			}
		}

		return allIds.toArray(new String[0]);
	}

	/**
	 * Compute and set double-click action for the vertical ruler
	 */
	private void computeAndSetDoubleClickAction() {
		/*
		 * Make double-clicking on the ruler toggle a breakpoint instead of
		 * toggling a bookmark. For lines where a breakpoint won't be created,
		 * create a bookmark through the contributed RulerDoubleClick action.
		 */
		setAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK, new ToggleBreakpointAction(this, getVerticalRuler(), getAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK)));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.ExtendedTextEditor#configureSourceViewerDecorationSupport(org.eclipse.ui.texteditor.SourceViewerDecorationSupport)
	 */
	@Override
	protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
		support.setCharacterPairMatcher(createCharacterPairMatcher());
		support.setMatchingCharacterPainterPreferenceKeys(AppearancePreferenceNames.MATCHING_BRACKETS, AppearancePreferenceNames.MATCHING_BRACKETS_COLOR);

		super.configureSourceViewerDecorationSupport(support);
	}

	@Override
	protected void createActions() {
		super.createActions();
		ResourceBundle resourceBundle = SSEUIMessages.getResourceBundle();
		IWorkbenchHelpSystem helpSystem = SSEUIPlugin.getDefault().getWorkbench().getHelpSystem();
		// TextView Action - moving the selected text to
		// the clipboard
		// override the cut/paste/delete action to make
		// them run on read-only
		// files
		Action action = new TextOperationAction(resourceBundle, "Editor_Cut_", this, ITextOperationTarget.CUT); //$NON-NLS-1$
		action.setActionDefinitionId(IWorkbenchActionDefinitionIds.CUT);
		setAction(ITextEditorActionConstants.CUT, action);
		helpSystem.setHelp(action, IAbstractTextEditorHelpContextIds.CUT_ACTION);
		// TextView Action - inserting the clipboard
		// content at the current
		// position
		// override the cut/paste/delete action to make
		// them run on read-only
		// files
		action = new TextOperationAction(resourceBundle, "Editor_Paste_", this, ITextOperationTarget.PASTE); //$NON-NLS-1$
		action.setActionDefinitionId(IWorkbenchActionDefinitionIds.PASTE);
		setAction(ITextEditorActionConstants.PASTE, action);
		helpSystem.setHelp(action, IAbstractTextEditorHelpContextIds.PASTE_ACTION);
		// TextView Action - deleting the selected text or
		// if selection is
		// empty the character at the right of the current
		// position
		// override the cut/paste/delete action to make
		// them run on read-only
		// files
		action = new TextOperationAction(resourceBundle, "Editor_Delete_", this, ITextOperationTarget.DELETE); //$NON-NLS-1$
		action.setActionDefinitionId(IWorkbenchActionDefinitionIds.DELETE);
		setAction(ITextEditorActionConstants.DELETE, action);
		helpSystem.setHelp(action, IAbstractTextEditorHelpContextIds.DELETE_ACTION);
		// SourceView Action - requesting content assist to
		// show completetion
		// proposals for the current insert position
		action = new ContentAssistAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_PROPOSALS + UNDERSCORE, this);
		helpSystem.setHelp(action, IHelpContextIds.CONTMNU_CONTENTASSIST_HELPID);
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
		setAction(StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_PROPOSALS, action);
		markAsStateDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_PROPOSALS, true);
		// SourceView Action - requesting content assist to
		// show the content
		// information for the current insert position
		action = new TextOperationAction(SSEUIMessages.getResourceBundle(), StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_CONTEXT_INFORMATION + UNDERSCORE, this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION);
		action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
		setAction(StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_CONTEXT_INFORMATION, action);
		markAsStateDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_CONTEXT_INFORMATION, true);
		// StructuredTextViewer Action - requesting format
		// of the whole
		// document
		action = new TextOperationAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT + UNDERSCORE, this, StructuredTextViewer.FORMAT_DOCUMENT);
		helpSystem.setHelp(action, IHelpContextIds.CONTMNU_FORMAT_DOC_HELPID);
		action.setActionDefinitionId(ActionDefinitionIds.FORMAT_DOCUMENT);
		setAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT, action);
		markAsStateDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT, true);
		markAsSelectionDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT, true);
		// StructuredTextViewer Action - requesting format
		// of the active
		// elements
		action = new TextOperationAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS + UNDERSCORE, this, StructuredTextViewer.FORMAT_ACTIVE_ELEMENTS);
		helpSystem.setHelp(action, IHelpContextIds.CONTMNU_FORMAT_ELEMENTS_HELPID);
		action.setActionDefinitionId(ActionDefinitionIds.FORMAT_ACTIVE_ELEMENTS);
		setAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS, action);
		markAsStateDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS, true);
		markAsSelectionDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS, true);

		// StructuredTextEditor Action - add breakpoints (falling back to the
		// current double-click if they can't be added)
		action = new ToggleBreakpointAction(this, getVerticalRuler());
		setAction(ActionDefinitionIds.TOGGLE_BREAKPOINTS, action);
		// StructuredTextEditor Action - manage breakpoints
		action = new ManageBreakpointAction(this, getVerticalRuler());
		setAction(ActionDefinitionIds.MANAGE_BREAKPOINTS, action);
		// StructuredTextEditor Action - edit breakpoints
		action = new EditBreakpointAction(this, getVerticalRuler());
		setAction(ActionDefinitionIds.EDIT_BREAKPOINTS, action);
		// StructuredTextViewer Action - open file on selection
		action = new OpenHyperlinkAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE + UNDERSCORE, this, getSourceViewer());
		action.setActionDefinitionId(ActionDefinitionIds.OPEN_FILE);
		setAction(StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE, action);

		computeAndSetDoubleClickAction();
		
		//add handlers to handler service
		IHandlerService handlerService = getSite().getService(IHandlerService.class);
		if (handlerService != null) {
			
			IHandler gotoHandler = new GotoMatchingBracketHandler();
			handlerService.activateHandler(ActionDefinitionIds.GOTO_MATCHING_BRACKET, gotoHandler);
			
			fOutlineHandler = new QuickOutlineHandler();
	    	handlerService.activateHandler(ActionDefinitionIds.SHOW_OUTLINE, fOutlineHandler);
			
			IHandler toggleCommentHandler = new ToggleLineCommentHandler();
			handlerService.activateHandler(ActionDefinitionIds.TOGGLE_COMMENT, toggleCommentHandler);
			
			IHandler addCommentBlockHandler = new AddBlockCommentHandler();
			handlerService.activateHandler(ActionDefinitionIds.ADD_BLOCK_COMMENT, addCommentBlockHandler);
			
			IHandler removeCommentBlockHandler = new RemoveBlockCommentHandler();
			handlerService.activateHandler(ActionDefinitionIds.REMOVE_BLOCK_COMMENT, removeCommentBlockHandler);
		}

		fShowPropertiesAction = new ShowPropertiesAction(getEditorPart(), getSelectionProvider());

		fFoldingGroup = new FoldingActionGroup(this, getSourceViewer());
		fFoldingGroup.setPreferenceStore(fAppearancePreferenceStore);
	}

	protected ICharacterPairMatcher createCharacterPairMatcher() {
		ICharacterPairMatcher matcher = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; matcher == null && i < ids.length; i++) {
			matcher = (ICharacterPairMatcher) builder.getConfiguration(DocumentRegionEdgeMatcher.ID, ids[i]);
		}
		if (matcher == null) {
			matcher = new DefaultCharacterPairMatcher(new char[]{'(', ')', '{', '}', '[', ']', '<', '>', '"', '"', '\'', '\''});
		}
		return matcher;
	}

	/**
	 * Create a preference store that combines the source editor preferences
	 * with the base editor's preferences.
	 * 
	 * @return IPreferenceStore
	 */
	private IPreferenceStore createCombinedPreferenceStore() {
		final List<IPreferenceStore> stores = new ArrayList<>(3);

		if (fInitializationData != null) {
			fInitializationData.entrySet().forEach((entry) -> {
				if (StructuredTextEditorPreferencePage.PREFERENCE_SCOPE_NAME.equalsIgnoreCase(entry.getKey().toString())) {
					stores.add(new ScopedPreferenceStore(InstanceScope.INSTANCE, entry.getValue().toString().toLowerCase(Locale.US)));
				}
			});
		}

		// sseEditorPrefs
		stores.add(SSEUIPlugin.getDefault().getPreferenceStore());
		// baseEditorPrefs
		stores.add(EditorsUI.getPreferenceStore());
		return new ChainedPreferenceStore(stores.toArray(new IPreferenceStore[stores.size()]));
	}

	private ContentOutlineConfiguration createContentOutlineConfiguration() {
		ContentOutlineConfiguration cfg = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; cfg == null && i < ids.length; i++) {
			cfg = (ContentOutlineConfiguration) builder.getConfiguration(ExtendedConfigurationBuilder.CONTENTOUTLINECONFIGURATION, ids[i]);
		}
		return cfg;
	}

	protected void createModelDependentFields() {
		if (fStructuredSelectionProvider != null) {
			SelectionConverter convertor = fStructuredModel.getAdapter(SelectionConverter.class);
			if (convertor != null)
				fStructuredSelectionProvider.selectionConverter = convertor;
			else
				fStructuredSelectionProvider.selectionConverter = new SelectionConverter();
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Use StructuredTextViewerConfiguration if a viewerconfiguration has not
	 * already been set. Also initialize StructuredTextViewer.
	 * </p>
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createPartControl(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	public void createPartControl(Composite parent) {
		IContextService contextService = getSite().getService(IContextService.class);
		if (contextService != null)
			contextService.activateContext(EDITOR_KEYBINDING_SCOPE_ID);

		if (getSourceViewerConfiguration() == null) {
			ConfigurationAndTarget cat = createSourceViewerConfiguration();
			fViewerConfigurationTargetId = cat.getTargetId();
			StructuredTextViewerConfiguration newViewerConfiguration = cat.getConfiguration();
			setSourceViewerConfiguration(newViewerConfiguration);
		}

		super.createPartControl(parent);

		// instead of calling setInput twice, use initializeSourceViewer() to
		// handle source viewer initialization previously handled by setInput
		initializeSourceViewer();

		// update editor context menu, vertical ruler context menu, infopop
		if (getInternalModel() != null) {
			updateEditorControlsForContentType(getInternalModel().getContentTypeIdentifier());
		}
		else {
			updateEditorControlsForContentType(null);
		}

		// used for Show Tooltip Description
		IInformationControlCreator informationControlCreator = new IInformationControlCreator() {
			@Override
			public IInformationControl createInformationControl(Shell shell) {
				boolean cutDown = false;
				int style = cutDown ? SWT.NONE : (SWT.V_SCROLL | SWT.H_SCROLL);
				return new DefaultInformationControl(shell, SWT.RESIZE | SWT.TOOL, style, new HTMLTextPresenter(cutDown));
			}
		};

		fInformationPresenter = new InformationPresenter(informationControlCreator);
		fInformationPresenter.setSizeConstraints(60, 10, true, true);
		fInformationPresenter.install(getSourceViewer());
		addReconcilingListeners(getSourceViewerConfiguration(), getTextViewer());
		fPartListener = new PartListener(this);
		getSite().getWorkbenchWindow().getPartService().addPartListener(fPartListener);
		installSemanticHighlighting();
		if (fOutlineHandler != null) {
			IInformationPresenter presenter = configureOutlinePresenter(getSourceViewer(), getSourceViewerConfiguration());
			if (presenter != null) {
				presenter.install(getSourceViewer());
				fOutlineHandler.configure(presenter);
			}
		}
		installCharacterPairing();
		ISourceViewer viewer = getSourceViewer();
		if (viewer instanceof ITextViewerExtension) {
			((ITextViewerExtension) viewer).appendVerifyKeyListener(fPairInserter);
			fPairInserter.installCompletionListener();
		}

		if (Platform.getProduct() != null) {
			String viewID = Platform.getProduct().getProperty("idPerspectiveHierarchyView"); //$NON-NLS-1$);
			if (viewID != null) {
				// make sure the specified view ID is known
				if (PlatformUI.getWorkbench().getViewRegistry().find(viewID) != null) {
					fShowInTargetIds = new String[]{viewID, IPageLayout.ID_PROJECT_EXPLORER, IPageLayout.ID_RES_NAV, IPageLayout.ID_OUTLINE};
				}
			}
		}
	}

	protected PropertySheetConfiguration createPropertySheetConfiguration() {
		PropertySheetConfiguration cfg = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; cfg == null && i < ids.length; i++) {
			cfg = (PropertySheetConfiguration) builder.getConfiguration(ExtendedConfigurationBuilder.PROPERTYSHEETCONFIGURATION, ids[i]);
		}
		return cfg;
	}

	/**
	 * Loads the Show In Target IDs from the Extended Configuration extension
	 * point.
	 * 
	 * @return
	 */
	private String[] createShowInTargetIds() {
		List<String> allIds = new ArrayList<>(0);
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] configurationIds = getConfigurationPoints();
		for (int i = 0; i < configurationIds.length; i++) {
			String[] definitions = builder.getDefinitions("showintarget", configurationIds[i]); //$NON-NLS-1$
			for (int j = 0; j < definitions.length; j++) {
				String someIds = definitions[j];
				if (someIds != null && someIds.length() > 0) {
					String[] ids = StringUtils.unpack(someIds);
					for (int k = 0; k < ids.length; k++) {
						// trim, just to keep things clean
						String id = ids[k].trim();
						if (!allIds.contains(id)) {
							allIds.add(id);
						}
					}
				}
			}
		}

		if (!allIds.contains(IPageLayout.ID_RES_NAV)) {
			allIds.add(IPageLayout.ID_RES_NAV);
		}
		if (!allIds.contains(IPageLayout.ID_PROJECT_EXPLORER)) {
			allIds.add(IPageLayout.ID_PROJECT_EXPLORER);
		}
		if (!allIds.contains(IPageLayout.ID_OUTLINE)) {
			allIds.add(IPageLayout.ID_OUTLINE);
		}
		return allIds.toArray(new String[0]);
	}

	/**
	 * @return
	 */
	private ISourceEditingTextTools createSourceEditingTextTools() {
		ISourceEditingTextTools tools = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; tools == null && i < ids.length; i++) {
			tools = (ISourceEditingTextTools) builder.getConfiguration(NullSourceEditingTextTools.ID, ids[i]);
		}
		if (tools == null) {
			tools = NullSourceEditingTextTools.getInstance();
			((NullSourceEditingTextTools) tools).setTextEditor(this);
		}
		Method method = null;
		try {
			method = tools.getClass().getMethod("setTextEditor", new Class[]{StructuredTextEditor.class}); //$NON-NLS-1$
		}
		catch (NoSuchMethodException e) {
		}
		if (method == null) {
			try {
				method = tools.getClass().getMethod("setTextEditor", new Class[]{ITextEditor.class}); //$NON-NLS-1$
			}
			catch (NoSuchMethodException e) {
			}
		}
		if (method == null) {
			try {
				method = tools.getClass().getMethod("setTextEditor", new Class[]{IEditorPart.class}); //$NON-NLS-1$
			}
			catch (NoSuchMethodException e) {
			}
		}
		if (method != null) {
			if (!method.isAccessible()) {
				method.setAccessible(true);
			}
			try {
				method.invoke(tools, new Object[]{this});
			}
			catch (Exception e) {
				Logger.logException("Problem creating ISourceEditingTextTools implementation", e); //$NON-NLS-1$
			}
		}

		return tools;
	}

	/**
	 * Creates the source viewer to be used by this editor
	 */
	@Override
	protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) {
		fAnnotationAccess = createAnnotationAccess();
		fOverviewRuler = createOverviewRuler(getSharedColors());
		StructuredTextViewer sourceViewer = createStructedTextViewer(parent, verticalRuler, styles);
		initSourceViewer(sourceViewer);
		return sourceViewer;
	}

	private ConfigurationAndTarget createSourceViewerConfiguration() {
		ConfigurationAndTarget cat = null;
		StructuredTextViewerConfiguration cfg = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; cfg == null && i < ids.length; i++) {
			cfg = (StructuredTextViewerConfiguration) builder.getConfiguration(ExtendedConfigurationBuilder.SOURCEVIEWERCONFIGURATION, ids[i]);
			cat = new ConfigurationAndTarget(ids[i], cfg);
		}
		if (cfg == null) {
			cfg = new StructuredTextViewerConfiguration();
			String targetid = getClass().getName() + "#default"; //$NON-NLS-1$
			cat = new ConfigurationAndTarget(targetid, cfg);
		}
		return cat;
	}

	protected StructuredTextViewer createStructedTextViewer(Composite parent, IVerticalRuler verticalRuler, int styles) {
		return new StructuredTextViewer(parent, verticalRuler, getOverviewRuler(), isOverviewRulerVisible(), styles);
	}

	@Override
	protected void createUndoRedoActions() {
		// overridden to add icons to actions
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=111877
		super.createUndoRedoActions();
		IAction action = getAction(ITextEditorActionConstants.UNDO);
		if (action != null) {
			action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_UNDO));
		}

		action = getAction(ITextEditorActionConstants.REDO);
		if (action != null) {
			action.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_REDO));
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IWorkbenchPart#dispose()
	 */
	@Override
	public void dispose() {
		Logger.trace("Source Editor", "StructuredTextEditor::dispose entry"); //$NON-NLS-1$ //$NON-NLS-2$
		if (org.eclipse.wst.sse.core.internal.util.Debug.perfTestAdapterClassLoading) {
			System.out.println("Total calls to getAdapter: " + adapterRequests); //$NON-NLS-1$
			System.out.println("Total time in getAdapter: " + adapterTime); //$NON-NLS-1$
			System.out.println("Average time per call: " + (adapterTime / adapterRequests)); //$NON-NLS-1$
		}

		ISourceViewer viewer = getSourceViewer();
		if (viewer instanceof ITextViewerExtension)
			((ITextViewerExtension) viewer).removeVerifyKeyListener(fPairInserter);

		// dispose of information presenter
		if (fInformationPresenter != null) {
			fInformationPresenter.dispose();
			fInformationPresenter = null;
		}

		if (fOutlineHandler != null) {
			fOutlineHandler.dispose();
			fOutlineHandler = null;
		}
		// dispose of selection history
		if (fSelectionHistory != null) {
			fSelectionHistory.dispose();
			fSelectionHistory = null;
		}

		if (fProjectionSupport != null) {
			fProjectionSupport.dispose();
			fProjectionSupport = null;
		}

		if (fFoldingGroup != null) {
			fFoldingGroup.dispose();
			fFoldingGroup = null;
		}

		if (fAppearancePropertyChangeListener != null) {
			if (fAppearancePreferenceStore != null) {
				fAppearancePreferenceStore.removePropertyChangeListener(fAppearancePropertyChangeListener);
				fAppearancePreferenceStore = null;
			}
			fAppearancePropertyChangeListener = null;
		}

		// dispose of menus that were being tracked
		if (fTextContextMenu != null) {
			fTextContextMenu.dispose();
			fTextContextMenu = null;
		}
		if (fRulerContextMenu != null) {
			fRulerContextMenu.dispose();
			fRulerContextMenu = null;
		}
		if (fTextContextMenuManager != null) {
			fTextContextMenuManager.removeMenuListener(getContextMenuListener());
			fTextContextMenuManager.removeAll();
			fTextContextMenuManager.dispose();
		}
		if (fRulerContextMenuManager != null) {
			fRulerContextMenuManager.removeMenuListener(getContextMenuListener());
			fRulerContextMenuManager.removeAll();
			fRulerContextMenuManager.dispose();
		}

		// added this 2/20/2004 based on probe results --
		// seems should be handled by setModel(null), but
		// that's a more radical change.
		// and, technically speaking, should not be needed,
		// but makes a memory leak
		// less severe.
		if (fStructuredModel != null) {
			fStructuredModel.removeModelStateListener(getInternalModelStateListener());
			//fStructuredModel.setStructuredDocument(null);
			/* BUG398460 - Editor is still marked dirty when relaunching editor after closing without saving changes */
//			fStructuredModel = null;
		}

		// BUG155335 - if there was no document provider, there was nothing
		// added
		// to document, so nothing to remove
		if (getDocumentProvider() != null) {
			IDocument doc = getDocumentProvider().getDocument(getEditorInput());
			if (doc != null) {
				if (doc instanceof IExecutionDelegatable) {
					((IExecutionDelegatable) doc).setExecutionDelegate(null);
				}
			}
		}

		// some things in the configuration need to clean
		// up after themselves
		if (fOutlinePage != null) {
			if (fOutlinePage instanceof ConfigurableContentOutlinePage && fOutlinePageListener != null) {
				((ConfigurableContentOutlinePage) fOutlinePage).removeDoubleClickListener(fOutlinePageListener);
			}
			if (fOutlinePageListener != null) {
				fOutlinePage.removeSelectionChangedListener(fOutlinePageListener);
				fOutlinePageListener = null;
			}
			fOutlinePage = null;
		}

		fEditorDisposed = true;
		disposeModelDependentFields();

		if (fPartListener != null) {
			getSite().getWorkbenchWindow().getPartService().removePartListener(fPartListener);
			fPartListener = null;
		}

		uninstallSemanticHighlighting();

		if (fPairInserter != null) {
			fPairInserter.dispose();
			fPairInserter = null;
		}


		setPreferenceStore(null);

		/*
		 * Strictly speaking, but following null outs should not be needed,
		 * but in the event of a memory leak, they make the memory leak less
		 * severe
		 */
		fDropAdapter = null;

		if (fStructuredSelectionProvider != null) {
			fStructuredSelectionProvider.dispose();
			fStructuredSelectionProvider = null;
		}
		
		if (fStatusLineLabelProvider != null) {
			fStatusLineLabelProvider.dispose();
			fStatusLineLabelProvider = null;
		}

		setStatusLineMessage(null);

		super.dispose();

		Logger.trace("Source Editor", "StructuredTextEditor::dispose exit"); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#disposeDocumentProvider()
	 */
	@Override
	protected void disposeDocumentProvider() {
		if (fStructuredModel != null && !fisReleased && !(getDocumentProvider() instanceof IModelProvider)) {
			fStructuredModel.releaseFromEdit();
			fisReleased = true;
		}
		super.disposeDocumentProvider();
	}

	/**
	 * Disposes model specific editor helpers such as statusLineHelper.
	 * Basically any code repeated in update() & dispose() should be placed
	 * here.
	 */
	private void disposeModelDependentFields() {
		if(fStructuredSelectionProvider != null) {
			fStructuredSelectionProvider.selectionConverter = new SelectionConverter();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.ITextEditor#doRevertToSaved()
	 */
	@Override
	public void doRevertToSaved() {
		super.doRevertToSaved();
		if (fOutlinePage != null && fOutlinePage instanceof IUpdate) {
			((IUpdate) fOutlinePage).update();
		}
		// reset undo
		IDocument doc = getDocumentProvider().getDocument(getEditorInput());
		if (doc instanceof IStructuredDocument) {
			((IStructuredDocument) doc).getUndoManager().getCommandStack().flush();
		}

		// update menu text
		updateMenuText();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
	 */
	@Override
	public void doSave(IProgressMonitor progressMonitor) {
		IStructuredModel model = null;
		try {
			model = aboutToSaveModel();
			updateEncodingMemento();
			super.doSave(progressMonitor);
		}
		finally {
			savedModel(model);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#doSetInput(org.eclipse.ui.IEditorInput)
	 */
	@Override
	protected void doSetInput(IEditorInput input) throws CoreException {
		IEditorInput oldInput = getEditorInput();
		if (oldInput != null) {
			IDocument olddoc = getDocumentProvider().getDocument(oldInput);
			if (olddoc != null && olddoc instanceof IExecutionDelegatable) {
				((IExecutionDelegatable) olddoc).setExecutionDelegate(null);
			}
		}

		if (fStructuredModel != null && !(getDocumentProvider() instanceof IModelProvider)) {
			fStructuredModel.releaseFromEdit();
		}

		//attempt to get the model for the given input
		super.doSetInput(input);
		IStructuredModel model = tryToGetModel(input);
		
		/* if could not get the model prompt user to update content type
		 * if preferences allow, then try to get model again
		 */
		if (model == null && getPreferenceStore().getBoolean(AppearancePreferenceNames.SHOW_UNKNOWN_CONTENT_TYPE_MSG)) {
			if (fInitializationData != null && fInitializationData.containsKey(PREFERRED_CONTENT_TYPE_WHEN_UNSUPPORTED)) {
				IContentType contentType = Platform.getContentTypeManager().getContentType(fInitializationData.get(PREFERRED_CONTENT_TYPE_WHEN_UNSUPPORTED).toString());
				if (contentType != null && !StringUtils.contains(contentType.getFileSpecs(IContentTypeSettings.FILE_NAME_SPEC), input.getName(), false)) {
					/*
					 * Display a dialog informing user of unknown content type,
					 * offering to update preferences for them
					 */
					UnknownContentTypeDialog2 dialog = new UnknownContentTypeDialog2(getSite().getShell(), getPreferenceStore(), input.getName(), contentType);
					dialog.open();
				}
			}
			else {
				/*
				 * Display a dialog informing user of unknown content type,
				 * giving them chance to update preferences
				 */
				UnknownContentTypeDialog dialog = new UnknownContentTypeDialog(getSite().getShell(), getPreferenceStore(), AppearancePreferenceNames.SHOW_UNKNOWN_CONTENT_TYPE_MSG);
				dialog.open();
			}

			// try to get model again in hopes user updated preferences
			super.doSetInput(input);
			model = tryToGetModel(input);
			
			// still could not get the model to open this editor, so log
			if(model == null) {
				logUnexpectedDocumentKind(input);
			}
		}

		if (fStructuredModel != null || model != null) {
			setModel(model);
		}

		if (getInternalModel() != null) {
			updateEditorControlsForContentType(getInternalModel().getContentTypeIdentifier());
		}
		else {
			updateEditorControlsForContentType(null);
		}

		// start editor with smart insert mode
		setInsertMode(SMART_INSERT);
	}
	
	/**
	 * <p>Attempts to get the {@link IStructuredModel} for the given {@link IEditorInput}</p>
	 * 
	 * @param input the {@link IEditorInput} to try and get the {@link IStructuredModel} for
	 * 
	 * @return The {@link IStructuredModel} associated with the given {@link IEditorInput} or
	 * <code>null</code> if no associated {@link IStructuredModel} could be found.
	 */
	private IStructuredModel tryToGetModel(IEditorInput input) {
		IStructuredModel model = null;
		
		IDocument newDocument = getDocumentProvider().getDocument(input);
		if (newDocument instanceof IExecutionDelegatable) {
			((IExecutionDelegatable) newDocument).setExecutionDelegate(new EditorExecutionContext(this));
		}

		// if we have a Model provider, get the model from it
		if (getDocumentProvider() instanceof IModelProvider) {
			model = ((IModelProvider) getDocumentProvider()).getModel(getEditorInput());
			if (!model.isShared()) {
				EditorModelUtil.addFactoriesTo(model);
			}
		}
		else if (newDocument instanceof IStructuredDocument) {
			// corresponding releaseFromEdit occurs in dispose()
			model = StructuredModelManager.getModelManager().getModelForEdit((IStructuredDocument) newDocument);
			EditorModelUtil.addFactoriesTo(model);
		} 
		
		return model;
	}

	/**
	 * Sets up this editor's context menu before it is made visible.
	 * <p>
	 * Not API. May be reduced to protected method in the future.
	 * </p>
	 * 
	 * @param menu
	 *            the menu
	 */
	@Override
	public void editorContextMenuAboutToShow(IMenuManager menu) {
		/*
		 * To be consistent with the Java Editor, we want to remove ShiftRight
		 * and ShiftLeft from the context menu.
		 */
		super.editorContextMenuAboutToShow(menu);
		menu.remove(ITextEditorActionConstants.SHIFT_LEFT);
		menu.remove(ITextEditorActionConstants.SHIFT_RIGHT);

		addContextMenuActions(menu);
		addSourceMenuActions(menu);
		addRefactorMenuActions(menu);
		addExtendedContextMenuActions(menu);
	}

	/**
	 * End background mode.
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 */
	void endBackgroundOperation() {
		fBackgroundJobEnded = true;
		// note, we don't immediately end our 'internal busy' state,
		// since we may get many calls in a short period of
		// time. We always wait for the time out.
		resetBusyState();
	}

	/**
	 * Note this method can be called indirectly from background job operation
	 * ... but expected to be gaurded there with ILock, plus, can be called
	 * directly from timer thread, so the timer's run method guards with ILock
	 * too.
	 * 
	 * Set result[0] to 1 if the busy state was ended successfully
	 */
	private void endBusyStateInternal(byte[] result) {
		if (fBackgroundJobEnded) {
			result[0] = 1;
			showBusy(false);

			ISourceViewer viewer = getSourceViewer();
			if (viewer instanceof StructuredTextViewer) {
				((StructuredTextViewer) viewer).endBackgroundUpdate();
			}
			fBusyState = false;
		}
		else {
			// we will only be in this branch for a back ground job that is
			// taking
			// longer than our normal time-out period (meaning we got notified
			// of
			// the timeout "inbetween" calls to 'begin' and
			// 'endBackgroundOperation'.
			// (which, remember, can only happen since there are many calls to
			// begin/end in a short period of time, and we only "reset" on the
			// 'ends').
			// In this event, there's really nothing to do, we're still in
			// "busy state"
			// and should start a new reset cycle once endBackgroundjob is
			// called.
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T getAdapter(Class<T> required) {
		if (org.eclipse.wst.sse.core.internal.util.Debug.perfTestAdapterClassLoading) {
			startPerfTime = System.currentTimeMillis();
		}
		T result = null;
		// text editor
		IStructuredModel internalModel = getInternalModel();
		if (ITextEditor.class.equals(required) || ITextEditorExtension5.class.equals(required) || ITextEditorExtension4.class.equals(required) || ITextEditorExtension3.class.equals(required) || ITextEditorExtension2.class.equals(required) || ITextEditorExtension.class.equals(required)) {
			result = (T) this;
		}
		else if (IWorkbenchSiteProgressService.class.equals(required)) {
			return (T) getEditorPart().getSite().getAdapter(IWorkbenchSiteProgressService.class);
		}
		// content outline page
		else if (IContentOutlinePage.class.equals(required)) {
			if (fOutlinePage == null && !fEditorDisposed) {
				ContentOutlineConfiguration cfg = createContentOutlineConfiguration();
				if (cfg != null) {
					ConfigurableContentOutlinePage outlinePage = new ConfigurableContentOutlinePage();
					outlinePage.setConfiguration(cfg);
					if (internalModel != null) {
						outlinePage.setInputContentTypeIdentifier(internalModel.getContentTypeIdentifier());
						outlinePage.setInput(internalModel);
					}

					if (fOutlinePageListener == null) {
						fOutlinePageListener = new OutlinePageListener();
					}

					outlinePage.addSelectionChangedListener(fOutlinePageListener);
					outlinePage.addDoubleClickListener(fOutlinePageListener);

					fOutlinePage = outlinePage;
				}
			}
			result = (T) fOutlinePage;
		}
		// property sheet page, but only if the input's editable
		else if (IPropertySheetPage.class.equals(required) && isEditable()) {
			if (fPropertySheetPage == null || fPropertySheetPage.getControl() == null || fPropertySheetPage.getControl().isDisposed()) {
				PropertySheetConfiguration cfg = createPropertySheetConfiguration();
				if (cfg != null) {
					ConfigurablePropertySheetPage propertySheetPage = new ConfigurablePropertySheetPage();
					propertySheetPage.setConfiguration(cfg);
					fPropertySheetPage = propertySheetPage;
				}
			}
			result = (T) fPropertySheetPage;
		}
		else if (IDocument.class.equals(required)) {
			result = (T) getDocumentProvider().getDocument(getEditorInput());
		}
		else if (ISourceEditingTextTools.class.equals(required)) {
			result = (T) createSourceEditingTextTools();
		}
		else if (IToggleBreakpointsTarget.class.equals(required)) {
			result = (T) ToggleBreakpointsTarget.getInstance();
		}
		else if (ITextEditorExtension4.class.equals(required)) {
			result = (T) this;
		}
		else if (IShowInTargetList.class.equals(required)) {
			result = (T) new ShowInTargetListAdapter();
		}
		else if (IVerticalRuler.class.equals(required)) {
			return (T) getVerticalRuler();
		}
		else if (SelectionHistory.class.equals(required)) {
			if (fSelectionHistory == null) {
				fSelectionHistory = new SelectionHistory(this);
			}
			result = (T) fSelectionHistory;
		}
		else if (IResource.class.equals(required)) {
			IEditorInput input = getEditorInput();
			if (input != null) {
				result = input.getAdapter(required);
			}
		}
		else {
			if (result == null && internalModel != null) {
				result = internalModel.getAdapter(required);
			}
			// others
			if (result == null)
				result = super.getAdapter(required);
		}
		if (result == null) {
//			Logger.log(Logger.INFO_DEBUG, "StructuredTextEditor.getAdapter returning null for " + required); //$NON-NLS-1$
		}
		if (org.eclipse.wst.sse.core.internal.util.Debug.perfTestAdapterClassLoading) {
			long stop = System.currentTimeMillis();
			adapterRequests++;
			adapterTime += (stop - startPerfTime);
		}
		if (org.eclipse.wst.sse.core.internal.util.Debug.perfTestAdapterClassLoading) {
			System.out.println("Total calls to getAdapter: " + adapterRequests); //$NON-NLS-1$
			System.out.println("Total time in getAdapter: " + adapterTime); //$NON-NLS-1$
			System.out.println("Average time per call: " + (adapterTime / adapterRequests)); //$NON-NLS-1$
		}
		return result;
	}

	private String[] getConfigurationPoints() {
		String contentTypeIdentifierID = null;
		if (getInternalModel() != null) {
			contentTypeIdentifierID = getInternalModel().getContentTypeIdentifier();
		}
		return ConfigurationPointCalculator.getConfigurationPoints(this, contentTypeIdentifierID, ConfigurationPointCalculator.SOURCE, StructuredTextEditor.class);
	}

	/**
	 * added checks to overcome bug such that if we are shutting down in an
	 * error condition, then viewer will have already been disposed.
	 */
	@Override
	protected String getCursorPosition() {
		String result = null;
		// this may be too expensive in terms of
		// performance, to do this check
		// every time, just to gaurd against error
		// condition.
		// perhaps there's a better way?
		if (getSourceViewer() != null && getSourceViewer().getTextWidget() != null && !getSourceViewer().getTextWidget().isDisposed()) {
			result = super.getCursorPosition();
		}
		else {
			result = "0:0"; //$NON-NLS-1$
		}
		return result;
	}


	Display getDisplay() {
		return PlatformUI.getWorkbench().getDisplay();
	}

	/**
	 * Returns this editor part.
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 * 
	 * @return this editor part
	 */
	public IEditorPart getEditorPart() {
		if (fEditorPart == null)
			return this;
		return fEditorPart;
	}

	IStructuredModel getInternalModel() {
		return fStructuredModel;
	}

	private InternalModelStateListener getInternalModelStateListener() {
		if (fInternalModelStateListener == null) {
			fInternalModelStateListener = new InternalModelStateListener();
		}
		return fInternalModelStateListener;
	}

	/**
	 * Returns this editor's StructuredModel.
	 * <p>
	 * Not API. Will be removed in the future.
	 * </p>
	 * 
	 * @return returns this editor's IStructuredModel
	 * @deprecated - This method allowed for uncontrolled access to the model
	 *             instance and will be removed in the future. It is
	 *             recommended that the current document provider be asked for
	 *             the current document and the IModelManager then asked for
	 *             the corresponding model with
	 *             getExistingModelFor*(IDocument). Supported document
	 *             providers ensure that the document maps to a shared
	 *             structured model.
	 */
	@Deprecated
	public IStructuredModel getModel() {
		IDocumentProvider documentProvider = getDocumentProvider();
		
		if (documentProvider == null) {
			// this indicated an error in startup sequence
			Logger.trace(getClass().getName(), "Program Info Only: document provider was null when model requested"); //$NON-NLS-1$ 
		}
		
		// Remember if we entered this method without a model existing
		boolean initialModelNull = (fStructuredModel == null);
		
		if (fStructuredModel == null && documentProvider != null) {
			// lazily set the model instance, although this is an ABNORMAL
			// CODE PATH
			if (documentProvider instanceof IModelProvider) {
				fStructuredModel = ((IModelProvider) documentProvider).getModel(getEditorInput());
				fisReleased = false;
			}
			else {
				IDocument doc = documentProvider.getDocument(getEditorInput());
				if (doc instanceof IStructuredDocument) {
					/*
					 * Called in this manner because getExistingModel can skip
					 * some calculations always performed in getModelForEdit
					 */
					IStructuredModel model = StructuredModelManager.getModelManager().getExistingModelForEdit(doc);
					if (model == null) {
						model = StructuredModelManager.getModelManager().getModelForEdit((IStructuredDocument) doc);
					}
					fStructuredModel = model;
					fisReleased = false;
				}
			}

			EditorModelUtil.addFactoriesTo(fStructuredModel);

			if (initialModelNull && fStructuredModel != null) {
				/*
				 * DMW: 9/1/2002 -- why is update called here? No change has
				 * been indicated? I'd like to remove, but will leave for now
				 * to avoid breaking this hack. Should measure/breakpoint to
				 * see how large the problem is. May cause performance
				 * problems.
				 * 
				 * DMW: 9/8/2002 -- not sure why this was here initially, but
				 * the intent/hack must have been to call update if this was
				 * the first time fStructuredModel was set. So, I added the
				 * logic to check for that "first time" case. It would appear
				 * we don't really need. may remove in future when can test
				 * more.
				 */
				update();
			}
		}
		return fStructuredModel;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.IWorkbenchPartOrientation#getOrientation()
	 */
	@Override
	public int getOrientation() {
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=88714
		return SWT.LEFT_TO_RIGHT;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.ITextEditor#getSelectionProvider()
	 */
	@Override
	public ISelectionProvider getSelectionProvider() {
		if (fStructuredSelectionProvider == null) {
			ISelectionProvider parentProvider = super.getSelectionProvider();
			if (parentProvider != null) {
				fStructuredSelectionProvider = new StructuredSelectionProvider(parentProvider, this);
				fStructuredSelectionProvider.addPostSelectionChangedListener(new ISelectionChangedListener() {
					@Override
					public void selectionChanged(SelectionChangedEvent event) {
						updateStatusLine(event.getSelection());
					}
				});
				if (fStructuredModel != null) {
					SelectionConverter converter = fStructuredModel.getAdapter(SelectionConverter.class);
					if (converter != null) {
						fStructuredSelectionProvider.selectionConverter = converter;
					}
				}
			}
		}
		if (fStructuredSelectionProvider == null) {
			return super.getSelectionProvider();
		}
		return fStructuredSelectionProvider;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#getStatusLineManager()
	 * 
	 * Overridden to use the top-level editor part's status line
	 */
	@Override
	protected IStatusLineManager getStatusLineManager() {
		return getEditorPart().getEditorSite().getActionBars().getStatusLineManager();
	}

	/**
	 * Returns the editor's source viewer. This method was created to expose
	 * the protected final getSourceViewer() method.
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 * 
	 * @return the editor's source viewer
	 */
	public StructuredTextViewer getTextViewer() {
		return (StructuredTextViewer) getSourceViewer();
	}

	/**
	 * Jumps to the matching bracket.
	 */
	void gotoMatchingBracket() {
		ICharacterPairMatcher matcher = createCharacterPairMatcher();
		if (matcher == null)
			return;

		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(SSEUIMessages.GotoMatchingBracket_error_invalidSelection);
			sourceViewer.getTextWidget().getDisplay().beep();
			return;
		}

		int sourceCaretOffset = selection.getOffset() + selection.getLength();
		IRegion region = matcher.match(document, sourceCaretOffset);
		if (region == null) {
			setStatusLineErrorMessage(SSEUIMessages.GotoMatchingBracket_error_noMatchingBracket);
			sourceViewer.getTextWidget().getDisplay().beep();
			return;
		}

		int offset = region.getOffset();
		int length = region.getLength();

		if (length < 1)
			return;

		int anchor = matcher.getAnchor();

		// go to after the match if matching to the right
		int targetOffset = (ICharacterPairMatcher.RIGHT == anchor) ? offset : 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(SSEUIMessages.GotoMatchingBracket_error_bracketOutsideSelectedElement);
			sourceViewer.getTextWidget().getDisplay().beep();
			return;
		}

		if (selection.getLength() < 0)
			targetOffset -= selection.getLength();

		if (sourceViewer != null) {
			sourceViewer.setSelectedRange(targetOffset, selection.getLength());
			sourceViewer.revealRange(targetOffset, selection.getLength());
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#handleCursorPositionChanged()
	 */
	@Override
	protected void handleCursorPositionChanged() {
		super.handleCursorPositionChanged();
		updateStatusField(StructuredTextEditorActionConstants.STATUS_CATEGORY_OFFSET);
	}
	
	@Override
	protected void handleElementContentReplaced() {
		super.handleElementContentReplaced();

		// queue a full revalidation of content
		IDocument document = getDocumentProvider().getDocument(getEditorInput());
		SourceViewerConfiguration sourceViewerConfiguration = getSourceViewerConfiguration();
		if (document != null && sourceViewerConfiguration != null && sourceViewerConfiguration.getReconciler(getSourceViewer()) instanceof DirtyRegionProcessor) {
			((DirtyRegionProcessor) sourceViewerConfiguration.getReconciler(getSourceViewer())).processDirtyRegion(new DirtyRegion(0, document.getLength(), DirtyRegion.INSERT, document.get()));
		}

		/*
		 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=129906 - update
		 * selection to listeners
		 */
		ISelectionProvider selectionProvider = getSelectionProvider();
		ISelection originalSelection = selectionProvider.getSelection();
		if (selectionProvider instanceof StructuredSelectionProvider && originalSelection instanceof ITextSelection) {
			ITextSelection textSelection = (ITextSelection) originalSelection;
			// make sure the old selection is actually still valid
			if (!textSelection.isEmpty() && (document == null || textSelection.getOffset() + textSelection.getLength() <= document.getLength())) {
				SelectionChangedEvent syntheticEvent = new SelectionChangedEvent(selectionProvider, new TextSelection(textSelection.getOffset(), textSelection.getLength()));
				((StructuredSelectionProvider) selectionProvider).handleSelectionChanged(syntheticEvent);
				((StructuredSelectionProvider) selectionProvider).handlePostSelectionChanged(syntheticEvent);
			}
			else {
				SelectionChangedEvent syntheticEvent = new SelectionChangedEvent(selectionProvider, new TextSelection(0, 0));
				((StructuredSelectionProvider) selectionProvider).handleSelectionChanged(syntheticEvent);
				((StructuredSelectionProvider) selectionProvider).handlePostSelectionChanged(syntheticEvent);
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#handlePreferenceStoreChanged(org.eclipse.jface.util.PropertyChangeEvent)
	 */
	@Override
	protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
		String property = event.getProperty();

		if (EditorPreferenceNames.EDITOR_TEXT_HOVER_MODIFIERS.equals(property)) {
			updateHoverBehavior();
		}
		
		//enable or disable as you type validation
		else if(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS.equals(property)) {
			IReconciler reconciler = this.getSourceViewerConfiguration().getReconciler(this.getSourceViewer());
			if (reconciler instanceof DocumentRegionProcessor) {
				((DocumentRegionProcessor) reconciler).setValidatorStrategyEnabled(isValidationEnabled());
			}
		}

		else if (AppearancePreferenceNames.FOLDING_ENABLED.equals(property)) {
			if (getSourceViewer() instanceof ProjectionViewer) {
				// install projection support if it has not even been
				// installed yet
				if (isFoldingEnabled() && (fProjectionSupport == null)) {
					installProjectionSupport();
				}
				ProjectionViewer pv = (ProjectionViewer) getSourceViewer();
				if (pv.isProjectionMode() != isFoldingEnabled()) {
					if (pv.canDoOperation(ProjectionViewer.TOGGLE)) {
						pv.doOperation(ProjectionViewer.TOGGLE);
					}
				}
			}
		}

		// update content assist preferences
		else if (AppearancePreferenceNames.CODEASSIST_PROPOSALS_BACKGROUND.equals(property)) {
			ISourceViewer sourceViewer = getSourceViewer();
			if (sourceViewer != null) {
				SourceViewerConfiguration configuration = getSourceViewerConfiguration();
				if (configuration != null) {
					IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer);
					if (contentAssistant instanceof ContentAssistant) {
						ContentAssistant assistant = (ContentAssistant) contentAssistant;
						RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), AppearancePreferenceNames.CODEASSIST_PROPOSALS_BACKGROUND);
						Color color = EditorUtility.getColor(rgb);
						assistant.setProposalSelectorBackground(color);
					}
				}
			}
		}

		// update content assist preferences
		else if (AppearancePreferenceNames.CODEASSIST_PROPOSALS_FOREGROUND.equals(property)) {
			ISourceViewer sourceViewer = getSourceViewer();
			if (sourceViewer != null) {
				SourceViewerConfiguration configuration = getSourceViewerConfiguration();
				if (configuration != null) {
					IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer);
					if (contentAssistant instanceof ContentAssistant) {
						ContentAssistant assistant = (ContentAssistant) contentAssistant;
						RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), AppearancePreferenceNames.CODEASSIST_PROPOSALS_FOREGROUND);
						Color color = EditorUtility.getColor(rgb);
						assistant.setProposalSelectorForeground(color);
					}
				}
			}
		}

		// update content assist preferences
		else if (AppearancePreferenceNames.CODEASSIST_PARAMETERS_BACKGROUND.equals(property)) {
			ISourceViewer sourceViewer = getSourceViewer();
			if (sourceViewer != null) {
				SourceViewerConfiguration configuration = getSourceViewerConfiguration();
				if (configuration != null) {
					IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer);
					if (contentAssistant instanceof ContentAssistant) {
						ContentAssistant assistant = (ContentAssistant) contentAssistant;
						RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), AppearancePreferenceNames.CODEASSIST_PARAMETERS_BACKGROUND);
						Color color = EditorUtility.getColor(rgb);
						assistant.setContextInformationPopupBackground(color);
						assistant.setContextSelectorBackground(color);
					}
				}
			}
		}

		// update content assist preferences
		else if (AppearancePreferenceNames.CODEASSIST_PARAMETERS_FOREGROUND.equals(property)) {
			ISourceViewer sourceViewer = getSourceViewer();
			if (sourceViewer != null) {
				SourceViewerConfiguration configuration = getSourceViewerConfiguration();
				if (configuration != null) {
					IContentAssistant contentAssistant = configuration.getContentAssistant(sourceViewer);
					if (contentAssistant instanceof ContentAssistant) {
						ContentAssistant assistant = (ContentAssistant) contentAssistant;
						RGB rgb = PreferenceConverter.getColor(getPreferenceStore(), AppearancePreferenceNames.CODEASSIST_PARAMETERS_FOREGROUND);
						Color color = EditorUtility.getColor(rgb);
						assistant.setContextInformationPopupForeground(color);
						assistant.setContextSelectorForeground(color);
					}
				}
			}
		}

		super.handlePreferenceStoreChanged(event);
	}

	private boolean inBusyState() {
		return fBusyState;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite,
	 *      org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
		// if we've gotten an error elsewhere, before
		// we've actually opened, then don't open.
		if (shouldClose) {
			setSite(site);
			close(false);
		}
		else {
			super.init(site, input);
		}
	}

	/**
	 * Set the document provider for this editor.
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 * 
	 * @param documentProvider
	 *            documentProvider to initialize
	 */
	public void initializeDocumentProvider(IDocumentProvider documentProvider) {
		if (documentProvider != null) {
			setDocumentProvider(documentProvider);
		}
	}

	/**
	 * @deprecated since 1.6.300 - no longer used in favor of platform text
	 *             drag and drop, left for binary compatibility
	 * @param textViewer
	 */
	protected void initializeDrop(ITextViewer textViewer) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeEditor()
	 */
	@Override
	protected void initializeEditor() {
		super.initializeEditor();

		setPreferenceStore(createCombinedPreferenceStore());

		setRangeIndicator(new DefaultRangeIndicator());
		setEditorContextMenuId(EDITOR_CONTEXT_MENU_ID);
		initializeDocumentProvider(null);
		// set the infopop for source viewer
		String helpId = getHelpContextId();
		// no infopop set or using default text editor help, use default
		if (helpId == null || ITextEditorHelpContextIds.TEXT_EDITOR.equals(helpId))
			helpId = IHelpContextIds.XML_SOURCE_VIEW_HELPID;
		setHelpContextId(helpId);
		// defect 203158 - disable ruler context menu for
		// beta
		// setRulerContextMenuId(RULER_CONTEXT_MENU_ID);
		configureInsertMode(SMART_INSERT, true);

		// enable the base source editor activity when editor opens
		try {
			// FIXME: - commented out to avoid minor dependancy during
			// transition to org.eclipse
			// WTPActivityBridge.getInstance().enableActivity(CORE_SSE_ACTIVITY_ID,
			// true);
		}
		catch (Exception t) {
			// if something goes wrong with enabling activity, just log the
			// error but dont
			// have it break the editor
			Logger.log(Logger.WARNING_DEBUG, t.getMessage(), t);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.editors.text.TextEditor#initializeKeyBindingScopes()
	 */
	@Override
	protected void initializeKeyBindingScopes() {
		setKeyBindingScopes(new String[]{EDITOR_KEYBINDING_SCOPE_ID});
	}

	/**
	 * Initializes the editor's source viewer and other items that were source
	 * viewer-dependent.
	 */
	private void initializeSourceViewer() {
		IAction openHyperlinkAction = getAction(StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE);
		if (openHyperlinkAction instanceof OpenHyperlinkAction) {
			((OpenHyperlinkAction) openHyperlinkAction).setHyperlinkDetectors(getSourceViewerConfiguration().getHyperlinkDetectors(getSourceViewer()));
		}

		// do not even install projection support until folding is actually
		// enabled
		if (isFoldingEnabled()) {
			installProjectionSupport();
		}
	}

	protected void initSourceViewer(StructuredTextViewer sourceViewer) {
		// ensure decoration support is configured
		getSourceViewerDecorationSupport(sourceViewer);
	}

	@Override
	protected void installTextDragAndDrop(final ISourceViewer textViewer) {
		/**
		 * For compatibility, let subclasses install their own support and
		 * supersede the default
		 */
		initializeDrop(textViewer);
		if (textViewer.getTextWidget().getData(DND.DROP_TARGET_KEY) == null) {
			super.installTextDragAndDrop(textViewer);
			IDragAndDropService dndService = getSite().getService(IDragAndDropService.class);
			Object dropTarget = textViewer.getTextWidget().getData(DND.DROP_TARGET_KEY);
			int operations = DND.DROP_COPY | DND.DROP_MOVE;
			if (dropTarget instanceof DropTarget) {
				DropTargetListener[] dropListeners = ((DropTarget) dropTarget).getDropListeners();
				fDropAdapter = new DefaultTextTransferDropTargetAdapterProxy(dropListeners[dropListeners.length - 1]);
			}
			else {
				fDropAdapter = new ReadOnlyAwareDropTargetAdapter(true);
			}
			fDropAdapter.setTargetEditor(this);
			fDropAdapter.setTargetIDs(getConfigurationPoints());
			fDropAdapter.setTextViewer(textViewer);
			Transfer[] transfers = fDropAdapter.getTransfers();
			if (dropTarget instanceof DropTarget) {
				transfers = Arrays.copyOf(transfers, transfers.length + 1);
				transfers[transfers.length - 1] = TextTransfer.getInstance();
			}
			dndService.addMergedDropTarget(textViewer.getTextWidget(), operations, transfers, fDropAdapter);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.editors.text.TextEditor#installEncodingSupport()
	 */
	@Override
	protected void installEncodingSupport() {
		fEncodingSupport = new EncodingSupport(getConfigurationPoints());
		fEncodingSupport.initialize(this);
	}

	/**
	 * Install everything necessary to get document folding working and enable
	 * document folding
	 */
	private void installProjectionSupport() {
		ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer();

		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() {
			@Override
			public IInformationControl createInformationControl(Shell parent) {
				return new DefaultInformationControl(parent, EditorsUI.getTooltipAffordanceString());
			}
		});
		fProjectionSupport.install();

		if (isFoldingEnabled())
			projectionViewer.doOperation(ProjectionViewer.TOGGLE);
	}

	/**
	 * Return whether document folding should be enabled according to the
	 * preference store settings.
	 * 
	 * @return <code>true</code> if document folding should be enabled
	 */
	private boolean isFoldingEnabled() {
		IPreferenceStore store = fAppearancePreferenceStore;
		return store.getBoolean(AppearancePreferenceNames.FOLDING_ENABLED);
	}

	/**
	 * Determine if the user preference for as you type validation is enabled or not
	 */
	private boolean isValidationEnabled() {
		return getPreferenceStore().getBoolean(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS);
	}

	/**
	 * <p>Logs a warning about how this {@link StructuredTextEditor} just opened an {@link IEditorInput}
	 * it was not designed to open.</p>
	 * 
	 * @param input the {@link IEditorInput} this {@link StructuredTextEditor} was not designed to open
	 * to log the message about.
	 */
	private void logUnexpectedDocumentKind(IEditorInput input) {
		Logger.log(Logger.WARNING, "StructuredTextEditor being used without StructuredDocument"); //$NON-NLS-1$
		String name = null;
		if (input != null) {
			name = input.getName();
		}
		else {
			name = "input was null"; //$NON-NLS-1$
		}
		Logger.log(Logger.WARNING, "         Input Name: " + name); //$NON-NLS-1$
		String implClass = null;
		IDocument document = getDocumentProvider().getDocument(input);
		if (document != null) {
			implClass = document.getClass().getName();
		}
		else {
			implClass = "document was null"; //$NON-NLS-1$
		}
		Logger.log(Logger.WARNING, "        Unexpected IDocumentProvider implementation: " + getDocumentProvider().getClass().getName()); //$NON-NLS-1$
		Logger.log(Logger.WARNING, "        Unexpected IDocument implementation: " + implClass); //$NON-NLS-1$
	}

	/*
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#performRevert()
	 */
	@Override
	protected void performRevert() {
		ProjectionViewer projectionViewer = (ProjectionViewer) getSourceViewer();
		projectionViewer.setRedraw(false);
		try {

			boolean projectionMode = projectionViewer.isProjectionMode();
			if (projectionMode) {
				projectionViewer.disableProjection();
			}

			super.performRevert();

			if (projectionMode) {
				projectionViewer.enableProjection();
			}

		}
		finally {
			projectionViewer.setRedraw(true);
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Not API. May be reduced to protected method in the future.
	 * </p>
	 */
	@Override
	public void rememberSelection() {
		/*
		 * This method was made public for use by editors that use
		 * StructuredTextEditor (like some clients)
		 */
		super.rememberSelection();
	}


	/**
	 * both starts and resets the busy state timer
	 */
	private void resetBusyState() {
		// reset the "busy" timeout
		if (fBusyTimer != null) {
			fBusyTimer.cancel();
		}
		startBusyTimer();
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Not API. May be reduced to protected method in the future.
	 * </p>
	 */
	@Override
	public void restoreSelection() {
		/*
		 * This method was made public for use by editors that use
		 * StructuredTextEditor (like some clients)
		 */
		// catch odd case where source viewer has no text
		// widget (defect
		// 227670)
		if ((getSourceViewer() != null) && (getSourceViewer().getTextWidget() != null))
			super.restoreSelection();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#rulerContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager)
	 */
	@Override
	protected void rulerContextMenuAboutToShow(IMenuManager menu) {
		super.rulerContextMenuAboutToShow(menu);

		IMenuManager foldingMenu = new MenuManager(SSEUIMessages.Folding, "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);

		IStructuredModel internalModel = getInternalModel();
		if (internalModel != null) {
			boolean debuggingAvailable = BreakpointProviderBuilder.getInstance().isAvailable(internalModel.getContentTypeIdentifier(), BreakpointRulerAction.getFileExtension(getEditorInput()));
			if (debuggingAvailable) {
				// append actions to "debug" group (created in
				// AbstractDecoratedTextEditor.rulerContextMenuAboutToShow(IMenuManager)
				menu.appendToGroup("debug", getAction(ActionDefinitionIds.TOGGLE_BREAKPOINTS)); //$NON-NLS-1$
				menu.appendToGroup("debug", getAction(ActionDefinitionIds.MANAGE_BREAKPOINTS)); //$NON-NLS-1$
				menu.appendToGroup("debug", getAction(ActionDefinitionIds.EDIT_BREAKPOINTS)); //$NON-NLS-1$
			}
			addExtendedRulerContextMenuActions(menu);
		}
	}

	/**
	 * {@inheritDoc}
	 * <p>
	 * Overridden to expose part activation handling for multi-page editors.
	 * </p>
	 * <p>
	 * Not API. May be reduced to protected method in the future.
	 * </p>
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#safelySanityCheckState(org.eclipse.ui.IEditorInput)
	 */
	@Override
	public void safelySanityCheckState(IEditorInput input) {
		super.safelySanityCheckState(input);
	}
	
	@Override
	protected void sanityCheckState(IEditorInput input) {
		try {
			++validateEditCount;
			super.sanityCheckState(input);
		}
		finally {
			--validateEditCount;
		}
	}

	private void savedModel(IStructuredModel model) {
		if (model != null) {
			model.changedModel();
		}
	}

	/**
	 * Ensure that the correct IDocumentProvider is used. For direct models, a
	 * special provider is used. For StorageEditorInputs, use a custom
	 * provider that creates a usable ResourceAnnotationModel. For everything
	 * else, use the base support.
	 * 
	 * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#setDocumentProvider(org.eclipse.ui.IEditorInput)
	 */
	@Override
	protected void setDocumentProvider(IEditorInput input) {
		if (input instanceof IStructuredModel) {
			// largely untested
			setDocumentProvider(StructuredModelDocumentProvider.getInstance());
		}
		else if (input instanceof IStorageEditorInput && !(input instanceof IFileEditorInput)) {
			setDocumentProvider(StorageModelProvider.getInstance());
		}
		else {
			super.setDocumentProvider(input);
		}
	}

	/**
	 * Set the WorkbenchPage-level editor part associated with this editor.
	 * Encouraged if using the
	 * <code>org.eclipse.wst.sse.ui.editorConfiguration</code> extension point
	 * with the <code>StructuredTextEditor</code> as a source page in a
	 * MultiPageEditorPart.
	 * 
	 * @param editorPart
	 *            editor part associated with (containing) this editor
	 */
	public void setEditorPart(IEditorPart editorPart) {
		fEditorPart = editorPart;
	}

	/**
	 * Sets the model field within this editor.
	 * 
	 * @deprecated - can eventually be eliminated
	 */
	@Deprecated
	private void setModel(IStructuredModel newModel) {
		Assert.isNotNull(getDocumentProvider(), "document provider can not be null when setting model"); //$NON-NLS-1$
		if (fStructuredModel != null) {
			fStructuredModel.removeModelStateListener(getInternalModelStateListener());
		}
		fStructuredModel = newModel;
		if (fStructuredModel != null) {
			fStructuredModel.addModelStateListener(getInternalModelStateListener());
		}
		// update() should be called whenever the model is
		// set or changed
		update();
	}

	@Override
	protected void setPreferenceStore(IPreferenceStore store) {
		super.setPreferenceStore(store);

		if (fAppearancePropertyChangeListener != null) {
			if (fAppearancePreferenceStore != null) {
				fAppearancePreferenceStore.removePropertyChangeListener(fAppearancePropertyChangeListener);
				fAppearancePreferenceStore= null;
			}
			fAppearancePropertyChangeListener= null;
		}

		if (store != null) {
			fAppearancePreferenceStore = SSEUIPlugin.getDefault().getPreferenceStore();

			if (fInitializationData != null) {
				fInitializationData.entrySet().forEach((entry) -> {
					if (StructuredTextEditorPreferencePage.PREFERENCE_SCOPE_NAME.equalsIgnoreCase(entry.getKey().toString())) {
						ScopedPreferenceStore scopedPreferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, entry.getValue().toString().toLowerCase(Locale.US));
						fAppearancePreferenceStore = scopedPreferenceStore;
						fAppearancePreferenceStore.addPropertyChangeListener(fAppearancePropertyChangeListener = new PropertyChangeListener());
					}
				});
			}

		}
	}

	/**
	 * Sets the editor's source viewer configuration which it uses to
	 * configure it's internal source viewer. This method was overwritten so
	 * that viewer configuration could be set after editor part was created.
	 */
	@Override
	protected void setSourceViewerConfiguration(SourceViewerConfiguration config) {
		SourceViewerConfiguration oldSourceViewerConfiguration = getSourceViewerConfiguration();
		super.setSourceViewerConfiguration(config);
		StructuredTextViewer stv = getTextViewer();
		if (stv != null) {
			/*
			 * There should be no need to unconfigure before configure because
			 * configure will also unconfigure before configuring
			 */
			removeReconcilingListeners(oldSourceViewerConfiguration, stv);
			stv.unconfigure();
			setStatusLineMessage(null);
			stv.configure(config);
			addReconcilingListeners(config, stv);
		}
	}
	
	private void removeReconcilingListeners(SourceViewerConfiguration config, StructuredTextViewer stv) {
		IReconciler reconciler = config.getReconciler(stv);
		if (reconciler instanceof DocumentRegionProcessor) {
			for (int i = 0; i < fReconcilingListeners.length; i++) {
				((DocumentRegionProcessor) reconciler).removeReconcilingListener(fReconcilingListeners[i]);
			}
		}
	}

	private void addReconcilingListeners(SourceViewerConfiguration config, StructuredTextViewer stv) {
		try {
			List<ISourceReconcilingListener> reconcilingListeners = new ArrayList<>(fReconcilingListeners.length);
			String[] ids = getConfigurationPoints();
			for (int i = 0; i < ids.length; i++) {
				reconcilingListeners.addAll(ExtendedConfigurationBuilder.getInstance().getConfigurations("sourceReconcilingListener", ids[i])); //$NON-NLS-1$
			}
			fReconcilingListeners = reconcilingListeners.toArray(new ISourceReconcilingListener[reconcilingListeners.size()]);
		}
		catch (ClassCastException e) {
			Logger.log(Logger.ERROR, "Configuration has a reconciling listener that does not implement ISourceReconcilingListener."); //$NON-NLS-1$
		}

		IReconciler reconciler = config.getReconciler(stv);
		if (reconciler instanceof DocumentRegionProcessor) {
			for (int i = 0; i < fReconcilingListeners.length; i++)
				((DocumentRegionProcessor) reconciler).addReconcilingListener(fReconcilingListeners[i]);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean)
	 */
	@Override
	public void showBusy(boolean busy) {
		// no-op
		super.showBusy(busy);
	}

	private void startBusyTimer() {
		// TODO: we need a resettable timer, so not so
		// many are created
		fBusyTimer = new Timer(true);
		fBusyTimer.schedule(new TimeOutExpired(), BUSY_STATE_DELAY);
	}

	@Override
	protected void uninstallTextDragAndDrop(ISourceViewer viewer) {
		super.uninstallTextDragAndDrop(viewer);
		fDropAdapter = null;
	}

	/**
	 * Update should be called whenever the model is set or changed (as in
	 * swapped)
	 * <p>
	 * Not API. May be removed in the future.
	 * </p>
	 */
	public void update() {
		if (fOutlinePage != null && fOutlinePage instanceof ConfigurableContentOutlinePage) {
			ContentOutlineConfiguration cfg = createContentOutlineConfiguration();
			((ConfigurableContentOutlinePage) fOutlinePage).setConfiguration(cfg);
			IStructuredModel internalModel = getInternalModel();
			((ConfigurableContentOutlinePage) fOutlinePage).setInputContentTypeIdentifier(
					internalModel == null ? null : internalModel.getContentTypeIdentifier());
			((ConfigurableContentOutlinePage) fOutlinePage).setInput(internalModel);
		}
		if (fPropertySheetPage != null && fPropertySheetPage instanceof ConfigurablePropertySheetPage) {
			PropertySheetConfiguration cfg = createPropertySheetConfiguration();
			((ConfigurablePropertySheetPage) fPropertySheetPage).setConfiguration(cfg);
		}
		disposeModelDependentFields();

		fShowInTargetIds = createShowInTargetIds();

		if (getSourceViewerConfiguration() instanceof StructuredTextViewerConfiguration && fStatusLineLabelProvider != null) {
			fStatusLineLabelProvider.dispose();
		}

		String configurationId = fViewerConfigurationTargetId;
		updateSourceViewerConfiguration();

		/* Only reinstall if the configuration id has changed */
		if (configurationId != null && !configurationId.equals(fViewerConfigurationTargetId)) {
			uninstallSemanticHighlighting();
			installSemanticHighlighting();
		}

		if (getSourceViewerConfiguration() instanceof StructuredTextViewerConfiguration) {
			fStatusLineLabelProvider = ((StructuredTextViewerConfiguration) getSourceViewerConfiguration()).getStatusLineLabelProvider(getSourceViewer());
			updateStatusLine(null);
		}

		if (fEncodingSupport != null && fEncodingSupport instanceof EncodingSupport) {
			((EncodingSupport) fEncodingSupport).reinitialize(getConfigurationPoints());
		}

		createModelDependentFields();
	}

	/**
	 * Updates all content dependent actions.
	 */
	@Override
	protected void updateContentDependentActions() {
		super.updateContentDependentActions();
		// super.updateContentDependentActions only updates
		// the enable/disable
		// state of all
		// the content dependent actions.
		// StructuredTextEditor's undo and redo actions
		// have a detail label and
		// description.
		// They needed to be updated.
		if (!fEditorDisposed)
			updateMenuText();
	}


	/**
	 * Updates the editor context menu by creating a new context menu with the
	 * given menu id
	 * 
	 * @param contextMenuId
	 *            Cannot be null
	 */
	private void updateEditorContextMenuId(String contextMenuId) {
		// update editor context menu id if updating to a new id or if context
		// menu is not already set up
		if (!contextMenuId.equals(getEditorContextMenuId()) || (fTextContextMenu == null)) {
			setEditorContextMenuId(contextMenuId);

			if (getSourceViewer() != null) {
				StyledText styledText = getSourceViewer().getTextWidget();
				if (styledText != null) {
					// dispose of previous context menu
					if (fTextContextMenu != null) {
						fTextContextMenu.dispose();
					}
					if (fTextContextMenuManager != null) {
						fTextContextMenuManager.removeMenuListener(getContextMenuListener());
						fTextContextMenuManager.removeAll();
						fTextContextMenuManager.dispose();
					}

					fTextContextMenuManager = new MenuManager(getEditorContextMenuId(), getEditorContextMenuId());
					fTextContextMenuManager.setRemoveAllWhenShown(true);
					fTextContextMenuManager.addMenuListener(getContextMenuListener());

					fTextContextMenu = fTextContextMenuManager.createContextMenu(styledText);
					styledText.setMenu(fTextContextMenu);

					getSite().registerContextMenu(getEditorContextMenuId(), fTextContextMenuManager, getSelectionProvider());

					// also register this menu for source page part and
					// structured text editor ids
					String partId = getSite().getId();
					if (partId != null) {
						getSite().registerContextMenu(partId + EDITOR_CONTEXT_MENU_SUFFIX, fTextContextMenuManager, getSelectionProvider());
					}
					getSite().registerContextMenu(EDITOR_CONTEXT_MENU_ID, fTextContextMenuManager, getSelectionProvider());
				}
			}
		}
	}

	/**
	 * Updates editor context menu, vertical ruler menu, help context id for
	 * new content type
	 * 
	 * @param contentType
	 */
	private void updateEditorControlsForContentType(String contentType) {
		if (contentType == null) {
			updateEditorContextMenuId(EDITOR_CONTEXT_MENU_ID);
			updateRulerContextMenuId(RULER_CONTEXT_MENU_ID);
			updateHelpContextId(ITextEditorHelpContextIds.TEXT_EDITOR);
		}
		else {
			updateEditorContextMenuId(contentType + EDITOR_CONTEXT_MENU_SUFFIX);
			updateRulerContextMenuId(contentType + RULER_CONTEXT_MENU_SUFFIX);
			updateHelpContextId(contentType + "_source_HelpId"); //$NON-NLS-1$
			
			/* Activate the contexts defined for this editor */
			activateContexts(getSite().getService(IContextService.class));
		}
	}
	
	private void updateEncodingMemento() {
		boolean failed = false;
		IStructuredModel internalModel = getInternalModel();
		if (internalModel != null) {
			IStructuredDocument doc = internalModel.getStructuredDocument();
			EncodingMemento memento = doc.getEncodingMemento();
			IDocumentCharsetDetector detector = internalModel.getModelHandler().getEncodingDetector();
			if (memento != null && detector != null) {
				detector.set(doc);
				try {
					String newEncoding = detector.getEncoding();
					if (newEncoding != null) {
						memento.setDetectedCharsetName(newEncoding);
					}
				}
				catch (IOException e) {
					failed = true;
				}
			}
			/**
			 * Be sure to use the new value but only if no exception
			 * occurred. (we may find cases we need to do more error recovery
			 * there) should be near impossible to get IOException from
			 * processing the _document_
			 */
			if (!failed) {
				doc.setEncodingMemento(memento);
			}
		}
	}

	/**
	 * Updates the help context of the editor with the given help context id
	 * 
	 * @param helpContextId
	 *            Cannot be null
	 */
	private void updateHelpContextId(String helpContextId) {
		if (!helpContextId.equals(getHelpContextId())) {
			setHelpContextId(helpContextId);

			if (getSourceViewer() != null) {
				StyledText styledText = getSourceViewer().getTextWidget();
				if (styledText != null) {
					IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench().getHelpSystem();
					helpSystem.setHelp(styledText, getHelpContextId());
				}
			}
		}
	}

	/*
	 * Update the hovering behavior depending on the preferences.
	 */
	private void updateHoverBehavior() {
		SourceViewerConfiguration configuration = getSourceViewerConfiguration();
		String[] types = configuration.getConfiguredContentTypes(getSourceViewer());

		ISourceViewer sourceViewer = getSourceViewer();
		if (sourceViewer == null)
			return;

		for (int i = 0; i < types.length; i++) {

			String t = types[i];

			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);
		}
	}

	private void updateMenuText() {
		ITextViewer viewer = getTextViewer();
		StyledText widget = null;
		if (viewer != null)
			widget = viewer.getTextWidget();

		if (fStructuredModel != null && !fStructuredModel.isModelStateChanging() && viewer != null && widget != null && !widget.isDisposed()) {
			// performance: don't force an update of the action bars unless
			// required as it is expensive
			String previousUndoText = null;
			String previousUndoDesc = null;
			String previousRedoText = null;
			String previousRedoDesc = null;
			boolean updateActions = false;
			IAction undoAction = getAction(ITextEditorActionConstants.UNDO);
			IAction redoAction = getAction(ITextEditorActionConstants.REDO);
			if (undoAction != null) {
				previousUndoText = undoAction.getText();
				previousUndoDesc = undoAction.getDescription();
				updateActions = updateActions || previousUndoText == null || previousUndoDesc == null;
				undoAction.setText(UNDO_ACTION_TEXT_DEFAULT);
				undoAction.setDescription(UNDO_ACTION_DESC_DEFAULT);
			}
			if (redoAction != null) {
				previousRedoText = redoAction.getText();
				previousRedoDesc = redoAction.getDescription();
				updateActions = updateActions || previousRedoText == null || previousRedoDesc == null;
				redoAction.setText(REDO_ACTION_TEXT_DEFAULT);
				redoAction.setDescription(REDO_ACTION_DESC_DEFAULT);
			}
			if (fStructuredModel.getUndoManager() != null) {
				IStructuredTextUndoManager undoManager = fStructuredModel.getUndoManager();
				// get undo command
				Command undoCommand = undoManager.getUndoCommand();
				// set undo label and description
				if (undoAction != null) {
					undoAction.setEnabled(undoManager.undoable());
					if (undoCommand != null) {
						String label = undoCommand.getLabel();
						if (label != null) {
							String customText = MessageFormat.format(UNDO_ACTION_TEXT, new Object[]{label});
							updateActions = updateActions || customText == null || previousUndoText == null || !customText.equals(previousUndoText);
							undoAction.setText(customText);
						}
						String desc = undoCommand.getDescription();
						if (desc != null) {
							String customDesc = MessageFormat.format(UNDO_ACTION_DESC, new Object[]{desc});
							updateActions = updateActions || customDesc == null || previousRedoDesc == null || !customDesc.equals(previousUndoDesc);
							undoAction.setDescription(customDesc);
						}
					}
				}
				// get redo command
				Command redoCommand = undoManager.getRedoCommand();
				// set redo label and description
				if (redoAction != null) {
					redoAction.setEnabled(undoManager.redoable());
					if (redoCommand != null) {
						String label = redoCommand.getLabel();
						if (label != null) {
							String customText = MessageFormat.format(REDO_ACTION_TEXT, new Object[]{label});
							updateActions = updateActions || customText == null || previousRedoText == null || !customText.equals(previousRedoText);
							redoAction.setText(customText);
						}
						String desc = redoCommand.getDescription();
						if (desc != null) {
							String customDesc = MessageFormat.format(REDO_ACTION_DESC, new Object[]{desc});
							updateActions = updateActions || customDesc == null || previousRedoDesc == null || !customDesc.equals(previousRedoDesc);
							redoAction.setDescription(customDesc);
						}
					}
				}
			}
			// tell the action bars to update
			if (updateActions) {
				if (getEditorSite().getActionBars() != null) {
					getEditorSite().getActionBars().updateActionBars();
				}
				else if (getEditorPart() != null && getEditorPart().getEditorSite().getActionBars() != null) {
					getEditorPart().getEditorSite().getActionBars().updateActionBars();
				}
			}
		}
	}

	void updateRangeIndication(ISelection selection) {
		boolean rangeUpdated = false;
		if (selection instanceof IStructuredSelection && !((IStructuredSelection) selection).isEmpty()) {
			Object[] objects = ((IStructuredSelection) selection).toArray();
			if (objects.length > 0 ) {
				// no ordering is guaranteed for multiple selection
				Object o = objects[0];
				IRegion region = fStructuredSelectionProvider.selectionConverter.getRegion(o);
				int start = region.getOffset();
				int end = start + region.getLength();
				if (objects.length > 1) {
					for (int i = 1; i < objects.length; i++) {
						region = fStructuredSelectionProvider.selectionConverter.getRegion(objects[i]);
						start = Math.min(start, region.getOffset());
						end = Math.max(end, region.getOffset() + region.getLength());
					}
				}
				getSourceViewer().setRangeIndication(start, end - start, false);
				rangeUpdated = true;
			}
		}
		if (!rangeUpdated && getSourceViewer() != null) {
			if (selection instanceof ITextSelection) {
				getSourceViewer().setRangeIndication(((ITextSelection) selection).getOffset(), ((ITextSelection) selection).getLength(), false);
			}
			else {
				getSourceViewer().removeRangeIndication();
			}
		}
	}


	/**
	 * Updates the editor vertical ruler menu by creating a new vertical ruler
	 * context menu with the given menu id
	 * 
	 * @param rulerMenuId
	 *            Cannot be null
	 */
	private void updateRulerContextMenuId(String rulerMenuId) {
		// update ruler context menu id if updating to a new id or if context
		// menu is not already set up
		if (!rulerMenuId.equals(getRulerContextMenuId()) || (fRulerContextMenu == null)) {
			setRulerContextMenuId(rulerMenuId);

			if (getVerticalRuler() != null) {
				// dispose of previous ruler context menu
				if (fRulerContextMenu != null) {
					fRulerContextMenu.dispose();
				}
				if (fRulerContextMenuManager != null) {
					fRulerContextMenuManager.removeMenuListener(getContextMenuListener());
					fRulerContextMenuManager.removeAll();
					fRulerContextMenuManager.dispose();
				}

				fRulerContextMenuManager = new MenuManager(getRulerContextMenuId(), getRulerContextMenuId());
				fRulerContextMenuManager.setRemoveAllWhenShown(true);
				fRulerContextMenuManager.addMenuListener(getContextMenuListener());

				Control rulerControl = getVerticalRuler().getControl();
				fRulerContextMenu = fRulerContextMenuManager.createContextMenu(rulerControl);
				rulerControl.setMenu(fRulerContextMenu);

				getSite().registerContextMenu(getRulerContextMenuId(), fRulerContextMenuManager, getSelectionProvider());

				// also register this menu for source page part and structured
				// text editor ids
				String partId = getSite().getId();
				if (partId != null) {
					getSite().registerContextMenu(partId + RULER_CONTEXT_MENU_SUFFIX, fRulerContextMenuManager, getSelectionProvider());
				}
				getSite().registerContextMenu(RULER_CONTEXT_MENU_ID, fRulerContextMenuManager, getSelectionProvider());
			}
		}
	}

	private void updateSourceViewerConfiguration() {
		SourceViewerConfiguration configuration = getSourceViewerConfiguration();
		// no need to update source viewer configuration if one does not exist
		// yet
		if (configuration == null) {
			return;
		}
		// do not configure source viewer configuration twice
		boolean configured = false;

		// structuredtextviewer only works with
		// structuredtextviewerconfiguration
		if (!(configuration instanceof StructuredTextViewerConfiguration)) {
			ConfigurationAndTarget cat = createSourceViewerConfiguration();
			fViewerConfigurationTargetId = cat.getTargetId();
			configuration = cat.getConfiguration();
			setSourceViewerConfiguration(configuration);
			configured = true;
		}
		else {
			ConfigurationAndTarget cat = createSourceViewerConfiguration();
			StructuredTextViewerConfiguration newViewerConfiguration = cat.getConfiguration();
			if (!(cat.getTargetId().equals(fViewerConfigurationTargetId))) {
				// d282894 use newViewerConfiguration
				fViewerConfigurationTargetId = cat.getTargetId();
				configuration = newViewerConfiguration;
				setSourceViewerConfiguration(configuration);
				configured = true;
			}
		}

		if (getSourceViewer() != null) {
			// not sure if really need to reconfigure when input changes
			// (maybe only need to reset viewerconfig's document)
			if (!configured)
				getSourceViewer().configure(configuration);
			IAction openHyperlinkAction = getAction(StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE);
			if (openHyperlinkAction instanceof OpenHyperlinkAction) {
				((OpenHyperlinkAction) openHyperlinkAction).setHyperlinkDetectors(getSourceViewerConfiguration().getHyperlinkDetectors(getSourceViewer()));
			}
		}
	}

	@Override
	protected void updateStatusField(String category) {
		super.updateStatusField(category);

		if (category == null)
			return;

		if (StructuredTextEditorActionConstants.STATUS_CATEGORY_OFFSET.equals(category)) {
			IStatusField field = getStatusField(category);
			ISourceViewer sourceViewer = getSourceViewer();
			if (field != null && sourceViewer != null) {
				Point selection = sourceViewer.getTextWidget().getSelection();
				int offset1 = widgetOffset2ModelOffset(sourceViewer, selection.x);
				int offset2 = widgetOffset2ModelOffset(sourceViewer, selection.y);
				String text = null;
				if (offset1 != offset2)
					text = "[" + offset1 + "-" + offset2 + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				else
					text = "[ " + offset1 + " ]"; //$NON-NLS-1$ //$NON-NLS-2$
				field.setText(text == null ? fErrorLabel : text);
			}
		}
	}
	
	@Override
	public Annotation gotoAnnotation(boolean forward) {
		Annotation result = super.gotoAnnotation(forward);
		if(result != null)
			fSelectionChangedFromGoto = true;
		return result;
	}

	void updateStatusLine(ISelection selection) {
		// Bug 210481 - Don't update the status line if the selection
		// was caused by go to navigation
		if(fSelectionChangedFromGoto) {
			fSelectionChangedFromGoto = false;
			return;
		}
		IStatusLineManager statusLineManager = getEditorSite().getActionBars().getStatusLineManager();
		if (fStatusLineLabelProvider != null && statusLineManager != null) {
			String text = null;
			Image image = null;
			if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
				Object firstElement = ((IStructuredSelection) selection).getFirstElement();
				if (firstElement != null) {
					text = fStatusLineLabelProvider.getText(firstElement);
					image = fStatusLineLabelProvider.getImage((firstElement));
				}
			}
			if (image == null) {
				statusLineManager.setMessage(text);
			}
			else {
				statusLineManager.setMessage(image, text);
			}
		}
	}

	/**
	 * 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
	 */
	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);
	}

	@Override
	protected SourceViewerDecorationSupport getSourceViewerDecorationSupport(ISourceViewer viewer) {
		/* Removed workaround for Bug [206913] source annotations are not painting in source editors.
		 * With the new presentation reconciler, we no longer need to force the painting. This
		 * actually caused Bug [219776] Wrong annotation display on macs. We forced the
		 * Squiggles strategy, even when the native problem underline was specified for annotations */
		return super.getSourceViewerDecorationSupport(viewer);
	}

	private void installCharacterPairing() {
		IStructuredModel model = getInternalModel();
		if (model != null) {
			IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(SSEUIPlugin.ID, "characterPairing"); //$NON-NLS-1$
			IContentTypeManager mgr = Platform.getContentTypeManager();
			IContentType type = mgr.getContentType(model.getContentTypeIdentifier());
			if (type != null) {
				for (int i = 0; i < elements.length; i++) {
					// Create the inserter
					IConfigurationElement element = elements[i];
					try {
						IConfigurationElement[] contentTypes = element.getChildren("contentTypeIdentifier");
						for (int j = 0; j < contentTypes.length; j++) {
							String id = contentTypes[j].getAttribute("id");
							if (id != null) {
								IContentType targetType = mgr.getContentType(id);
								int priority = calculatePriority(type, targetType, 0);
								if (priority >= 0) {
									final CharacterPairing pairing = new CharacterPairing();
									pairing.priority = priority;
									String[] partitions = StringUtils.unpack(contentTypes[j].getAttribute("partitions"));
									pairing.partitions = new HashSet<>(partitions.length);
									// Only add the inserter if there is at least one partition for the content type
									for (int k = 0; k < partitions.length; k++) {
										pairing.partitions.add(partitions[k]);
									}

									pairing.inserter = (AbstractCharacterPairInserter) element.createExecutableExtension("class");
									if (pairing.inserter != null && partitions.length > 0) {
										fPairInserter.addInserter(pairing);
										/* use a SafeRunner since this method is also invoked during Part creation */
										SafeRunner.run(new ISafeRunnable() {
											@Override
											public void run() throws Exception {
												pairing.inserter.initialize();
											}

											@Override
											public void handleException(Throwable exception) {
												// rely on default logging
											}
										});
									}
								}
							}
						}
					} catch (CoreException e) {
						Logger.logException(e);
					}
				}
				fPairInserter.prioritize();
			}
		}
	}

	/**
	 * Calculates the priority of the target content type. The closer <code>targetType</code>
	 * is to <code>type</code> the higher its priority.
	 * 
	 * @param type
	 * @param targetType
	 * @param priority
	 * @return
	 */
	private int calculatePriority(IContentType type, IContentType targetType, int priority) {
		if (type == null || targetType == null)
			return -1;
		if (type.getId().equals(targetType.getId()))
			return priority;
		return calculatePriority(type.getBaseType(), targetType, ++priority);
	}

	/**
	 * Installs semantic highlighting on the editor
	 */
	private void installSemanticHighlighting() {
		IStructuredModel model = getInternalModel();
		if (fSemanticManager == null && model != null) {
			fSemanticManager = new SemanticHighlightingManager();
			fSemanticManager.install(getSourceViewer(), getPreferenceStore(), getSourceViewerConfiguration(), model.getContentTypeIdentifier());
		}
	}
	
	/**
	 * Uninstalls semantic highlighting on the editor and performs cleanup
	 */
	private void uninstallSemanticHighlighting() {
		if (fSemanticManager != null) {
			fSemanticManager.uninstall();
			fSemanticManager = null;
		}
	}

	private IInformationPresenter configureOutlinePresenter(ISourceViewer sourceViewer, SourceViewerConfiguration config) {
		InformationPresenter presenter = null;

		// Get the quick outline configuration
		AbstractQuickOutlineConfiguration cfg = null;
		ExtendedConfigurationBuilder builder = ExtendedConfigurationBuilder.getInstance();
		String[] ids = getConfigurationPoints();
		for (int i = 0; cfg == null && i < ids.length; i++) {
			cfg = (AbstractQuickOutlineConfiguration) builder.getConfiguration(ExtendedConfigurationBuilder.QUICKOUTLINECONFIGURATION, ids[i]);
		}

		if (cfg != null) {
			presenter = new InformationPresenter(getOutlinePresenterControlCreator(cfg));
			presenter.setDocumentPartitioning(config.getConfiguredDocumentPartitioning(sourceViewer));
			presenter.setAnchor(AbstractInformationControlManager.ANCHOR_GLOBAL);
			IInformationProvider provider = new SourceInfoProvider(this);
			String[] contentTypes = config.getConfiguredContentTypes(sourceViewer);
			for (int i = 0; i < contentTypes.length; i++) {
				presenter.setInformationProvider(provider, contentTypes[i]);
			}
			presenter.setSizeConstraints(50, 20, true, false);
		}
		return presenter;
	}

	/**
	 * Returns the outline presenter control creator. The creator is a 
	 * factory creating outline presenter controls for the given source viewer. 
	 *
	 * @param sourceViewer the source viewer to be configured by this configuration
	 * @return an information control creator
	 */
	private IInformationControlCreator getOutlinePresenterControlCreator(final AbstractQuickOutlineConfiguration config) {
		return new IInformationControlCreator() {
			@Override
			public IInformationControl createInformationControl(Shell parent) {
				int shellStyle = SWT.RESIZE;
				return new QuickOutlinePopupDialog(parent, shellStyle, getInternalModel(), config);
			}
		};
	}

	@Override
	public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) {
		super.setInitializationData(cfig, propertyName, data);
		if (data instanceof Map<?, ?>) {
			fInitializationData = (Map<?,?>) data;
			setPreferenceStore(createCombinedPreferenceStore());
		}
	}
}
