org.eclipse.datatools.sqltools.sqleditor.SQLEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.datatools.sqltools.sqleditor.SQLEditor.java

Source

/***********************************************************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others. All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0 which is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: IBM Corporation - initial API and implementation
 **********************************************************************************************************************/
package org.eclipse.datatools.sqltools.sqleditor;

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

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.datatools.modelbase.sql.schema.Database;
import org.eclipse.datatools.sqltools.common.ui.dialog.SaveAsDialog;
import org.eclipse.datatools.sqltools.core.DatabaseIdentifier;
import org.eclipse.datatools.sqltools.core.DatabaseVendorDefinitionId;
import org.eclipse.datatools.sqltools.core.SQLDevToolsConfiguration;
import org.eclipse.datatools.sqltools.core.SQLToolsFacade;
import org.eclipse.datatools.sqltools.core.services.ActionService;
import org.eclipse.datatools.sqltools.core.services.SQLEditorService;
import org.eclipse.datatools.sqltools.core.services.SQLEditorUIService;
import org.eclipse.datatools.sqltools.editor.contentassist.ISQLDBProposalsService;
import org.eclipse.datatools.sqltools.editor.core.connection.ISQLEditorConnectionInfo;
import org.eclipse.datatools.sqltools.editor.ui.core.SQLDevToolsUIConfiguration;
import org.eclipse.datatools.sqltools.editor.ui.core.SQLToolsUIFacade;
import org.eclipse.datatools.sqltools.plan.IPlanOption;
import org.eclipse.datatools.sqltools.sql.parser.ParserParameters;
import org.eclipse.datatools.sqltools.sql.parser.ParsingResult;
import org.eclipse.datatools.sqltools.sql.parser.SQLParser;
import org.eclipse.datatools.sqltools.sql.parser.SQLParserConstants;
import org.eclipse.datatools.sqltools.sql.parser.ast.SimpleNode;
import org.eclipse.datatools.sqltools.sqleditor.internal.IHelpContextIds;
import org.eclipse.datatools.sqltools.sqleditor.internal.PreferenceConstants;
import org.eclipse.datatools.sqltools.sqleditor.internal.SQLEditorContributorExtensionRegistry;
import org.eclipse.datatools.sqltools.sqleditor.internal.SQLEditorDocumentSetupParticipant;
import org.eclipse.datatools.sqltools.sqleditor.internal.SQLEditorPlugin;
import org.eclipse.datatools.sqltools.sqleditor.internal.SQLEditorResources;
import org.eclipse.datatools.sqltools.sqleditor.internal.SymbolInserter;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.AddTemplateAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.DMLDialogSelectionSQLAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.ExecuteCurrentSQLAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.ExecuteSQLAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.ExecuteSQLAsOneStatementAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.ExecuteSelectionSQLAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.GotoMatchingTokenAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.SQLConnectAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.actions.ToggleCommentAction;
import org.eclipse.datatools.sqltools.sqleditor.internal.editor.SQLEditorContentOutlinePage;
import org.eclipse.datatools.sqltools.sqleditor.internal.editor.SQLOutlinePage;
import org.eclipse.datatools.sqltools.sqleditor.internal.editor.SQLSourceViewerConfiguration;
import org.eclipse.datatools.sqltools.sqleditor.internal.editor.SQLUpdater;
import org.eclipse.datatools.sqltools.sqleditor.internal.matching.AbstractPairMatcher;
import org.eclipse.datatools.sqltools.sqleditor.internal.matching.GenericSQLMatchingPairs;
import org.eclipse.datatools.sqltools.sqleditor.internal.matching.GenericSQLPairMatcher;
import org.eclipse.datatools.sqltools.sqleditor.internal.sql.ISQLPartitions;
import org.eclipse.datatools.sqltools.sqleditor.internal.sql.SQLDBProposalsService;
import org.eclipse.datatools.sqltools.sqleditor.internal.sql.SQLPartitionScanner;
import org.eclipse.datatools.sqltools.sqleditor.internal.utils.SQLColorProvider;
import org.eclipse.datatools.sqltools.sqleditor.preferences.ContentAssistPreference;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
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.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.AbstractInformationControlManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextHover;
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.ITextViewerExtension4;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.information.IInformationProvider;
import org.eclipse.jface.text.information.IInformationProviderExtension;
import org.eclipse.jface.text.information.IInformationProviderExtension2;
import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.rules.FastPartitioner;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.IAnnotationHoverExtension;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
import org.eclipse.jface.text.source.ILineRange;
import org.eclipse.jface.text.source.IOverviewRuler;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.ISourceViewerExtension2;
import org.eclipse.jface.text.source.ISourceViewerExtension3;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.IVerticalRulerInfo;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.editors.text.FileDocumentProvider;
import org.eclipse.ui.editors.text.ILocationProvider;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.DefaultRangeIndicator;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.ui.texteditor.ResourceAction;
import org.eclipse.ui.texteditor.TextEditorAction;
import org.eclipse.ui.texteditor.TextOperationAction;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

/**
 * This class is responsible for configuring the SQL editor.
 */
public class SQLEditor extends TextEditor implements IPropertyChangeListener {

    /**
     * Internal implementation class for a change listener.
     */
    protected abstract class AbstractSelectionChangedListener implements ISelectionChangedListener {

        /**
         * Installs this selection changed listener with the given selection provider. If the selection provider is a
         * post selection provider, post selection changed events are the preferred choice, otherwise normal selection
         * changed events are requested.
         * 
         * @param selectionProvider
         */
        public void install(ISelectionProvider selectionProvider) {
            if (selectionProvider == null) {
                return;
            }

            if (selectionProvider instanceof IPostSelectionProvider) {
                IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
                provider.addPostSelectionChangedListener(this);
            } else {
                selectionProvider.addSelectionChangedListener(this);
            }
        }

        /**
         * Removes this selection changed listener from the given selection provider.
         * 
         * @param selectionProvider the selection provider
         */
        public void uninstall(ISelectionProvider selectionProvider) {
            if (selectionProvider == null) {
                return;
            }

            if (selectionProvider instanceof IPostSelectionProvider) {
                IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
                provider.removePostSelectionChangedListener(this);
            } else {
                selectionProvider.removeSelectionChangedListener(this);
            }
        }
    }

    /**
     * Information provider used to present focusable information shells.
     * 
     */
    private static final class InformationProvider
            implements IInformationProvider, IInformationProviderExtension, IInformationProviderExtension2 {

        private IRegion fHoverRegion;
        private Object fHoverInfo;
        private IInformationControlCreator fControlCreator;

        InformationProvider(IRegion hoverRegion, Object hoverInfo, IInformationControlCreator controlCreator) {
            fHoverRegion = hoverRegion;
            fHoverInfo = hoverInfo;
            fControlCreator = controlCreator;
        }

        /*
         * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer,
         *      int)
         */
        public IRegion getSubject(ITextViewer textViewer, int invocationOffset) {
            return fHoverRegion;
        }

        /*
         * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer,
         *      org.eclipse.jface.text.IRegion)
         */
        public String getInformation(ITextViewer textViewer, IRegion subject) {
            return fHoverInfo.toString();
        }

        /*
         * @see org.eclipse.jface.text.information.IInformationProviderExtension#getInformation2(org.eclipse.jface.text.ITextViewer,
         *      org.eclipse.jface.text.IRegion)
         * @since 3.2
         */
        public Object getInformation2(ITextViewer textViewer, IRegion subject) {
            return fHoverInfo;
        }

        /*
         * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator()
         */
        public IInformationControlCreator getInformationPresenterControlCreator() {
            return fControlCreator;
        }
    }

    /**
     * This action behaves in two different ways: If there is no current text hover, the SQL information is displayed
     * using information presenter. If there is a current text hover, it is converted into a information presenter in
     * order to make it sticky.
     * 
     * @see AbstractTextEditor#InformationDispatchAction. Copied out to support Eclipse 3.2
     * 
     */
    private final class InformationDispatchAction extends TextEditorAction {

        /** The wrapped text operation action. */
        private final TextOperationAction fTextOperationAction;

        /**
         * Creates a dispatch action.
         * 
         * @param resourceBundle the resource bundle
         * @param prefix the prefix
         * @param textOperationAction the text operation action
         */
        public InformationDispatchAction(ResourceBundle resourceBundle, String prefix,
                final TextOperationAction textOperationAction) {
            super(resourceBundle, prefix, SQLEditor.this);
            if (textOperationAction == null)
                throw new IllegalArgumentException();
            fTextOperationAction = textOperationAction;
        }

