org.eclipse.equinox.p2.authoring.forms.RichFormPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.equinox.p2.authoring.forms.RichFormPage.java

Source

/*******************************************************************************
 * Copyright (c) 2008
 * The code, documentation and other materials contained herein have been
 * licensed under the Eclipse Public License - v 1.0 by the individual
 * copyright holders listed below, as Initial Contributors under such license.
 * The text of such license is available at 
 * http://www.eclipse.org/legal/epl-v10.html.
 * 
 * Contributors:
 *       Henrik Lindberg
 *******************************************************************************/

package org.eclipse.equinox.p2.authoring.forms;

import java.io.PrintWriter;
import java.io.StringWriter;

import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.HyperlinkSettings;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.IMessage;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IExpansionListener;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.eclipse.ui.forms.AbstractFormPart;

/**
 * A base class for Eclipse form pages that adds support for showing messages and sets wanted defaults.
 * 
 * @author Henrik Lindberg
 * 
 */
public abstract class RichFormPage extends FormPage implements IGlobalActionPerformer {
    private IExpansionListener m_reflowOnExpansion;

    /** The number of columns in the outermost TableWrapLayout - default is 2 */
    protected int m_numColumns = 2;

    /** The header string - default is "Undefined" */
    protected String m_header = "Undefined";

    protected boolean m_makeColumnsEqualWidth = false;

    protected Image m_headerImage = null;

    public RichFormPage(FormEditor editor, String id, String tabLabel) {
        super(editor, id, tabLabel);
    }

    /**
     * Creates the form content:
     * <ul>
     * <li>The outermost ScrolledForm gets a TableWrapLayout</li>
     * <li>The outermost table gets a default of 2 columns - change by setting {@link #m_numColumns }</li>
     * <li>Left and right margins are set to 10 so the form contents does not kiss the edges</li>
     * <li>The Eclipse 3.3. default header decoration is turned on</li>
     * <li>Hyperlinks are set to underline on hover</li>
     * <li>The header is set to the value of the protected {@link #m_header}</li>
     * <li>A section expansion listener that reflows the layout is created, and can be used when setting up the contents
     * of the form. See {@link #getReflowListener()}.</li>
     * <li>A hyperlink listener is set up to display a list of formatted messages from the MessageManager.</li>
     * </ul>
     * 
     */
    @Override
    protected final void createFormContent(IManagedForm managedForm) {
        final ScrolledForm scrolledForm = managedForm.getForm();
        final FormToolkit toolkit = managedForm.getToolkit();

        // Set header.
        scrolledForm.setText(m_header);
        if (m_headerImage != null)
            scrolledForm.setImage(m_headerImage);

        // Use default 3.3. form page header (old style required an image)
        toolkit.decorateFormHeading(scrolledForm.getForm());

        // underline hyperlinks on hover
        toolkit.getHyperlinkGroup().setHyperlinkUnderlineMode(HyperlinkSettings.UNDERLINE_HOVER);

        TableWrapLayout layout = new TableWrapLayout();
        layout.leftMargin = 5;
        layout.rightMargin = 5;
        layout.numColumns = m_numColumns;
        layout.makeColumnsEqualWidth = m_makeColumnsEqualWidth;
        scrolledForm.getBody().setLayout(layout);

        // Create the reflowing expansion listener
        //
        m_reflowOnExpansion = new ExpansionAdapter() {

            @Override
            public void expansionStateChanged(ExpansionEvent e) {
                scrolledForm.reflow(true);
            }
        };

        // Add a popup with formatted message to a hyperlink
        // TODO: This sample code probably pops up an empty window for non message links
        // Needs to be fixed if other hyperlinks are added to the form...

        scrolledForm.getForm().addMessageHyperlinkListener(new HyperlinkAdapter() {
            @Override
            public void linkActivated(HyperlinkEvent e) {
                String title = e.getLabel();
                // String details = title;
                Object href = e.getHref();
                if (href instanceof IMessage[]) {
                    // details =
                    // managedForm.getMessageManager().createSummary((IMessage[])href);
                }
                // int type = form.getForm().getMessageType();
                /*
                 * switch (type) { case IMessageProvider.NONE: case IMessageProvider.INFORMATION:
                 * MessageDialog.openInformation(form.getShell(), title, details); break; case IMessageProvider.WARNING:
                 * MessageDialog.openWarning(form.getShell(), title, details); break; case IMessageProvider.ERROR:
                 * MessageDialog.openError(form.getShell(), title, details); break; }
                 */
                Point hl = ((Control) e.widget).toDisplay(0, 0);
                hl.x += 10;
                hl.y += 10;
                // Note, must be application modal, or it is possible to navigate the form and make changes that affects the
                // message state. (And perhaps even worse, to open the popup again).
                final Shell shell = new Shell(scrolledForm.getShell(),
                        SWT.ON_TOP | SWT.TOOL | SWT.APPLICATION_MODAL);
                shell.setImage(getImage(scrolledForm.getMessageType()));
                shell.setText(title);
                shell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
                FillLayout fillLayout = new FillLayout();
                fillLayout.marginHeight = 5;
                fillLayout.marginWidth = 5;

                shell.setLayout(fillLayout);
                // ScrolledFormText stext = new ScrolledFormText(shell, false);
                // stext.setBackground(toolkit.getColors().getBackground());
                FormText text = toolkit.createFormText(shell, false);
                configureFormText(scrolledForm.getForm(), text);
                // stext.setFormText(text);
                if (href instanceof IMessage[])
                    text.setText(createFormTextContent((IMessage[]) href), true, false);
                shell.setLocation(hl);
                // Point size = shell.computeSize(400, SWT.DEFAULT);
                /*
                 * richToolTipMessageManager.setActive(false); shell.addDisposeListener(new DisposeListener() { public
                 * void widgetDisposed(DisposeEvent e) { richToolTipMessageManager.setActive(true); } });
                 */

                // must have a key listener to make it possible to close the popup shell on ESC key
                shell.addKeyListener(new KeyAdapter() {

                    @Override
                    public void keyPressed(KeyEvent event) {
                        // close shell on escape key
                        if (event.keyCode == SWT.ESC)
                            shell.dispose();
                    }
                });
                shell.pack();
                shell.open();
                shell.forceFocus();
            }
        });
        scrolledForm.addTraverseListener(new TraverseListener() {

            public void keyTraversed(TraverseEvent e) {
                System.err.print("Traverse Event Occured in RichFormPage");
            }

        });
        addFormContent(managedForm);
    }

