com.aptana.snippets.ui.views.SnippetPopupDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.aptana.snippets.ui.views.SnippetPopupDialog.java

Source

/**
 * Aptana Studio
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
 * Please see the license.html included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
package com.aptana.snippets.ui.views;

import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;

import com.aptana.core.logging.IdeLog;
import com.aptana.core.util.ArrayUtil;
import com.aptana.core.util.StringUtil;
import com.aptana.editor.common.AbstractThemeableEditor;
import com.aptana.editor.common.CommonEditorPlugin;
import com.aptana.editor.common.ExtendedFastPartitioner;
import com.aptana.editor.common.IExtendedPartitioner;
import com.aptana.editor.common.IPartitioningConfiguration;
import com.aptana.editor.common.NullPartitionerSwitchStrategy;
import com.aptana.editor.common.scripting.QualifiedContentType;
import com.aptana.editor.common.scripting.snippets.SnippetTemplateUtil;
import com.aptana.editor.common.text.rules.CompositePartitionScanner;
import com.aptana.editor.common.text.rules.NullSubPartitionScanner;
import com.aptana.editor.common.util.EditorUtil;
import com.aptana.formatter.IScriptFormatterFactory;
import com.aptana.formatter.ScriptFormatterManager;
import com.aptana.formatter.preferences.profile.IProfileManager;
import com.aptana.formatter.preferences.profile.ProfileManager;
import com.aptana.formatter.ui.preferences.FormatterPreviewUtils;
import com.aptana.formatter.ui.preferences.ScriptSourcePreviewerUpdater;
import com.aptana.scripting.model.BundleElement;
import com.aptana.scripting.model.BundleManager;
import com.aptana.scripting.model.BundlePrecedence;
import com.aptana.scripting.model.SnippetElement;
import com.aptana.scripting.model.TriggerType;
import com.aptana.scripting.ui.ScriptingUIPlugin;
import com.aptana.theme.ColorManager;
import com.aptana.theme.Theme;
import com.aptana.theme.ThemePlugin;
import com.aptana.ui.util.UIUtils;
import com.aptana.workbench.commands.EditBundleJob;

/**
 * PopupDialog that displays the contents of a snippets, formatted and colored based on the preferences
 * 
 * @author nle
 */
public class SnippetPopupDialog extends PopupDialog {
    private static final String SNIPPETS_POPUP_SETTINGS = "snippets.popup.settings"; //$NON-NLS-1$
    private ToolBar toolbar;
    private Control positionTarget;
    private List<Image> toolbarImages = new ArrayList<Image>();
    private SnippetElement snippet;
    private ColorManager colorManager;
    private Point popupSize = null;
    private String tabChar;

    /**
     * The pixel offset of the popup from the bottom corner of the control.
     */
    private static final int POPUP_OFFSET = 3;

    /**
     * Indicates that a chosen proposal should be inserted into the field.
     */
    public static final int PROPOSAL_INSERT = 1;
    private QualifiedContentType translatedQualifiedType;
    private Composite toolbarComp;
    private ISourceViewer snippetViewer;
    private Composite mainComp;
    private Composite snippetComp;

    public SnippetPopupDialog(Shell shell, SnippetElement snippet, Control positionTarget) {
        super(shell, PopupDialog.INFOPOPUP_SHELLSTYLE, true, true, false, false, false, snippet.getDisplayName(),
                null);
        this.positionTarget = positionTarget;
        this.snippet = snippet;
        colorManager = new ColorManager();
        tabChar = Platform.getOS().equals(Platform.OS_MACOSX) ? "\u21E5" : "\u00bb"; //$NON-NLS-1$ //$NON-NLS-2$ 
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#createContents(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createContents(Composite parent) {
        Composite composite = new Composite(parent, SWT.BORDER);
        composite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
        composite.setLayout(GridLayoutFactory.fillDefaults().create());

        return super.createContents(composite);
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        mainComp = (Composite) super.createDialogArea(parent);

        snippetComp = new Composite(mainComp, SWT.NONE);
        snippetComp.setLayout(new FillLayout());
        snippetComp.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());