        /*
         * @see org.eclipse.jface.action.IAction#run()
         */
        public void run() {

            ISourceViewer sourceViewer = getSourceViewer();
            if (sourceViewer == null) {
                if (fTextOperationAction.isEnabled())
                    fTextOperationAction.run();
                return;
            }

            if (sourceViewer instanceof ITextViewerExtension4) {
                ITextViewerExtension4 extension4 = (ITextViewerExtension4) sourceViewer;
                if (extension4.moveFocusToWidgetToken())
                    return;
            }

            if (sourceViewer instanceof ITextViewerExtension2) {
                // does a text hover exist?
                ITextHover textHover = ((ITextViewerExtension2) sourceViewer).getCurrentTextHover();
                if (textHover != null && makeTextHoverFocusable(sourceViewer, textHover))
                    return;
            }

            if (sourceViewer instanceof ISourceViewerExtension3) {
                // does an annotation hover exist?
                IAnnotationHover annotationHover = ((ISourceViewerExtension3) sourceViewer)
                        .getCurrentAnnotationHover();
                if (annotationHover != null && makeAnnotationHoverFocusable(sourceViewer, annotationHover))
                    return;
            }
            //            
            // otherwise, just run the action
            if (fTextOperationAction.isEnabled())
                fTextOperationAction.run();
        }

        /**
         * Tries to make a text hover focusable (or "sticky").
         * 
         * @param sourceViewer the source viewer to display the hover over
         * @param textHover the hover to make focusable
         * @return <code>true</code> if successful, <code>false</code> otherwise
         */
        private boolean makeTextHoverFocusable(ISourceViewer sourceViewer, ITextHover textHover) {
            Point hoverEventLocation = ((ITextViewerExtension2) sourceViewer).getHoverEventLocation();
            int offset = computeOffsetAtLocation(sourceViewer, hoverEventLocation.x, hoverEventLocation.y);
            if (offset == -1)
                return false;

            try {
                IRegion hoverRegion = textHover.getHoverRegion(sourceViewer, offset);
                if (hoverRegion == null)
                    return false;

                String hoverInfo = textHover.getHoverInfo(sourceViewer, hoverRegion);

                IInformationControlCreator controlCreator = null;
                if (textHover instanceof IInformationProviderExtension2)
                    controlCreator = ((IInformationProviderExtension2) textHover)
                            .getInformationPresenterControlCreator();

                IInformationProvider informationProvider = new InformationProvider(hoverRegion, hoverInfo,
                        controlCreator);

                _informationPresenter.setOffset(offset);
                _informationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_BOTTOM);
                _informationPresenter.setMargins(6, 6); // default values from AbstractInformationControlManager
                String contentType = TextUtilities.getContentType(sourceViewer.getDocument(),
                        getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()), offset,
                        true);
                _informationPresenter.setInformationProvider(informationProvider, contentType);
                _informationPresenter.showInformation();