    /**
     * Replacement for {@link #createFormContent(IManagedForm)} which has been made final. This method is called as the
     * last step, and should complete the creation of the form content, but should not set up everything supported by
     * the default implementation. See {@link #createFormContent(IManagedForm)} for all the things that are set up by
     * default.
     * 
     * @param managedForm
     */
    abstract protected void addFormContent(IManagedForm managedForm);

    /**
     * Returns an IExpansionListener that reflows the form when expansion changes. Attach this listener to expandable
     * sections in the form.
     * 
     * @return null if createFormContent has not been called.
     */
    protected IExpansionListener getReflowListener() {
        return m_reflowOnExpansion;
    }

    private void configureFormText(final Form form, FormText text) {
        text.addHyperlinkListener(new HyperlinkAdapter() {
            @Override
            public void linkActivated(HyperlinkEvent e) {
                String is = (String) e.getHref();
                try {
                    int index = Integer.parseInt(is);
                    IMessage[] messages = form.getChildrenMessages();
                    IMessage message = messages[index];
                    Control c = message.getControl();
                    ((FormText) e.widget).getShell().dispose();
                    if (c != null)
                        c.setFocus();
                } catch (ArrayIndexOutOfBoundsException ex) {
                    // This can happens if message array changes while menu is up
                    ((FormText) e.widget).getShell().dispose();
                } catch (NumberFormatException ex) {
                }
            }
        });
        text.setImage("error", getImage(IMessageProvider.ERROR)); //$NON-NLS-1$
        text.setImage("warning", getImage(IMessageProvider.WARNING)); //$NON-NLS-1$
        text.setImage("info", getImage(IMessageProvider.INFORMATION)); //$NON-NLS-1$
    }