        snippetViewer = createSnippetViewer(snippetComp);

        Label separator = new Label(mainComp, SWT.HORIZONTAL | SWT.SEPARATOR);
        separator.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());

        toolbarComp = new Composite(mainComp, SWT.NONE);
        toolbarComp.setBackground(null);
        toolbarComp.setLayout(GridLayoutFactory.fillDefaults().margins(2, 2).create());
        toolbarComp.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());

        toolbar = new ToolBar(toolbarComp, SWT.HORIZONTAL);
        toolbar.setBackground(null);
        toolbar.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());

        ToolItem openSnippetItem = new ToolItem(toolbar, SWT.PUSH);
        Image navigateImage = ScriptingUIPlugin.getImageDescriptor("/icons/full/elcl16/nav_snippet_tsk.png") //$NON-NLS-1$
                .createImage();
        toolbarImages.add(navigateImage);
        openSnippetItem.setImage(navigateImage);
        openSnippetItem.setToolTipText(Messages.SnippetPopupDialog_Open_Snippet_Source_desc);
        openSnippetItem.addSelectionListener(new SelectionAdapter() {
            /*
             * (non-Javadoc)
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                // We have to create it if it's still pre-packaged
                final BundleElement bundle = snippet.getOwningBundle();
                BundlePrecedence bundlePrecedence = bundle.getBundlePrecedence();
                if (bundlePrecedence != BundlePrecedence.PROJECT && bundlePrecedence != BundlePrecedence.USER) {
                    final EditBundleJob job = new EditBundleJob(bundle);
                    job.addJobChangeListener(new JobChangeAdapter() {
                        public void done(IJobChangeEvent event) {
                            openBundleSnippet(bundle);
                        }
                    });

                    job.schedule();
                } else {
                    openBundleSnippet(bundle);
                }

                close();
            }

            private void openBundleSnippet(BundleElement bundle) {
                String path = snippet.getPath();
                List<SnippetElement> bundleSnippets = BundleManager.getInstance()
                        .getBundleSnippets(bundle.getDisplayName());
                for (SnippetElement element : bundleSnippets) {
                    if (element.getDisplayName().equals(snippet.getDisplayName())
                            && element.getExpansion().equals(snippet.getExpansion())) {
                        path = element.getPath();
                        break;
                    }
                }

                final File file = new File(path);
                Display.getDefault().asyncExec(new Runnable() {

                    public void run() {
                        IFile[] foundFiles = ResourcesPlugin.getWorkspace().getRoot()
                                .findFilesForLocationURI(file.toURI());
                        if (!ArrayUtil.isEmpty(foundFiles)) {
                            EditorUtil.openInEditor(new File(foundFiles[0].getLocationURI()));
                        } else if (file.exists()) {
                            EditorUtil.openInEditor(file);
                        }
                    }
                });

            }
        });

        return mainComp;
    }

    @Override
    protected Control createTitleControl(Composite parent) {
        Control control = super.createTitleControl(parent);

        Label subText = new Label(parent, SWT.WRAP);
        String[] prefixes = snippet.getTriggerTypeValues(TriggerType.PREFIX);
        String[] formattedPrefixes = new String[prefixes.length];
        for (int i = 0; i < formattedPrefixes.length; i++) {
            formattedPrefixes[i] = MessageFormat.format("{0}{1}", prefixes[i], tabChar); //$NON-NLS-1$
        }

        String scopeString = snippet.getScope();
        if (scopeString == null) {
            scopeString = Messages.SnippetPopupDialog_Scope_None;
        }

        subText.setText(MessageFormat.format(Messages.SnippetPopupDialog_Desciption, scopeString,
                StringUtil.join(",", formattedPrefixes))); //$NON-NLS-1$
        subText.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).create());

        return control;
    }

    private ColorManager getColorManager() {
        return ThemePlugin.getDefault().getColorManager();
    }

    private Theme getCurrentTheme() {
        return ThemePlugin.getDefault().getThemeManager().getCurrentTheme();
    }

    @Override
    protected Color getBackground() {
        return getColorManager().getColor(getCurrentTheme().getBackground());

    }

    @Override
    protected Color getForeground() {
        return getColorManager().getColor(getCurrentTheme().getForeground());
    }

    @Override
    protected List getBackgroundColorExclusions() {
        List exclusions = super.getBackgroundColorExclusions();
        exclusions.add(toolbar);
        exclusions.add(toolbarComp);
        exclusions.add(mainComp);
        exclusions.add(snippetComp);
        return exclusions;
    }

    private ISourceViewer createSnippetViewer(Composite parent) {
        ProjectionViewer viewer = new ProjectionViewer(parent, null, null, false, SWT.V_SCROLL | SWT.H_SCROLL);
        StyledText styledText = viewer.getTextWidget();
        styledText.setFont(JFaceResources.getTextFont());

        IScriptFormatterFactory factory = null;
        String contentType = getContentType();

        if (contentType != null) {
            factory = ScriptFormatterManager.getSelected(contentType);
        }

        IPreferenceStore generalTextStore = EditorsUI.getPreferenceStore();
        // TODO - Note that we pass the factory's preferences store and not calling to this.getPrefereceStore.
        // In case we decide to unify the preferences into the this plugin, we might need to change this.

        if (factory != null) {
            IPreferenceStore store = new ChainedPreferenceStore(
                    new IPreferenceStore[] { factory.getPreferenceStore(), generalTextStore });

            SourceViewerConfiguration configuration = (SourceViewerConfiguration) factory
                    .createSimpleSourceViewerConfiguration(colorManager, store, null, false);
            viewer.configure(configuration);
            new ScriptSourcePreviewerUpdater(viewer, configuration, store);
        }

        if (viewer.getTextWidget().getTabs() == 0) {
            viewer.getTextWidget().setTabs(4);
        }
        viewer.getTextWidget().setEnabled(false);

        viewer.setEditable(false);
        IDocument document = new Document();
        viewer.setDocument(document);

        String expansion = snippet.getExpansion();

        if (expansion != null) {
            expansion = SnippetTemplateUtil.evaluateSnippet(snippet, document, new Position(0));
        }

        if (factory != null) {
            IPartitioningConfiguration partitioningConfiguration = (IPartitioningConfiguration) factory
                    .getPartitioningConfiguration();
            CompositePartitionScanner partitionScanner = new CompositePartitionScanner(
                    partitioningConfiguration.createSubPartitionScanner(), new NullSubPartitionScanner(),
                    new NullPartitionerSwitchStrategy());
            IDocumentPartitioner partitioner = new ExtendedFastPartitioner(partitionScanner,
                    partitioningConfiguration.getContentTypes());
            partitionScanner.setPartitioner((IExtendedPartitioner) partitioner);
            partitioner.connect(document);
            document.setDocumentPartitioner(partitioner);

            IProfileManager manager = ProfileManager.getInstance();
            IResource selectedResource = UIUtils.getSelectedResource();
            IProject project = null;

            if (selectedResource == null) {
                IEditorPart activeEditor = UIUtils.getActiveEditor();
                if (activeEditor instanceof AbstractThemeableEditor) {
                    project = EditorUtil.getProject((AbstractThemeableEditor) activeEditor);
                }
            } else {
                project = selectedResource.getProject();
            }

            if (project != null) {
                FormatterPreviewUtils.updatePreview(viewer, expansion, null, factory,
                        manager.getSelected(project).getSettings());
            } else {
                document.set(expansion);
            }
        } else {
            document.set(expansion);
        }

        if (translatedQualifiedType != null) {
            for (String part : translatedQualifiedType.getParts()) {
                viewer.removeTextHovers(part);
            }
        }
        return viewer;
    }

    private String getContentType() {
        IEditorPart activeEditor = UIUtils.getActiveEditor();
        if (activeEditor instanceof AbstractThemeableEditor) {
            AbstractThemeableEditor abstractThemeableEditor = (AbstractThemeableEditor) activeEditor;

            ISourceViewer sourceViewer = abstractThemeableEditor.getISourceViewer();
            if (sourceViewer != null) {
                IDocument document = sourceViewer.getDocument();
                int caretOffset = abstractThemeableEditor.getCaretOffset();
                try {

                    translatedQualifiedType = CommonEditorPlugin.getDefault().getDocumentScopeManager()
                            .getContentType(document, caretOffset);
                    if (translatedQualifiedType != null) {
                        return extractContentType(translatedQualifiedType);
                    }
                } catch (BadLocationException e) {
                    IdeLog.logError(ScriptingUIPlugin.getDefault(),
                            MessageFormat.format("Caret offset {0} was out of bounds with a max of {1} for {2}", //$NON-NLS-1$
                                    caretOffset, document.get().length(),
                                    abstractThemeableEditor.getPartName()),
                            com.aptana.editor.common.IDebugScopes.PRESENTATION);
                }
            }
        }

        return null;
    }

    protected String extractContentType(QualifiedContentType qualifiedContentType) {
        if (qualifiedContentType == null) {
            return null;
        }
        int partCount = qualifiedContentType.getPartCount();
        if (partCount > 2) {
            return qualifiedContentType.getParts()[partCount - 2];
        }
        return qualifiedContentType.getParts()[0];
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#getDialogSettings()
     */
    @Override
    protected IDialogSettings getDialogSettings() {
        IDialogSettings dialogSettings = ScriptingUIPlugin.getDefault().getDialogSettings();
        if (dialogSettings != null) {
            IDialogSettings section = dialogSettings.getSection(SNIPPETS_POPUP_SETTINGS);
            if (section == null) {
                section = dialogSettings.addNewSection(SNIPPETS_POPUP_SETTINGS);
            }

            return section;
        }

        return null;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#close()
     */
    @Override
    public boolean close() {
        boolean willClose = super.close();
        if (willClose) {
            for (Image image : toolbarImages) {
                image.dispose();
            }
            colorManager.dispose();
        }

        return willClose;
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog.adjustBounds()
     */
    protected void adjustBounds() {
        // Get our control's location in display coordinates.
        Point location = positionTarget.getDisplay().map(positionTarget.getParent(), null,
                positionTarget.getLocation());
        Point targetSize = positionTarget.getSize();
        Point sizeSize = UIUtils.getActiveWorkbenchWindow().getShell().getSize();
        int initialX = location.x + targetSize.x;
        int initialY = location.y + POPUP_OFFSET;

        if (popupSize == null) {
            getShell().pack();
            popupSize = getShell().getSize();
            if (popupSize.x > 500) {
                popupSize.x = 500;
            }

            if (popupSize.y > sizeSize.y) {
                popupSize.y = sizeSize.y;
            }

            // On OSX, compensate for the always visible horizontal scroll bar
            if (Platform.OS_MACOSX.equals(Platform.getOS())) {
                ScrollBar horizontalBar = snippetViewer.getTextWidget().getHorizontalBar();
                if (horizontalBar != null) {
                    int height = horizontalBar.getSize().y;
                    popupSize.y += height;
                }

                ScrollBar verticalBar = snippetViewer.getTextWidget().getVerticalBar();
                if (verticalBar != null) {
                    int width = verticalBar.getSize().x;
                    popupSize.x += width;
                }
            }
        }

        // Constrain to the display
        Rectangle constrainedBounds = getConstrainedShellBounds(
                new Rectangle(initialX, initialY, popupSize.x, popupSize.y));

        // If there has been an adjustment causing the popup to overlap
        // with the control, then put the popup above the control.
        if (constrainedBounds.y < initialY) {
            getShell().setBounds(initialX, location.y - popupSize.y, popupSize.x, popupSize.y);
        } else {
            getShell().setBounds(initialX, initialY, popupSize.x, popupSize.y);
        }
    }

    /*
     * (non-Javadoc)
     * @see org.eclipse.jface.dialogs.PopupDialog#getFocusControl()
     */
    @Override
    protected Control getFocusControl() {
        snippetViewer.getTextWidget().setEnabled(true);
        return getContents();
    }

}