                return true;

            } catch (BadLocationException e) {
                return false;
            }
        }

        /**
         * Tries to make an annotation hover focusable (or "sticky").
         * 
         * @param sourceViewer the source viewer to display the hover over
         * @param annotationHover the hover to make focusable
         * @return <code>true</code> if successful, <code>false</code> otherwise
         */
        private boolean makeAnnotationHoverFocusable(ISourceViewer sourceViewer, IAnnotationHover annotationHover) {
            IVerticalRulerInfo info = getVerticalRuler();
            int line = info.getLineOfLastMouseButtonActivity();
            if (line == -1)
                return false;

            try {

                // compute the hover information
                Object hoverInfo;
                if (annotationHover instanceof IAnnotationHoverExtension) {
                    IAnnotationHoverExtension extension = (IAnnotationHoverExtension) annotationHover;
                    ILineRange hoverLineRange = extension.getHoverLineRange(sourceViewer, line);
                    if (hoverLineRange == null)
                        return false;
                    final int maxVisibleLines = Integer.MAX_VALUE; // allow any number of lines being displayed, as we
                                                                   // support scrolling
                    hoverInfo = extension.getHoverInfo(sourceViewer, hoverLineRange, maxVisibleLines);
                } else {
                    hoverInfo = annotationHover.getHoverInfo(sourceViewer, line);
                }

                // hover region: the beginning of the concerned line to place the control right over the line
                IDocument document = sourceViewer.getDocument();
                int offset = document.getLineOffset(line);
                String contentType = TextUtilities.getContentType(document,
                        getSourceViewerConfiguration().getConfiguredDocumentPartitioning(getSourceViewer()), offset,
                        true);

                IInformationControlCreator controlCreator = null;
                if (annotationHover instanceof IInformationProviderExtension2)
                    controlCreator = ((IInformationProviderExtension2) annotationHover)
                            .getInformationPresenterControlCreator();
                else if (annotationHover instanceof IAnnotationHoverExtension)
                    controlCreator = ((IAnnotationHoverExtension) annotationHover).getHoverControlCreator();

                IInformationProvider informationProvider = new InformationProvider(new Region(offset, 0), hoverInfo,
                        controlCreator);

                _informationPresenter.setOffset(offset);
                _informationPresenter.setAnchor(AbstractInformationControlManager.ANCHOR_RIGHT);
                _informationPresenter.setMargins(4, 0);
                _informationPresenter.setInformationProvider(informationProvider, contentType);
                _informationPresenter.showInformation();

                return true;

            } catch (BadLocationException e) {
                return false;
            }
        }

        // modified version from TextViewer
        private int computeOffsetAtLocation(ITextViewer textViewer, int x, int y) {

            StyledText styledText = textViewer.getTextWidget();
            IDocument document = textViewer.getDocument();

            if (document == null)
                return -1;

            try {
                int widgetOffset = styledText.getOffsetAtLocation(new Point(x, y));
                Point p = styledText.getLocationAtOffset(widgetOffset);
                if (p.x > x)
                    widgetOffset--;

                if (textViewer instanceof ITextViewerExtension5) {
                    ITextViewerExtension5 extension = (ITextViewerExtension5) textViewer;
                    return extension.widgetOffset2ModelOffset(widgetOffset);
                }
                IRegion visibleRegion = textViewer.getVisibleRegion();
                return widgetOffset + visibleRegion.getOffset();
            } catch (IllegalArgumentException e) {
                return -1;
            }

        }
    }

    /**
     * Updates the selection in the editor's widget with the selection of the outline page.
     */
    protected class OutlineSelectionChangedListener extends AbstractSelectionChangedListener {
        public void selectionChanged(SelectionChangedEvent event) {
            ISelection selection = event.getSelection();
            Object element = ((IStructuredSelection) selection).getFirstElement();
            SimpleNode node = element instanceof SimpleNode ? (SimpleNode) element : null;

            setSelection(node);
        }
    }

    public class AdaptedSourceViewer extends ProjectionViewer {

        /**
         * @param parent
         * @param verticalRuler
         * @param overviewRuler
         * @param showAnnotationsOverview
         * @param styles
         */
        public AdaptedSourceViewer(Composite parent, IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
                boolean showAnnotationsOverview, int styles) {
            super(parent, verticalRuler, overviewRuler, showAnnotationsOverview, styles);
        }

        public IContentAssistant getContentAssistant() {
            return fContentAssistant;
        }
    }

    class propertyChangeListener implements IPropertyChangeListener {

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
         */
        public void propertyChange(PropertyChangeEvent event) {
            AdaptedSourceViewer asv = (AdaptedSourceViewer) getSourceViewer();
            if (asv != null) {
                String p = event.getProperty();
                ContentAssistant contentAssistant = (ContentAssistant) asv.getContentAssistant();

                if (contentAssistant instanceof ContentAssistant) {
                    ContentAssistPreference.changeConfiguration((ContentAssistant) contentAssistant,
                            getPreferenceStore(), event);
                }
                SQLEditor.this.handlePreferenceStoreChanged(event);
            }

        }

    }

    private class EditorSelectionChangedListener extends AbstractSelectionChangedListener {

        public void selectionChanged(SelectionChangedEvent event) {
            ISourceViewer sourceViewer = getSourceViewer();
            IDocument document = sourceViewer.getDocument();
            IRegion selection = getSignedSelection(sourceViewer);

            IRegion region = _pairMatcher.match(document, selection.getOffset());

            // Indicating the range between a pair of matching tokens, if they exist.
            if (region != null) {
                sourceViewer.setRangeIndication(region.getOffset(), region.getLength(), false);
                return;
            }

            // If no matching tokens, indicating current line.
            sourceViewer.setRangeIndication(selection.getOffset(), 0, false);
        }
    }

    public static final String PLUGIN_NAME = "org.eclipse.datatools.sqltools.sqleditor"; //$NON-NLS-1$
    public static final String HELP_CONTEXT_ID = PLUGIN_NAME + ".sqleditorhelp"; //$NON-NLS-1$

    /** The selection changed listener */
    protected AbstractSelectionChangedListener _fOutlineSelectionChangedListener = new OutlineSelectionChangedListener();
    /** The editor selection changed listener */
    private EditorSelectionChangedListener _fEditorSelectionChangedListener = null;
    /** The content outline page providing the outline view for the editor content. */
    private SQLOutlinePage _fOutlinePage = null;
    /** The object updating outline view and syntax validation. */
    protected SQLUpdater _fSQLUpdater = null;
    /** The projection (code folding) support object. */
    private ProjectionSupport fProjectionSupport;
    /** The document setup participant object, which is used partition the edit text. */
    private SQLEditorDocumentSetupParticipant fDocSetupParticipant;
    /** The content assist proposal service for database objects. */
    private ISQLDBProposalsService fDBProposalsService;
    /** The result value generated by SQLParser */
    protected ParsingResult _parsingResult = null;
    private SymbolInserter _symbolInserter = null;
    private ArrayList _profileListeners = new ArrayList();
    private InformationPresenter _informationPresenter;
    private IEditorPart _parentEditor = null;
    /** The token matcher. */
    private ICharacterPairMatcher _pairMatcher = null;
    /** Matching token painter. */
    private MatchingPairPainter _painter = null;
    /** Tracking the cursor position */
    private int _previousCursorLine = -1;

    /**
     * Constructs an instance of this class. This is the default constructor.
     */
    public SQLEditor() {
        super();
        _symbolInserter = new SymbolInserter(this);
    }

    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
        super.init(site, input);
        fireConnectionProfileAttached();

        // Set corresponding token matcher, according to database type.
        SQLDevToolsUIConfiguration sqlDevToolsConfig = SQLToolsUIFacade.getConfiguration(getDBType(),
                getDatabaseIdentifier());
        _pairMatcher = sqlDevToolsConfig.getSQLEditorUIService().getSQLPairMatcher();

        // If the specific database token matcher is not supported, set default generic sql matcher.
        if (_pairMatcher == null) {
            _pairMatcher = new GenericSQLPairMatcher(GenericSQLMatchingPairs.getInstance());
        }

        ((AbstractPairMatcher) _pairMatcher).setSQLEditor(this);
    }

    /**
     * Creates and installs the editor actions.
     * 
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions()
     */
    protected void createActions() {
        super.createActions();
        ResourceBundle bundle = getResourceBundle();
        IActionBars bars = ((IEditorSite) getSite()).getActionBars();

        IAction a = new TextOperationAction(bundle, "ContentAssistProposal.", this, //$NON-NLS-1$
                ISourceViewer.CONTENTASSIST_PROPOSALS);
        a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
        setAction("ContentAssistProposal", a); //$NON-NLS-1$

        a = new TextOperationAction(bundle, "ContentAssistTip.", this, //$NON-NLS-1$
                ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION);
        a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
        setAction("ContentAssistTip", a); //$NON-NLS-1$

        a = new TextOperationAction(bundle, "ContentFormat.", this, ISourceViewer.FORMAT); //$NON-NLS-1$
        setAction("ContentFormat", a); //$NON-NLS-1$

        a = new TextOperationAction(bundle, "ShowSQLInfo.", this, ISourceViewer.INFORMATION, true); //$NON-NLS-1$
        a = new InformationDispatchAction(bundle, "ShowSQLInfo.", (TextOperationAction) a); //$NON-NLS-1$
        a.setActionDefinitionId(ISQLEditorActionConstants.SHOW_INFORMATION_ACTION_ID);
        setAction(ISQLEditorActionConstants.SHOW_INFORMATION_ACTION_ID, a);

        // ToggleCommentAction
        a = new ToggleCommentAction(bundle, "SQLEditor.action.toggle.commect.", this); //$NON-NLS-1$
        setAction(ISQLEditorActionConstants.TOGGLE_COMMENT, a); //$NON-NLS-1$
        configureToggleCommentAction(a);
        markAsStateDependentAction(ISQLEditorActionConstants.TOGGLE_COMMENT, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.TOGGLE_COMMENT,
                getAction(ISQLEditorActionConstants.TOGGLE_COMMENT));

        // GotoMatchingTokenAction
        setAction(ISQLEditorActionConstants.GOTO_MATCHING_TOKEN_ACTION_ID, new GotoMatchingTokenAction(this));
        markAsStateDependentAction(ISQLEditorActionConstants.GOTO_MATCHING_TOKEN_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.GOTO_MATCHING_TOKEN_ACTION_ID,
                getAction(ISQLEditorActionConstants.GOTO_MATCHING_TOKEN_ACTION_ID));

        setAction(ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID, new ExecuteSQLAction(this));
        bars.setGlobalActionHandler(ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID,
                getAction(ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID));

        setAction(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID, new ExecuteSelectionSQLAction(this));
        markAsSelectionDependentAction(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID,
                getAction(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID));

        setAction(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID,
                new ExecuteSQLAsOneStatementAction(this));
        markAsSelectionDependentAction(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID,
                getAction(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID));

        setAction(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID, new ExecuteCurrentSQLAction(this));
        markAsSelectionDependentAction(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID,
                getAction(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID));

        setAction(ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID,
                new DMLDialogSelectionSQLAction(this));
        markAsSelectionDependentAction(ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID,
                getAction(ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID));

        setAction(ISQLEditorActionConstants.SAVE_AS_TEMPLATE_ACTION_ID,
                new AddTemplateAction(getResourceBundle(), "AddTemplateAction.", this)); //$NON-NLS-1$
        markAsSelectionDependentAction(ISQLEditorActionConstants.SAVE_AS_TEMPLATE_ACTION_ID, true);
        bars.setGlobalActionHandler(ISQLEditorActionConstants.SAVE_AS_TEMPLATE_ACTION_ID,
                getAction(ISQLEditorActionConstants.SAVE_AS_TEMPLATE_ACTION_ID));

        final Shell shell;
        if (getSourceViewer() != null)
            shell = getSourceViewer().getTextWidget().getShell();
        else
            shell = null;
        a = new ResourceAction(bundle, "Editor.ContextPreferencesAction.") { //$NON-NLS-1$
            public void run() {
                String[] preferencePages = collectContextMenuPreferencePages();
                if (preferencePages.length > 0 && (shell == null || !shell.isDisposed()))
                    PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null)
                            .open();
            }
        };
        a.setId(ITextEditorActionConstants.CONTEXT_PREFERENCES);
        setAction(ITextEditorActionConstants.CONTEXT_PREFERENCES, a);

    }

    /**
     * Creates and returns the content outline page for the SQL editor.
     * 
     * @return the new content outline page
     */
    protected SQLEditorContentOutlinePage createContentOutlinePage() {
        SQLEditorContentOutlinePage outlinePage = new SQLEditorContentOutlinePage(getDocumentProvider(), this);

        return outlinePage;
    }

    /**
     * Creates the SWT controls for the editor.
     * 
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    public void createPartControl(Composite parent) {
        setupDocumentPartitioner();

        super.createPartControl(parent);
        setProjectionSupport(createProjectionSupport());

        // Register the editor selection change listener.
        _fEditorSelectionChangedListener = new EditorSelectionChangedListener();
        _fEditorSelectionChangedListener.install(getSelectionProvider());

        /*
         * Now that we have enabled source folding, make sure everything is expanded.
         */
        ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
        viewer.doOperation(ProjectionViewer.TOGGLE);

        ((TextViewer) this.getSourceViewer()).setDocumentPartitioning(ISQLPartitions.SQL_PARTITIONING);

        getSite().setSelectionProvider((SourceViewer) getSourceViewer());
        hookContextMenu();

        // only when there's control, need we update update outline and annotation
        installSQLUpdater();

        SQLEditorPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(new propertyChangeListener());

        IInformationControlCreator informationControlCreator = new IInformationControlCreator() {
            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, style, null);
            }
        };

        _informationPresenter = new InformationPresenter(informationControlCreator);
        _informationPresenter.setSizeConstraints(60, 10, true, true);
        _informationPresenter.install(getSourceViewer());

        // TODO install EditorSelectionChangedListener to update the Java outline page selection and this editor's range
        // indicator.

        // symbol inserter
        IPreferenceStore preferenceStore = SQLEditorPlugin.getDefault().getPreferenceStore();
        boolean closeSingleQuotes = preferenceStore.getBoolean(PreferenceConstants.SQLEDITOR_CLOSE_SINGLE_QUOTES);
        boolean closeDoubleQuotes = preferenceStore.getBoolean(PreferenceConstants.SQLEDITOR_CLOSE_DOUBLE_QUOTES);
        boolean closeBrackets = preferenceStore.getBoolean(PreferenceConstants.SQLEDITOR_CLOSE_BRACKETS);

        _symbolInserter.setCloseSingleQuotesEnabled(closeSingleQuotes);
        _symbolInserter.setCloseDoubleQuotesEnabled(closeDoubleQuotes);
        _symbolInserter.setCloseBracketsEnabled(closeBrackets);

        ISourceViewer sourceViewer = getSourceViewer();
        if (sourceViewer instanceof ITextViewerExtension)
            ((ITextViewerExtension) sourceViewer).prependVerifyKeyListener(_symbolInserter);

        /* Set a help context ID to enable F1 help. */
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, HELP_CONTEXT_ID);
    }

    public void updatePartControl(IEditorInput input) {
        super.updatePartControl(input);
        refreshActionStatus();
    }

    private void hookContextMenu() {
        StyledText styledText = getSourceViewer().getTextWidget();
        MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);

        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                // editorContextMenuAboutToShow(manager);// Display what comes by default
                SQLEditor.this.fillContextMenu(manager);
            }
        });

        Menu menu = menuMgr.createContextMenu(styledText);
        styledText.setMenu(menu);
        getSite().registerContextMenu(EditorConstants.EDITOR_ID, menuMgr, getSelectionProvider());
    }

    /**
     * Creates, configures, and returns a <code>ProjectionSupport</code> object for this editor.
     * 
     * @return the <code>ProjectSupport</code> object to use with this editor
     */
    protected ProjectionSupport createProjectionSupport() {
        ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
        ProjectionSupport projSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
        projSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$
        projSupport.addSummarizableAnnotationType("org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$
        projSupport.install();

        return projSupport;
    }

    /**
     * Creates the source viewer to be used by this editor.
     * 
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#createSourceViewer(org.eclipse.swt.widgets.Composite,
     *      org.eclipse.jface.text.source.IVerticalRuler, int)
     */
    protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
        fAnnotationAccess = createAnnotationAccess();
        fOverviewRuler = createOverviewRuler(getSharedColors());

        ISourceViewer viewer = doCreateSourceViewer(parent, ruler, styles);
        // ensure decoration support has been created and configured.
        getSourceViewerDecorationSupport(viewer);
        // ensure decoration support has been created and configured.
        getSourceViewerDecorationSupport(viewer);

        // Instantiate and register the matching token painter to source viewer and its text widget.
        _painter = new MatchingPairPainter(viewer, _pairMatcher);
        viewer.getTextWidget().addPaintListener(_painter);
        _painter.setColor(new Color(viewer.getTextWidget().getDisplay(), 192, 192, 192));
        ((AdaptedSourceViewer) viewer).addPainter(_painter);

        return viewer;
    }

    protected AdaptedSourceViewer doCreateSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
        return new AdaptedSourceViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
    }

    /**
     * Creates the source viewer configuation to be used by this editor.
     * 
     * @return the new source viewer configuration object
     */
    protected SQLSourceViewerConfiguration createSourceViewerConfiguration() {
        SQLSourceViewerConfiguration config = SQLEditorContributorExtensionRegistry.getInstance()
                .getSQLSourceViewerConfiguration();
        if (config == null) {
            config = new SQLSourceViewerConfiguration(this);
        } else {
            config.setSQLEditor(this);
        }
        ISQLDBProposalsService proposalsService = getDBProposalsService();
        if (proposalsService != null) {
            config.setDBProposalsService(proposalsService);
        }

        return config;
    }

    /**
     * Dispose of resources held by this editor.
     * 
     * @see IWorkbenchPart#dispose()
     */
    public void dispose() {
        SQLOutlinePage outlinePage = getOutlinePage();
        if (outlinePage != null) {
            outlinePage.setInput(null);
        }

        // Remove the editor change listener.
        if (_fEditorSelectionChangedListener != null) {
            _fEditorSelectionChangedListener.uninstall(getSelectionProvider());
            _fEditorSelectionChangedListener = null;
        }

        // Remove and the matching token painter.
        if (_painter != null) {
            ((AdaptedSourceViewer) getSV()).removePainter(_painter);
            _painter.deactivate(true);
            _painter.dispose();
            _painter = null;
        }

        stopSQLUpdater();
        super.dispose();

        ISourceViewer sourceViewer = getSourceViewer();
        if (sourceViewer instanceof ITextViewerExtension)
            ((ITextViewerExtension) sourceViewer).removeVerifyKeyListener(_symbolInserter);

    }

    /**
     * Gets the multipage editor to which this sql editor belongs
     * 
     * @param editor
     */
    public IEditorPart getParentEditor() {
        return _parentEditor;
    }

    /**
     * Sets the multipage editor to which this sql editor belongs
     * 
     * @param editor
     */
    public void setParentEditor(IEditorPart editor) {
        _parentEditor = editor;
    }

    /**
     * Abandons all modifications applied to this text editor's input element's textual presentation since the last save
     * operation.
     * 
     * @see ITextEditor#doRevertToSaved()
     */
    public void doRevertToSaved() {
        super.doRevertToSaved();
        runUpdater();
    }

    /**
     * Saves the content of this editor.
     * 
     * @param progressMonitor the progress monitor for communicating result state or <code>null</code>
     * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
     */
    public void doSave(IProgressMonitor monitor) {
        super.doSave(monitor);
        runUpdater();
    }

    /**
     * Saves the contents of this editor to another object.
     * 
     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
     */
    public void doSaveAs() {
        ISQLEditorConnectionInfo connInfo = getConnectionInfo();
        super.doSaveAs();
        // now the input should be IFileEditorInput if saveas succeeded
        setConnectionInfo(connInfo);
        setupDocumentPartitioner();
        runUpdater();
    }

    /**
     * Sets the input of the outline page after this class has set input.
     * 
     * @param input the new input for the editor
     * @see org.eclipse.ui.editors.text.TextEditor#doSetInput(org.eclipse.ui.IEditorInput)
     */
    public void doSetInput(IEditorInput input) throws CoreException {
        //bz246180 :Lost line focus after saving
        saveCursorPosition();

        if (_fSQLUpdater != null) {
            _fSQLUpdater.removeMarkers();
            getSourceViewer().getDocument().removeDocumentListener(_fSQLUpdater);
        }

        IDocumentProvider docProvider = this.getDocumentProvider();
        // 209486: Changes in SQL Editor are not saved
        if (input instanceof FileEditorInput
                && (docProvider == null || !(docProvider instanceof FileDocumentProvider))) {
            docProvider = new FileDocumentProvider();
            setDocumentProvider(docProvider);
        }

        super.doSetInput(input);

        /*
         * Make sure the document partitioner is set up. The document setup participant sets up document partitioning,
         * which is used for text colorizing and other text features.
         */
        if (docProvider != null) {
            IDocument doc = docProvider.getDocument(input);
            if (doc != null) {
                SQLEditorDocumentSetupParticipant docSetupParticipant = getDocumentSetupParticipant();
                docSetupParticipant.setup(doc);
            }
        }

        if (input instanceof ISQLEditorInput) {
            ISQLEditorInput sqlEditorInput = (ISQLEditorInput) input;
            SQLDevToolsConfiguration toolsConfig = SQLToolsFacade
                    .getConfigurationByVendorIdentifier(getConnectionInfo().getDatabaseVendorDefinitionId());
            SQLEditorService editorService = toolsConfig.getSQLEditorService();
            fDBProposalsService = editorService.getSQLDBProposalsService(getConnectionInfo());
            if (fDBProposalsService == null) {
                fDBProposalsService = new SQLDBProposalsService(sqlEditorInput.getConnectionInfo());
            }
            SourceViewerConfiguration config = getSourceViewerConfiguration();
            if (config != null && config instanceof SQLSourceViewerConfiguration) {
                SQLSourceViewerConfiguration sqlConfig = (SQLSourceViewerConfiguration) config;
                sqlConfig.setDBProposalsService(fDBProposalsService);
            }
            setupDocumentPartitioner();
            IDocument document = getDocumentProvider().getDocument(input);
            if (_fSQLUpdater != null) {
                document.addDocumentListener(_fSQLUpdater);
                _fSQLUpdater.run();
            }
        }

        /*
         * Show the connection status in the status area at the bottom of the workbench window.
         */
        refreshConnectionStatus();

        //bz246180 :Lost line focus after saving
        tryKeepCursor();
    }

    /**
     * Save cursor line info.
     * BZ246180 :SOE:Lost line focus after saving
     * 
     * @author sul
     */
    private void saveCursorPosition() {
        Point preOffset = null;
        _previousCursorLine = -1;
        if (getSourceViewer() != null) {
            IDocument doc = getSourceViewer().getDocument();
            try {
                preOffset = getSourceViewer().getSelectedRange();
                _previousCursorLine = doc.getLineOfOffset(preOffset.x);
            } catch (BadLocationException bad) {
                preOffset = null;
                _previousCursorLine = -1;
            }
        }
    }

    /**
     * Try to restore the cursor to end of the preCursonLine.
     * BZ246180 :SOE:Lost line focus after saving
     * 
     * @author sul
     */
    private void tryKeepCursor() {
        if (_previousCursorLine >= 0) {
            ISourceViewer viewer = getSourceViewer();
            IDocument newDoc = viewer.getDocument();

            try {
                int newTotalLine = newDoc.getLineOfOffset(newDoc.getLength() - 1);

                if (_previousCursorLine >= newTotalLine) {
                    //locate cursor to the end of document
                    viewer.setRangeIndication(newDoc.getLength(), 0, true);
                } else {
                    //just locate cursor to the end of preCursorLine.
                    IRegion newLine = newDoc.getLineInformation(_previousCursorLine);
                    viewer.setRangeIndication(newLine.getOffset() + newLine.getLength(), 0, true);
                }
            } catch (BadLocationException bad) {
                //if exception is thrown out, set the cursor to the start
                viewer.setRangeIndication(0, 0, true);
            }

        }
    }

    /**
     * Sets up this editor's context menu before it is made visible.
     * 
     * @see org.eclipse.ui.texteditor.AbstractTextEditor#editorContextMenuAboutToShow(org.eclipse.jface.action.IMenuManager)
     */
    protected void editorContextMenuAboutToShow(IMenuManager menu) {
        super.editorContextMenuAboutToShow(menu);
        fillContextMenu(menu);
    }

    /**
     * Fills the context menu with sql editor specific actions. This is different with editorContextMenuAboutToShow in
     * that it does not show the inherited actions.
     * 
     * @param menu
     */
    protected void fillContextMenu(IMenuManager menu) {
        menu.add(new Separator(ITextEditorActionConstants.GROUP_UNDO));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_OPEN));
        menu.add(new Separator(ITextEditorActionConstants.GROUP_COPY));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_SQLEDITOR_SOURCE));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_SQLEDITOR_WIZARD));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_SQLEDITOR_SAVE));
        menu.add(new Separator(ISQLEditorActionConstants.GROUP_SQLEDITOR_ADDITION));
        menu.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));

        if (!isEditorInputReadOnly()) {
            addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.UNDO);
            if (getEditorInput() instanceof IFileEditorInput || getEditorInput() instanceof ILocationProvider) {
                addAction(menu, ITextEditorActionConstants.GROUP_UNDO, ITextEditorActionConstants.REVERT_TO_SAVED);
            }
            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.CUT);
            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.PASTE);
        } else {
            addAction(menu, ITextEditorActionConstants.GROUP_COPY, ITextEditorActionConstants.COPY);
        }
        menu.appendToGroup(ISQLEditorActionConstants.GROUP_SQLEDITOR_SOURCE,
                getAction(ISQLEditorActionConstants.TOGGLE_COMMENT));
        // menu.appendToGroup(ISQLEditorActionConstants.GROUP_SQLEDITOR_SOURCE,
        // getAction(ISQLEditorActionConstants.GOTO_MATCHING_TOKEN_ACTION_ID));

        // menu.add( new Separator() );
        // addAction( menu, "ContentAssistProposal" ); //$NON-NLS-1$
        // addAction( menu, "ContentAssistTip" ); //$NON-NLS-1$
        // addAction( menu, "ContentFormat" ); //$NON-NLS-1$

        menu.add(new Separator());

        // 2006-7-20
        SQLDevToolsUIConfiguration config = SQLToolsUIFacade
                .getConfigurationByVendorIdentifier(getConnectionInfo().getDatabaseVendorDefinitionId());
        ActionService actionService = config.getActionService();
        SQLEditorUIService editorService = config.getSQLEditorUIService();
        // Execute SQL
        if (actionService.supportsAction(ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID)) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE,
                    ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID);
        }
        if (actionService.supportsAction(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID)) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE,
                    ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID);
        }
        if (actionService.supportsAction(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID)) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE,
                    ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID);
        }
        if (actionService.supportsAction(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID)) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE,
                    ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID);
        }

        // Explain SQL
        IPlanOption planOption = config.getPlanService().getPlanOption();
        if (planOption != null && (actionService.supportsAction(ISQLEditorActionConstants.EXPLAIN_SQL_ACTION_ID))) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_EXECUTE,
                    ISQLEditorActionConstants.EXPLAIN_SQL_ACTION_ID);
        }

        addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_SAVE,
                ISQLEditorActionConstants.SAVE_AS_TEMPLATE_ACTION_ID);

        // Edit SQL in DMLdialog
        if (actionService.supportsAction(ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID)) {
            addAction(menu, ISQLEditorActionConstants.GROUP_SQLEDITOR_ADDITION,
                    ISQLEditorActionConstants.DMLDIALOG_SELECTION_SQL_ACTION_ID);
        }

        Collection extensions = SQLEditorPlugin.getSQLEditorActionContributorExtension();
        if (extensions != null) {
            for (Iterator iter = extensions.iterator(); iter.hasNext();) {
                ISQLEditorActionContributorExtension ext = (ISQLEditorActionContributorExtension) iter.next();
                ext.contributeToContextMenu(menu);
            }
        }

        // database specific actions go here
        HashMap dbActions = editorService.getAdditionalActions();
        if (dbActions != null && !dbActions.isEmpty()) {
            MenuManager dbSubMenuMgr = new MenuManager(config.getDatabaseVendorDefinitionId().toString(),
                    ISQLEditorActionConstants.GROUP_SQLEDITOR_DB_SUBMENU); //$NON-NLS-1$
            IActionBars bars = ((IEditorSite) getSite()).getActionBars();
            for (Iterator iter = dbActions.keySet().iterator(); iter.hasNext();) {
                String key = (String) iter.next();
                Object value = dbActions.get(key);
                if (value instanceof Collection) {
                    for (Iterator iterator = ((Collection) value).iterator(); iterator.hasNext();) {
                        addContributedMenus(key, iterator.next(), menu, dbSubMenuMgr);
                    }
                } else {
                    addContributedMenus(key, value, menu, dbSubMenuMgr);
                }
            }
            dbSubMenuMgr.add(new Separator(ITextEditorActionConstants.MB_ADDITIONS));
            menu.appendToGroup(ISQLEditorActionConstants.GROUP_SQLEDITOR_ADDITION, dbSubMenuMgr);
        }

        IAction preferencesAction = getAction(ITextEditorActionConstants.CONTEXT_PREFERENCES);
        menu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS,
                new Separator(ITextEditorActionConstants.GROUP_SETTINGS));
        menu.appendToGroup(ITextEditorActionConstants.GROUP_SETTINGS, preferencesAction);

    }

    private void addContributedMenus(String key, Object dba, IMenuManager manager, MenuManager dbSubMenuMgr) {
        if (dba instanceof IEditorActionDelegate) {
            ((IEditorActionDelegate) dba).setActiveEditor(null, this);
        } else if (dba instanceof TextEditorAction) {
            ((TextEditorAction) dba).setEditor(this);
        }
        // only one level for now
        if (dba instanceof IMenuManager) {
            IContributionItem[] items = ((IMenuManager) dba).getItems();
            for (int i = 0; i < items.length; i++) {
                if (items[i] instanceof IEditorActionDelegate) {
                    ((IEditorActionDelegate) items[i]).setActiveEditor(null, this);
                } else if (items[i] instanceof TextEditorAction) {
                    ((TextEditorAction) items[i]).setEditor(this);
                }
            }
        }
        if (key != null && !key.equals("")) //$NON-NLS-1$
        {
            String subMgrId = key;
            String subGroupId = key;
            if (key.indexOf("/") > 0) //$NON-NLS-1$
            {
                subMgrId = key.substring(0, key.indexOf("/")); //$NON-NLS-1$
                subGroupId = key.substring(key.indexOf("/") + 1); //$NON-NLS-1$
            }
            if (manager.find(subMgrId) != null) {
                IMenuManager subMgr = manager;
                if (manager.find(subMgrId) instanceof IMenuManager) {
                    subMgr = (IMenuManager) manager.find(subMgrId);
                }
                if (subMgr.find(subGroupId) != null) {
                    if (dba instanceof IAction) {
                        subMgr.appendToGroup(subGroupId, (IAction) dba);
                    } else if (dba instanceof IContributionItem) {
                        subMgr.appendToGroup(subGroupId, (IContributionItem) dba);
                    }
                }
            }
            // otherwise ignore
        } else {
            if (dba instanceof IAction) {
                dbSubMenuMgr.add((IAction) dba);
            } else if (dba instanceof IContributionItem) {
                dbSubMenuMgr.add((IContributionItem) dba);
            }
        }
    }

    /**
     * Gets an adapter for the given class. Returns the SQL content outline page if the get request is for an outline
     * page. Otherwise returns a projection adapter if one hasn't already been created.
     * 
     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
     * @see org.eclipse.jface.text.source.projection.ProjectionSupport#getAdapter(org.eclipse.jface.text.source.ISourceViewer,
     *      java.lang.Class)
     */
    public Object getAdapter(Class classForWhichAdapterNeeded) {
        Object adapter = null;

        /* Get and return the content outline page, if that's what's requested. */
        if (IContentOutlinePage.class.equals(classForWhichAdapterNeeded)) {
            if (_fOutlinePage == null) {
                _fOutlinePage = new SQLOutlinePage(this);
                _fOutlineSelectionChangedListener.install(_fOutlinePage);
                installSQLUpdater();
                _fSQLUpdater.setOutlinePage(_fOutlinePage);
            }
            adapter = _fOutlinePage;
        }
        /*
         * This allows consumers to get an instance of SQLEditor via the active editor in a consistent way.
         */
        else if (SQLEditor.class.equals(classForWhichAdapterNeeded)) {
            return this;
        }
        /*
         * Delegate getting the adapter to the projection support object, if there is one. Projection refers to the
         * ability to visibly collapse and expand sections of the document.
         */
        else if (adapter == null) {
            ProjectionSupport projSupport = getProjectionSupport();
            if (projSupport != null) {
                adapter = projSupport.getAdapter(getSourceViewer(), classForWhichAdapterNeeded);
            }
        }

        /* If we still don't have an adapter let the superclass handle it. */
        if (adapter == null) {
            adapter = super.getAdapter(classForWhichAdapterNeeded);
        }

        return adapter;
    }

    /**
     * Gets the connection info object of the editor input of this editor.
     * 
     * @return the current connection info object if the editor has one, otherwise null
     */
    public ISQLEditorConnectionInfo getConnectionInfo() {
        if (getEditorInput() instanceof ISQLEditorInput) {
            return ((ISQLEditorInput) getEditorInput()).getConnectionInfo();
        }
        return SQLEditorConnectionInfo.DEFAULT_SQLEDITOR_CONNECTION_INFO;
    }

    /**
     * Sets the connection info object of the editor input of this editor. Also updates connection related features such
     * as actions, status line, syntax highlighting, and syntax validation, etc.
     * 
     * @param connInfo the new connection info object
     */
    public void setConnectionInfo(ISQLEditorConnectionInfo connInfo) {
        if (getEditorInput() instanceof ISQLEditorInput) {
            ISQLEditorConnectionInfo oldConnInfo = getConnectionInfo();
            ((ISQLEditorInput) getEditorInput()).setConnectionInfo(connInfo);
            fDBProposalsService.setSQLEditorConnectionInfo(connInfo);

            if (connInfo != null && !connInfo.getDatabaseVendorDefinitionId()
                    .equals(oldConnInfo.getDatabaseVendorDefinitionId())) {
                // when the database definition is different, reset the SourceViewer for correct syntax highlight
                ((ISourceViewerExtension2) getSourceViewer()).unconfigure();
                SQLSourceViewerConfiguration configuration = createSourceViewerConfiguration();
                setSourceViewerConfiguration(configuration);
                getSourceViewer().configure(configuration);
                // we have to do this since only configuring the source viewer doesn't work. PresentationReconciler
                // won't get notified of the document changed event.
                setInput(getEditorInput());
                // do it twice because setInput might regenerate an editor input
                ((ISQLEditorInput) getEditorInput()).setConnectionInfo(connInfo);
            }

            SQLEditorPlugin.getDisplay().asyncExec(new Runnable() {
                public void run() {
                    refreshActionStatus();
                    refreshConnectionStatus();
                    _fSQLUpdater.run();
                    fireConnectionProfileAttached();
                }
            });

        }
    }

    /**
     * Requests a connection. Does not guarantee the connection is established. The default implementation does nothing.
     * 
     */
    public void requestConnection() {
        // Do nothing by default
    }

    /**
     * Gets the <code>Database</code> object associated with this input.
     * 
     * @return the <code>Database</code> object associated with this input
     */
    public Database getDatabase() {
        if (getEditorInput() instanceof ISQLEditorInput) {
            return ((ISQLEditorInput) getEditorInput()).getConnectionInfo().getDatabase();
        }
        return null;
    }

    /**
     * Gets the <code>DBProposalsService</code> object that provides content assist services for this editor.
     * 
     * @return the current <code>DBProposalsService</code> object
     */
    public ISQLDBProposalsService getDBProposalsService() {
        return fDBProposalsService;
    }

    /**
     * Gets the default schema name to use with the connection or database associated with this input.
     * 
     * @return the default schema name to use with this input, or null if none
     */
    public String getDefaultSchemaName() {
        if (getEditorInput() instanceof ISQLEditorInput) {
            return ((ISQLEditorInput) getEditorInput()).getConnectionInfo().getDefaultSchemaName();
        }
        return null;
    }

    /**
     * Gets the document setup participant object associated with this editor. The setup participant sets the
     * partitioning type for the document.
     * 
     * @return the current document setup participant
     */
    public SQLEditorDocumentSetupParticipant getDocumentSetupParticipant() {
        if (fDocSetupParticipant == null) {
            fDocSetupParticipant = new SQLEditorDocumentSetupParticipant();
        }
        return fDocSetupParticipant;
    }

    /**
     * Gets the outline page associated with this editor, if there is one.
     * 
     * @return the outline page associated with this editor
     */
    protected SQLOutlinePage getOutlinePage() {
        return _fOutlinePage;
    }

    /**
     * Gets the <code>ProjectionSupport</code> object associated with this editor.
     * 
     * @return the current <code>ProjectionSupport</code> object
     */
    protected ProjectionSupport getProjectionSupport() {
        return fProjectionSupport;
    }

    /**
     * Gets the resource bundle associated with this editor.
     * 
     * @return the resource bundle associated with this editor.
     */
    public ResourceBundle getResourceBundle() {
        return SQLEditorResources.getResourceBundle();
    }

    /**
     * Gets the color provider for colorizing SQL source code.
     * 
     * @return the SQL color provider
     */
    public SQLColorProvider getSQLColorProvider() {
        return SQLEditorPlugin.getDefault().getSQLColorProvider();
    }

    /**
     * Initializes the editor.
     * 
     * @see org.eclipse.ui.editors.text.TextEditor#initializeEditor()
     */
    protected void initializeEditor() {
        super.initializeEditor();
        setDocumentProvider(new SQLStorageDocumentProvider());
        setSourceViewerConfiguration(createSourceViewerConfiguration());
        setRulerContextMenuId("#SQLEditorRulerContext"); //$NON-NLS-1$
        setRangeIndicator(new DefaultRangeIndicator());
        // Sets the SQL editor's help context id.
        // 212003 caution: parameter can't be null
        setHelpContextId(IHelpContextIds.SQLEDITOR);

    }

    /**
     * Handles notifications to the object that a property has changed.
     * 
     * @param event the property change event object describing which property changed and how
     */
    public void propertyChange(PropertyChangeEvent event) {
        if (event.getProperty().equals(SQLConnectAction.CONNECTION)) {
            // TODO refresh db proposal service
            refreshConnectionStatus();
        }
    }

    protected void performSaveAs(IProgressMonitor progressMonitor) {
        // Using the SaveAsDialog defined in common.ui which provide "Create Project" button
        Shell shell = getSite().getShell();
        final IEditorInput input = getEditorInput();

        IDocumentProvider provider = getDocumentProvider();
        final IEditorInput newInput;

        {
            SaveAsDialog dialog = new SaveAsDialog(shell, false);

            IFile original = (input instanceof IFileEditorInput) ? ((IFileEditorInput) input).getFile() : null;
            if (original != null) {
                dialog.setOriginalFile(original);
            }

            dialog.create();

            if (provider.isDeleted(input) && original != null) {
                String message = NLS.bind(SQLEditorResources.SQLEditor_file_deleted_or_not_accessible,
                        original.getName());
                dialog.setErrorMessage(null);
                dialog.setMessage(message, IMessageProvider.WARNING);
            }

            if (dialog.open() == Window.CANCEL) {
                if (progressMonitor != null) {
                    progressMonitor.setCanceled(true);
                }
                return;
            }

            IPath filePath = dialog.getResult();
            if (filePath == null) {
                if (progressMonitor != null) {
                    progressMonitor.setCanceled(true);
                }
                return;
            }

            IWorkspace workspace = ResourcesPlugin.getWorkspace();
            IFile file = workspace.getRoot().getFile(filePath);
            newInput = new FileEditorInput(file);
        }

        if (provider == null) {
            // editor has programmatically been closed while the dialog was open
            return;
        }

        boolean success = false;
        try {

            provider.aboutToChange(newInput);
            provider.saveDocument(progressMonitor, newInput, provider.getDocument(input), true);
            success = true;

        } catch (CoreException x) {
            final IStatus status = x.getStatus();
            if (status == null || status.getSeverity() != IStatus.CANCEL) {
                String title = SQLEditorResources.SQLEditor_problem_save_as;
                String msg = NLS.bind(SQLEditorResources.SQLEditor_could_not_save_as, x.getMessage());
                MessageDialog.openError(shell, title, msg);
            }
        } finally {
            provider.changed(newInput);
            if (success) {
                setInput(newInput);
            }
        }

        if (progressMonitor != null) {
            progressMonitor.setCanceled(!success);
        }

    }

    /**
     * Sets the document setup participant object associated with this editor to the given object. The setup participant
     * sets the partitioning type for the document.
     * 
     * @return the current document setup participant
     */
    public void setDocumentSetupParticipant(SQLEditorDocumentSetupParticipant docSetupParticipant) {
        fDocSetupParticipant = docSetupParticipant;
    }

    /**
     * Asks this part to take focus within the workbench.
     * 
     * @see org.eclipse.ui.IWorkbenchPart#setFocus()
     */
    public void setFocus() {
        super.setFocus();

        /*
         * Make sure the connection status message is up to date. It doesn't automatically get updated if the user
         * switches editor instances.
         */
        refreshConnectionStatus();
    }

    /**
     * Sets the <code>ProjectionSupport</code> object associated with this editor.
     * 
     * @param projSupport the <code>ProjectionSupport</code> object to use
     */
    protected void setProjectionSupport(ProjectionSupport projSupport) {
        fProjectionSupport = projSupport;
    }

    /**
     * Forces the updater to run to update the outline page (if there is one) and syntax markers to reflect the latest
     * changes in the editor.
     */
    protected void runUpdater() {
        if (_fSQLUpdater != null) {
            _fSQLUpdater.run();
        }
    }

    /**
     * Prompts the user to select an existing connection or create a new one. Returns a
     * <code>ISQLEditorConnectionInfo</code> object for the chosen connection.
     * 
     * @return the <code>ISQLEditorConnectionInfo</code> object for the selected connection or null if none selected
     */
    public ISQLEditorConnectionInfo requestConnectionFromUser() {
        // TODO: call "SQL connection" dialog
        return null;
    }

    /**
     * Makes the source viewer public.
     * 
     * @return The source viewer used to create this editor
     */
    public ISourceViewer getSV() {
        return getSourceViewer();
    }

    // ///////////////////Outline and Updater//////////////////////////////////////
    /**
     * Informs the editor that its outliner has been closed.
     */
    public void outlinePageClosed() {
        if (_fOutlinePage != null) {
            _fOutlineSelectionChangedListener.uninstall(_fOutlinePage);
            _fOutlinePage = null;
        }
    }

    private void stopSQLUpdater() {
        try {
            _fSQLUpdater.removeMarkers();
            _fSQLUpdater.setOutlinePage(null);
            if (getSourceViewer().getDocument() != null) {
                getSourceViewer().getDocument().removeDocumentListener(_fSQLUpdater);
            }
            IPreferenceStore preferenceStore = SQLEditorPlugin.getDefault().getPreferenceStore();
            if (preferenceStore != null) {
                preferenceStore.removePropertyChangeListener(_fSQLUpdater);
            }
            getSite().getShell().getDisplay().timerExec(-1, _fSQLUpdater);
        } catch (RuntimeException e) {
            // do nothing
        }
    }

    private void installSQLUpdater() {

        try {
            if (_fSQLUpdater == null) {
                _fSQLUpdater = new SQLUpdater(this);

                getSourceViewer().getDocument().addDocumentListener(_fSQLUpdater);
                IPreferenceStore preferenceStore = SQLEditorPlugin.getDefault().getPreferenceStore();
                if (preferenceStore != null) {
                    preferenceStore.addPropertyChangeListener(_fSQLUpdater);
                }
                _fSQLUpdater.run();
            }
        } catch (Throwable e) {
            // Might caught LookaheadSuccess
            SQLEditorPlugin.getDefault().log(SQLEditorResources.SQLEditor_error_while_trying_to_install_sql_updater,
                    e);
        }
    }

    /**
     * Selects the given node in the editor.
     * 
     * @param node the selected node which contains the text range information
     */
    protected void setSelection(SimpleNode node) {
        ISourceViewer viewer = getSourceViewer();
        if (viewer == null) {
            return;
        }
        StyledText widget = viewer.getTextWidget();
        widget.setRedraw(false);
        if (node != null) {
            int offset = node.getStartOffset(viewer.getDocument());
            int length = node.getEndOffset(viewer.getDocument()) - offset;

            try {
                setHighlightRange(offset, length, true);
            } catch (Exception e) {
                // this can occur as result of a parse error
            }
            viewer.revealRange(offset, length);
            viewer.setSelectedRange(offset, length);
        } else {
            resetHighlightRange();
            viewer.setSelectedRange(widget.getCaretOffset(), 0);
        }
        widget.setRedraw(true);
    }

    /**
     * Returns the parsing result no matter the "Enable syntax validation" is on or off. If this option is on, we will
     * always keep the parsing result up-to-date, if it is off, we will check if the parsing result is kept sync with
     * the editor content, if not, we will parse it to get the synchronized parsing result
     * 
     * @return the recent parsing result since the last modification, may only be null when parser can't be found
     */
    public ParsingResult getParsingResult() {
        /*
         * If the "Enable syntax validation" is turned off and current editor is needed to be parsed again to keep the
         * parsing result in sync with the editor content, then we will parse it
         */
        if (_fSQLUpdater.needToParse()) {
            ISQLEditorConnectionInfo connInfo = getConnectionInfo();
            SQLDevToolsConfiguration conf = SQLToolsFacade.getConfiguration(getDatabaseIdentifier(),
                    connInfo.getDatabaseVendorDefinitionId());
            SQLParser parser = conf.getSQLService().getSQLParser();
            if (parser == null) {
                return null;
            }

            String content = getSourceViewer().getDocument().get();
            // Add '\n' to avoid parser to throw exception when last line is single line comment.
            content = content + "\n"; //$NON-NLS-1$

            boolean useDelimiter = getSQLType() == SQLParserConstants.TYPE_SQL_ROOT;
            _parsingResult = parser.parse(content, new ParserParameters(useDelimiter, getSQLType()));
            _parsingResult.getRootNode().setDocument(getSV().getDocument());
            _fSQLUpdater.setNeedToParse(false);
        }
        return _parsingResult;
    }

    /**
     * @param node the new parsing result
     */
    public void setParsingResult(ParsingResult result) {
        _parsingResult = result;
    }

    // /////////////////////Document Provider////////////////////////////////////////
    /**
     * Sets up the document partitioner. Since we support multiple dialects, each time when the database vendor
     * definition for this SQL editor is changed, this method should be called to update the document partitioner.
     */
    protected void setupDocumentPartitioner() {
        IDocument document = getDocumentProvider().getDocument(getEditorInput());
        DatabaseVendorDefinitionId vendorId = getConnectionInfo().getDatabaseVendorDefinitionId();

        SQLDevToolsConfiguration factory = SQLToolsFacade.getConfigurationByVendorIdentifier(vendorId);
        SQLPartitionScanner _sqlPartitionSanner = new SQLPartitionScanner(factory.getSQLService().getSQLSyntax());
        if (document instanceof IDocumentExtension3) {
            IDocumentExtension3 extension3 = (IDocumentExtension3) document;

            IDocumentPartitioner partitioner = new FastPartitioner(_sqlPartitionSanner,
                    new String[] { SQLPartitionScanner.SQL_COMMENT, SQLPartitionScanner.SQL_MULTILINE_COMMENT,
                            SQLPartitionScanner.SQL_STRING, SQLPartitionScanner.SQL_DOUBLE_QUOTES_IDENTIFIER });
            partitioner.connect(document);
            extension3.setDocumentPartitioner(SQLPartitionScanner.SQL_PARTITIONING, partitioner);

        }
    }

    // /////////////////////Action and Status line status/////////////////////////////////////
    /**
     * Refreshes the actions
     */
    protected void refreshActionStatus() {
        List actionList = new ArrayList();
        IAction action = getAction(ISQLEditorActionConstants.EXECUTE_SELECTION_SQL_ACTION_ID);
        if (action != null) {
            actionList.add(action);
        }
        action = getAction(ISQLEditorActionConstants.EXECUTE_SQL_ACTION_ID);
        if (action != null) {
            actionList.add(action);
        }
        action = getAction(ISQLEditorActionConstants.EXECUTE_SQL_AS_ONE_STATEMENT_ACTION_ID);
        if (action != null) {
            actionList.add(action);
        }
        action = getAction(ISQLEditorActionConstants.EXECUTE_CURRENT_SQL_ACTION_ID);
        if (action != null) {
            actionList.add(action);
        }
        // TODO notify ISQLEditorActionContributorExtension
        Collection extensions = SQLEditorPlugin.getSQLEditorActionContributorExtension();
        if (extensions != null) {
            for (Iterator iter = extensions.iterator(); iter.hasNext();) {
                ISQLEditorActionContributorExtension ext = (ISQLEditorActionContributorExtension) iter.next();
                ext.updateAction();
            }
        }

        Iterator iterator = actionList.iterator();
        while (iterator.hasNext()) {
            IUpdate textEditorAction = (IUpdate) iterator.next();
            if (textEditorAction != null) {
                textEditorAction.update();
            }
        }

    }

    /**
     * Refreshes the status area indicating the connection state.
     */
    public void refreshConnectionStatus() {
        IEditorSite editorSite = getEditorSite();
        if (editorSite != null) {
            IActionBars actionBars = editorSite.getActionBars();
            if (actionBars != null) {
                IStatusLineManager statusLineMgr = actionBars.getStatusLineManager();
                ISQLEditorConnectionInfo connInfo = getConnectionInfo();
                if (connInfo != null) {
                    statusLineMgr.setErrorMessage(null);
                    String connStatus = connInfo.getName();
                    statusLineMgr.setMessage(connStatus);
                } else {
                    String connStatus = SQLEditorResources.SQLEditor_connection_status_noConnection;
                    statusLineMgr.setErrorMessage(connStatus);
                }
                actionBars.updateActionBars();
            }
        }
    }

    // ////////////////////Utility methods///////////////////////////////////
    /**
     * Returns the complete text in this editor.
     * 
     * @return the complete text.
     */
    public String getText() {
        IDocument document = getDocumentProvider().getDocument(getEditorInput());
        return document.get();
    }

    /**
     * Returns the selected text.
     */
    public String getSelectedText() {
        String sql = null;
        if (getSelectionProvider() == null) {
            return null;
        }
        // get the selection
        ITextSelection selection = (ITextSelection) getSelectionProvider().getSelection();
        if (!selection.isEmpty() && selection.getText() != null && !selection.getText().equals("")) //$NON-NLS-1$
        {
            sql = selection.getText();
        }
        return sql;
    }

    /**
     * @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#initializeKeyBindingScopes()
     */
    protected void initializeKeyBindingScopes() {
        setKeyBindingScopes(new String[] { "org.eclipse.datatools.sqltools.SQLEditorScope" //$NON-NLS-1$
        }); //$NON-NLS-1$
    }

    /*
     * @see org.eclipse.ui.part.WorkbenchPart#getOrientation()
     * @since 3.1
     */
    public int getOrientation() {
        return SWT.LEFT_TO_RIGHT; // SQL editors are always left to right by default
    }

    /**
     * 
     * @return the selected text or the whole text when there's no selection
     */
    public String getTargetText() {
        String sql = getSelectedText();
        if (sql == null) {
            // get the document
            IDocument document = getDocumentProvider().getDocument(getEditorInput());
            sql = document.get();
        }
        return sql;
    }

    /**
     * Configures the toggle comment action
     * 
     */
    private void configureToggleCommentAction(IAction action) {
        if (action instanceof ToggleCommentAction) {
            ISourceViewer sourceViewer = getSourceViewer();
            SourceViewerConfiguration configuration = getSourceViewerConfiguration();
            ((ToggleCommentAction) action).configure(sourceViewer, configuration);
        }
    }

    //
    protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
        try {
            if (getSourceViewer() != null) {

                String p = event.getProperty();
                IPreferenceStore preferenceStore = SQLEditorPlugin.getDefault().getPreferenceStore();
                if (PreferenceConstants.SQLEDITOR_CLOSE_SINGLE_QUOTES.equals(p)) {
                    _symbolInserter.setCloseSingleQuotesEnabled(preferenceStore.getBoolean(p));
                    return;
                }
                if (PreferenceConstants.SQLEDITOR_CLOSE_DOUBLE_QUOTES.equals(p)) {
                    _symbolInserter.setCloseDoubleQuotesEnabled(preferenceStore.getBoolean(p));
                    return;
                }
                if (PreferenceConstants.SQLEDITOR_CLOSE_BRACKETS.equals(p)) {
                    _symbolInserter.setCloseBracketsEnabled(preferenceStore.getBoolean(p));
                    return;
                }
                // when user enbale "syntax validation", we update/recreate the parsing result for SQLEditor
                if (PreferenceConstants.SYNTAX_VALIDATION.equals(p)) {
                    if (_fSQLUpdater != null) {
                        _fSQLUpdater.run();
                    }
                    return;
                }
            }

        } finally {
            super.handlePreferenceStoreChanged(event);
        }
    }

    /**
     * Returns the outmost sql statement type that's allowed in this editor. The default sqlType is
     * SQLParserConstants.TYPE_SQL_ROOT, which means any sql statements can occur.
     * 
     * @return
     */
    public int getSQLType() {
        return SQLParserConstants.TYPE_SQL_ROOT;
    }

    public void addConnectionProfileAttachListener(IConnectionProfileAttachListener listener) {
        if (!_profileListeners.contains(listener)) {
            _profileListeners.add(listener);
        }
    }

    public void removeConnectionProfileAttachListener(IConnectionProfileAttachListener listener) {
        _profileListeners.remove(listener);
    }

    public void fireConnectionProfileAttached() {
        for (Iterator iter = _profileListeners.iterator(); iter.hasNext();) {
            IConnectionProfileAttachListener l = (IConnectionProfileAttachListener) iter.next();
            l.connectionProfileAttached(this);
        }
    }

    /**
     * Returns the DatabaseIdentifier associated with the connection info.
     * 
     * @return might be null
     */
    public DatabaseIdentifier getDatabaseIdentifier() {
        ISQLEditorConnectionInfo connInfo = getConnectionInfo();
        if (connInfo != null && connInfo.getConnectionProfileName() != null) {
            return new DatabaseIdentifier(connInfo.getConnectionProfileName(), connInfo.getDatabaseName());
        }
        return null;
    }

    public String getDBType() {
        return getConnectionInfo().getDatabaseVendorDefinitionId().toString();
    }

    /**
     * Insert the SQL text into editor
     * 
     * @param sqlText
     */
    public void insert(String sqlText) {
        // get the document
        IDocument document = getDocumentProvider().getDocument(getEditorInput());

        // get the selection
        ITextSelection selection = (ITextSelection) getSelectionProvider().getSelection();
        int start = 0;
        int length = 0;

        // get the offset of the selection
        if (!selection.isEmpty()) {
            start = selection.getOffset();
            length = selection.getLength();
            if (length < 0) {
                length = -length;
                start -= length;
            }
        }

        // replace/insert
        try {
            document.replace(start, length, sqlText);
        } catch (BadLocationException e) {
            IEditorSite editorSite = getEditorSite();
            if (editorSite != null) {
                IActionBars actionBars = editorSite.getActionBars();
                if (actionBars != null) {
                    IStatusLineManager statusLineMgr = actionBars.getStatusLineManager();
                    statusLineMgr.setErrorMessage(e.getLocalizedMessage());
                }
            }
            SQLEditorPlugin.getDefault().log(e);
        }
    }

    /**
     * Utility methods to "getConnectionInfo().isConnected()"
     * 
     * @return
     */
    public boolean isConnected() {
        return getConnectionInfo().isConnected();
    }

    protected String[] collectContextMenuPreferencePages() {
        String[] parent = super.collectContextMenuPreferencePages();
        String[] prefs = new String[parent.length + 1];
        System.arraycopy(parent, 0, prefs, 1, parent.length);
        prefs[0] = "org.eclipse.datatools.sqltools.sqleditor.preferences.SQLEditor";
        return prefs;
    }

    /**
     * Going to matching token.
     */
    public void gotoMatchingToken() {
        ISourceViewer sourceViewer = getSourceViewer();
        IDocument document = sourceViewer.getDocument();
        IRegion selection = getSignedSelection(sourceViewer);

        IRegion region = _pairMatcher.match(document, selection.getOffset());

        if (region == null) {
            return;
        }

        int offset = selection.getOffset();

        if (_pairMatcher.getAnchor() == ICharacterPairMatcher.RIGHT) {
            offset = region.getOffset() + ((AbstractPairMatcher) _pairMatcher).getMatchingTokenLength();
        } else if (_pairMatcher.getAnchor() == ICharacterPairMatcher.LEFT) {
            offset = region.getOffset() + region.getLength();
        }

        sourceViewer.setSelectedRange(offset, 0);
        sourceViewer.revealRange(offset, 0);
    }

    /**
     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#getSignedSelection(ISourceViewer sourceViewer)
     */
    protected IRegion getSignedSelection(ISourceViewer sourceViewer) {
        StyledText text = sourceViewer.getTextWidget();
        Point selection = text.getSelectionRange();

        if (text.getCaretOffset() == selection.x) {
            selection.x = selection.x + selection.y;
            selection.y = -selection.y;
        }

        selection.x = widgetOffset2ModelOffset(sourceViewer, selection.x);

        return new Region(selection.x, selection.y);
    }

    protected ICharacterPairMatcher getPairMatcher() {
        return _pairMatcher;
    }

    protected void setPairMatcher(ICharacterPairMatcher matcher) {
        if (matcher instanceof AbstractPairMatcher) {
            AbstractPairMatcher pairMatcher = (AbstractPairMatcher) matcher;

            pairMatcher.setSQLEditor(this);

            _pairMatcher = pairMatcher;

            _painter.setFPairMatcher(pairMatcher);
        }
    }

} // end class