    /**
     * Formats messages into a form string
     * 
     * @param messages
     *            - messages to format
     * @return a form string
     */
    private String createFormTextContent(IMessage[] messages) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        pw.println("<form>"); //$NON-NLS-1$
        for (int i = 0; i < messages.length; i++) {
            IMessage message = messages[i];
            pw.print("<li vspace=\"false\" style=\"image\" indent=\"16\" value=\""); //$NON-NLS-1$
            switch (message.getMessageType()) {
            case IMessageProvider.ERROR:
                pw.print("error"); //$NON-NLS-1$
                break;
            case IMessageProvider.WARNING:
                pw.print("warning"); //$NON-NLS-1$
                break;
            case IMessageProvider.INFORMATION:
                pw.print("info"); //$NON-NLS-1$
                break;
            }
            pw.print("\"> <a href=\""); //$NON-NLS-1$
            pw.print(i + ""); //$NON-NLS-1$
            pw.print("\">");//$NON-NLS-1$
            if (message.getPrefix() != null)
                pw.print(message.getPrefix());
            pw.print(message.getMessage());
            pw.println("</a></li>"); //$NON-NLS-1$
        }
        pw.println("</form>"); //$NON-NLS-1$
        pw.flush();
        return sw.toString();
    }

    /**
     * Convenience method to pick up platform images for error and warning.
     * 
     * @param type
     * @return
     */
    private Image getImage(int type) {
        switch (type) {
        case IMessageProvider.ERROR:
            return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
        case IMessageProvider.WARNING:
            return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);
        case IMessageProvider.INFORMATION:
            return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_INFO_TSK);
        }
        return null;
    }

    protected Control getFocusControl() {
        IManagedForm form = getManagedForm();
        if (form == null)
            return null;
        Control control = form.getForm();
        if (control == null || control.isDisposed())
            return null;
        Display display = control.getDisplay();
        Control focusControl = display.getFocusControl();
        if (focusControl == null || focusControl.isDisposed())
            return null;
        return focusControl;
    }

    public boolean doGlobalAction(String actionId) {
        Control focusControl = getFocusControl();
        if (focusControl == null)
            return false;

        if (canPerformDirectly(actionId, focusControl))
            return true;
        AbstractFormPart focusPart = getFocusSection();
        if (focusPart != null) {
            if (focusPart instanceof IGlobalActionPerformer)
                return ((IGlobalActionPerformer) focusPart).doGlobalAction(actionId);
        }
        return false;
    }

    public boolean canPaste(Clipboard clipboard) {
        AbstractFormPart focusPart = getFocusSection();
        if (focusPart != null) {
            if (focusPart instanceof IGlobalActionPerformer) {
                return ((IGlobalActionPerformer) focusPart).canPaste(clipboard);
            }
        }
        // Otherwise, check if focus holder can handle action
        Control focusControl = getFocusControl();
        if (focusControl != null && focusControl instanceof Text && ((Text) focusControl).getEditable())
            return true;
        return false;
    }

    /**
     * @param selection
     * @return
     */
    public boolean canCopy(ISelection selection) {
        // If there is a focused part that wants to handle this, it should do so
        AbstractFormPart focusPart = getFocusSection();
        if (focusPart != null) {
            if (focusPart instanceof IGlobalActionPerformer) {
                return ((IGlobalActionPerformer) focusPart).canCopy(selection);
            }
        }
        // Otherwise, check if focus holder can handle action
        Control focusControl = getFocusControl();
        if (focusControl != null && focusControl instanceof Text)
            return true;
        return false;
    }

    /**
     * @param selection
     * @return
     */
    public boolean canCut(ISelection selection) {
        AbstractFormPart focusPart = getFocusSection();
        if (focusPart != null) {
            if (focusPart instanceof IGlobalActionPerformer) {
                return ((IGlobalActionPerformer) focusPart).canCut(selection);
            }
        }
        // Otherwise, check if focus holder can handle action
        Control focusControl = getFocusControl();
        if (focusControl != null && focusControl instanceof Text && ((Text) focusControl).getEditable())
            return true;
        return false;
    }

    private AbstractFormPart getFocusSection() {
        Control focusControl = getFocusControl();
        if (focusControl == null)
            return null;
        Composite parent = focusControl.getParent();
        AbstractFormPart targetPart = null;
        while (parent != null) {
            Object data = parent.getData("part"); //$NON-NLS-1$
            if (data != null && data instanceof AbstractFormPart) {
                targetPart = (AbstractFormPart) data;
                break;
            }
            parent = parent.getParent();
        }
        return targetPart;
    }

    protected boolean canPerformDirectly(String id, Control control) {
        if (control instanceof Text) {
            Text text = (Text) control;
            if (id.equals(ActionFactory.CUT.getId())) {
                text.cut();
                return true;
            }
            if (id.equals(ActionFactory.COPY.getId())) {
                text.copy();
                return true;
            }
            if (id.equals(ActionFactory.PASTE.getId())) {
                text.paste();
                return true;
            }
            if (id.equals(ActionFactory.SELECT_ALL.getId())) {
                text.selectAll();
                return true;
            }
            if (id.equals(ActionFactory.DELETE.getId())) {
                int count = text.getSelectionCount();
                if (count == 0) {
                    int caretPos = text.getCaretPosition();
                    text.setSelection(caretPos, caretPos + 1);
                }
                text.insert(""); //$NON-NLS-1$
                return true;
            }
        }
        return false;
    }

}