com.liferay.ide.xml.search.ui.editor.LiferayCustomXmlHoverControl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.ide.xml.search.ui.editor.LiferayCustomXmlHoverControl.java

Source

/*******************************************************************************
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *******************************************************************************/

package com.liferay.ide.xml.search.ui.editor;

import com.liferay.ide.xml.search.ui.TempMarker;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.internal.text.html.HTMLTextPresenter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.AbstractInformationControl;
import org.eclipse.jface.text.DefaultInformationControl.IInformationPresenterExtension;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IInformationControlExtension2;
import org.eclipse.jface.text.IInformationControlExtension3;
import org.eclipse.jface.text.IInformationControlExtension5;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.IRewriteTarget;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.ITextViewerExtension;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.IMarkerResolution2;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;

/**
 * @author Kuo Zhang
 * @see org.eclipse.m2e.editor.xml.internal.MarkerHoverControl.
 */
@SuppressWarnings("restriction")
public class LiferayCustomXmlHoverControl extends AbstractInformationControl
        implements IInformationControlExtension2, IInformationControlExtension3, IInformationControlExtension5 {

    private static final String ONE_QUICK_FIX = "1 quick fix available:";
    private static final String MULTIPLE_QUICK_FIXES = "{0} quick fixes available:";

    private CompoundRegion region;
    private Control focusControl;
    private Composite parent;
    private final DefaultMarkerAnnotationAccess markerAccess;

    public LiferayCustomXmlHoverControl(Shell shell) {
        super(shell, EditorsUI.getTooltipAffordanceString());
        markerAccess = new DefaultMarkerAnnotationAccess();
        create();
    }

    private void apply(ICompletionProposal p, ITextViewer viewer, int offset, boolean isMultiFix) {
        // Focus needs to be in the text viewer, otherwise linked mode does not work
        dispose();

        IRewriteTarget target = null;
        try {
            IDocument document = viewer.getDocument();

            if (viewer instanceof ITextViewerExtension) {
                ITextViewerExtension extension = (ITextViewerExtension) viewer;
                target = extension.getRewriteTarget();
            }

            if (target != null) {
                target.beginCompoundChange();
            }

            if (p instanceof ICompletionProposalExtension2) {
                ICompletionProposalExtension2 e = (ICompletionProposalExtension2) p;
                e.apply(viewer, (char) 0, isMultiFix ? SWT.CONTROL : SWT.NONE, offset);
            } else if (p instanceof ICompletionProposalExtension) {
                ICompletionProposalExtension e = (ICompletionProposalExtension) p;
                e.apply(document, (char) 0, offset);
            } else {
                p.apply(document);
            }

            Point selection = p.getSelection(document);

            if (selection != null) {
                viewer.setSelectedRange(selection.x, selection.y);
                viewer.revealRange(selection.x, selection.y);
            }
        } catch (Exception e) {
        } finally {
            if (target != null) {
                target.endCompoundChange();
            }
        }
    }

    private void apply(IMarkerResolution res, IMarker mark, ITextViewer viewer, int offset) {
        if (res instanceof ICompletionProposal) {
            apply((ICompletionProposal) res, viewer, offset, false);
        } else {
            dispose();
            res.run(mark);
        }
    }

    public Point computeSizeHint() {
        Point preferedSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);

        Point constrains = getSizeConstraints();

        if (constrains == null) {
            return preferedSize;
        }

        Point constrainedSize = getShell().computeSize(constrains.x, SWT.DEFAULT, true);

        int width = Math.min(preferedSize.x, constrainedSize.x);
        int height = Math.max(preferedSize.y, constrainedSize.y);

        return new Point(width, height);
    }

    private void createAnnotationInformation(Composite parent, final Annotation annotation) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        GridLayout layout = new GridLayout(2, false);
        layout.marginHeight = 2;
        layout.marginWidth = 2;
        layout.horizontalSpacing = 0;
        composite.setLayout(layout);

        // this paints the icon..
        final Canvas canvas = new Canvas(composite, SWT.NO_FOCUS);
        GridData gridData = new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false);
        gridData.widthHint = 17;
        gridData.heightHint = 16;
        canvas.setLayoutData(gridData);

        canvas.addPaintListener(new PaintListener() {
            public void paintControl(PaintEvent e) {
                e.gc.setFont(null);
                markerAccess.paint(annotation, e.gc, canvas, new Rectangle(0, 0, 16, 16));
            }
        });

        // and now comes the text
        StyledText text = new StyledText(composite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        text.setLayoutData(data);
        String annotationText = annotation.getText();

        if (annotationText != null) {
            text.setText(annotationText);
        }
    }

    private Link createCompletionProposalLink(Composite parent, final IMarker mark,
            final IMarkerResolution proposal, int count) {
        final boolean isMultiFix = count > 1;

        if (isMultiFix) {
            new Label(parent, SWT.NONE); // spacer to fill image cell
            parent = new Composite(parent, SWT.NONE); // indented composite for multi-fix
            GridLayout layout = new GridLayout(2, false);
            layout.marginWidth = 0;
            layout.marginHeight = 0;
            parent.setLayout(layout);
        }

        Label proposalImage = new Label(parent, SWT.NONE);
        proposalImage.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, false));
        Image image = null;

        if (proposal instanceof ICompletionProposal) {
            image = ((ICompletionProposal) proposal).getImage();
        } else if (proposal instanceof IMarkerResolution2) {
            image = ((IMarkerResolution2) proposal).getImage();
        }
        if (image != null) {
            proposalImage.setImage(image);

            proposalImage.addMouseListener(new MouseAdapter() {
                public void mouseUp(MouseEvent e) {
                    if (e.button == 1) {
                        apply(proposal, mark, region.textViewer, region.textOffset);
                    }
                }
            });
        }

        Link proposalLink = new Link(parent, SWT.WRAP);
        GridData layoutData = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
        String linkText = proposal.getLabel();

        proposalLink.setText("<a>" + linkText + "</a>");
        proposalLink.setLayoutData(layoutData);

        proposalLink.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                apply(proposal, mark, region.textViewer, region.textOffset);
            }
        });

        return proposalLink;
    }

    protected void createContent(Composite parent) {
        this.parent = parent;
        GridLayout layout = new GridLayout(1, false);
        layout.verticalSpacing = 0;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        parent.setLayout(layout);
    }

    private void createResolutionsControl(Composite parent, IMarker marker, IMarkerResolution[] resolutions) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout layout = new GridLayout(1, false);
        layout.marginWidth = 0;
        layout.verticalSpacing = 2;
        layout.marginHeight = 0;
        composite.setLayout(layout);

        Label quickFixLabel = new Label(composite, SWT.NONE);
        GridData layoutData = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
        layoutData.horizontalIndent = 4;
        quickFixLabel.setLayoutData(layoutData);
        String text;

        if (resolutions.length == 1) {
            text = ONE_QUICK_FIX;
        } else {
            text = NLS.bind(MULTIPLE_QUICK_FIXES, String.valueOf(resolutions.length));
        }

        quickFixLabel.setText(text);

        Composite composite2 = new Composite(parent, SWT.NONE);
        composite2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        GridLayout layout2 = new GridLayout(2, false);
        layout2.marginLeft = 5;
        layout2.verticalSpacing = 2;
        composite2.setLayout(layout2);

        List<Link> list = new ArrayList<Link>();

        for (IMarkerResolution resolution : resolutions) {
            // Original link for single fix, hence pass 1 for count
            list.add(createCompletionProposalLink(composite2, marker, resolution, 1));
        }

        final Link[] links = list.toArray(new Link[0]);

        focusControl = links[0];
        for (int i = 0; i < links.length; i++) {
            final int index = i;
            final Link link = links[index];

            link.addKeyListener(new KeyListener() {
                public void keyPressed(KeyEvent e) {
                    switch (e.keyCode) {
                    case SWT.ARROW_DOWN: {
                        if (index + 1 < links.length) {
                            links[index + 1].setFocus();
                        }

                        break;
                    }
                    case SWT.ARROW_UP: {
                        if (index > 0) {
                            links[index - 1].setFocus();
                        }

                        break;
                    }

                    default:
                        break;
                    }
                }

                public void keyReleased(KeyEvent e) {
                }
            });

        }
    }

    protected void deferredCreateContent() {
        if (region != null) {
            final ScrolledComposite scrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL);
            GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
            scrolledComposite.setLayoutData(gridData);
            scrolledComposite.setExpandVertical(false);
            scrolledComposite.setExpandHorizontal(false);

            Composite composite = new Composite(scrolledComposite, SWT.NONE);
            composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
            GridLayout layout = new GridLayout(1, false);
            composite.setLayout(layout);

            scrolledComposite.setContent(composite);

            for (IRegion reg : region.getRegions()) {
                if (reg instanceof MarkerRegion) {
                    final MarkerRegion markerReg = (MarkerRegion) reg;
                    createAnnotationInformation(composite, markerReg.getAnnotation());
                    final IMarker marker = markerReg.getAnnotation().getMarker();
                    IMarkerResolution[] resolutions = IDE.getMarkerHelpRegistry().getResolutions(marker);

                    if (resolutions.length > 0) {
                        createResolutionsControl(composite, marker, resolutions);
                        // createSeparator( composite );
                    }
                } else if (reg instanceof TemporaryRegion) {
                    final TemporaryRegion tempReg = (TemporaryRegion) reg;
                    createAnnotationInformation(composite, tempReg.getAnnotation());
                    final IMarker marker = new TempMarker(tempReg.getAnnotation());

                    IMarkerResolution[] resolutions = IDE.getMarkerHelpRegistry().getResolutions(marker);

                    if (resolutions.length > 0) {
                        createResolutionsControl(composite, marker, resolutions);
                    }
                } else if (reg instanceof InfoRegion) {
                    String text;

                    if ((text = ((InfoRegion) reg).getInfo()) != null) {
                        setInformation(composite, text);
                    }
                }
            }

            Point constraints = getSizeConstraints();
            Point contentSize = composite.computeSize(constraints != null ? constraints.x : SWT.DEFAULT,
                    SWT.DEFAULT);

            composite.setSize(new Point(contentSize.x, contentSize.y));
        }

        setColorAndFont(parent, parent.getForeground(), parent.getBackground(), JFaceResources.getDialogFont());

        parent.layout(true);
    }

    protected void disposeDeferredCreatedContent() {
        Control[] children = parent.getChildren();

        for (Control child : children) {
            child.dispose();
        }

        ToolBarManager toolBarManager = getToolBarManager();

        if (toolBarManager != null) {
            toolBarManager.removeAll();
        }
    }

    public IInformationControlCreator getInformationPresenterControlCreator() {
        return new IInformationControlCreator() {
            public IInformationControl createInformationControl(Shell parent) {
                return new LiferayCustomXmlHoverControl(parent);
            }
        };
    }

    Shell getMyShell() {
        return super.getShell();
    }

    Control getRoot() {
        return parent;
    }

    public boolean hasContents() {
        return region != null;
    }

    private void setColorAndFont(Control control, Color foreground, Color background, Font font) {
        control.setForeground(foreground);
        control.setBackground(background);
        control.setFont(font);

        if (control instanceof Composite) {
            Control[] children = ((Composite) control).getChildren();

            for (Control child : children) {
                setColorAndFont(child, foreground, background, font);
            }
        }
    }

    public void setFocus() {
        super.setFocus();
        if (focusControl != null) {
            focusControl.setFocus();
        }
    }

    /**
     * @see org.eclipse.jface.text.DefaultInformationControl#setInformation(String)
     */
    private void setInformation(Composite composite, String content) {
        final HTMLTextPresenter presenter = new HTMLTextPresenter(true);

        final TextPresentation presentation = new TextPresentation();

        int maxWidth = -1;
        int maxHeight = -1;

        Point constraints = getSizeConstraints();
        StyledText styledText = new StyledText(composite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);

        int innerBorder = 1;

        if (constraints != null) {
            maxWidth = constraints.x;
            maxHeight = constraints.y;

            if (styledText.getWordWrap()) {
                maxWidth -= innerBorder * 2;
                maxHeight -= innerBorder * 2;
            } else {
                maxWidth -= innerBorder;
            }

            Rectangle trim = computeTrim();
            maxWidth -= trim.width;
            maxHeight -= trim.height;
            maxWidth -= styledText.getCaret().getSize().x;
        }

        if (isResizable()) {
            maxHeight = Integer.MAX_VALUE;
        }

        if (presenter instanceof IInformationPresenterExtension) {
            content = ((IInformationPresenterExtension) presenter).updatePresentation(styledText, content,
                    presentation, maxWidth, maxHeight);
        }

        if (content != null) {
            styledText.setText(content);
            TextPresentation.applyTextPresentation(presentation, styledText);
        } else {
            styledText.setText("");
        }
    }

    public void setInput(Object input) {
        if (input instanceof CompoundRegion) {
            region = (CompoundRegion) input;
        } else {
            // throw new IllegalStateException( "Not CompoundRegion" );
            return;
        }

        disposeDeferredCreatedContent();
        deferredCreateContent();
    }

    public final void setVisible(boolean visible) {
        if (!visible) {
            disposeDeferredCreatedContent();
        }

        super.setVisible(visible);
    }

}