org.jboss.tools.central.editors.xpl.TextSearchControl.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.tools.central.editors.xpl.TextSearchControl.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Tasktop Technologies 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 accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Tasktop Technologies - initial API and implementation
 *     JBoss by Red Hat
 *******************************************************************************/
package org.jboss.tools.central.editors.xpl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.fieldassist.ContentProposal;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.mylyn.internal.commons.ui.CommonsUiPlugin;
import org.eclipse.mylyn.internal.commons.workbench.Messages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseTrackListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.jboss.tools.central.JBossCentralActivator;

/**
 * @author Shawn Minto
 * @author snjeza
 */
public class TextSearchControl extends Composite {

    private static final int MAX_PROPOSAL_ITEMS = 50;

    /**
     * Image descriptor for enabled clear button.
     */
    private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEAR_ICON"; //$NON-NLS-1$

    /**
     * Image descriptor for enabled clear button.
     */
    private static final String FIND_ICON = "org.eclipse.ui.internal.dialogs.FIND_ICON"; //$NON-NLS-1$

    private static final String SEARCH_SECTION = "searchSection";

    private static final String SEARCH_KEY = "searchKey";

    /* SWT STYLE BIT AVAILABLE ON 3.5 AND HIGHER */
    public static final int ICON_SEARCH = 1 << 9;

    /* SWT STYLE BIT AVAILABLE ON 3.5 AND HIGHER */
    public static final int ICON_CANCEL = 1 << 8;

    private static final String INITIAL_MESSAGE = "initialMessage";

    /**
     * Get image descriptors for the clear button.
     */
    static {
        ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
                "$nl$/icons/full/etool16/clear_co.gif"); //$NON-NLS-1$
        if (descriptor != null) {
            JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor);
        }

        descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(CommonsUiPlugin.ID_PLUGIN,
                "$nl$/icons/etool16/find.png"); //$NON-NLS-1$
        if (descriptor != null) {
            JFaceResources.getImageRegistry().put(FIND_ICON, descriptor);
        }
    }

    private Text textControl;

    private Control clearControl;

    private Control findControl;

    private final Set<SelectionListener> selectionListeners = new HashSet<SelectionListener>();

    private static Boolean useNativeSearchField;

    private String initialMessage;

    private String[] proposals;

    @SuppressWarnings("restriction")
    public TextSearchControl(Composite parent, boolean automaticFind) {
        super(parent, getCompositeStyle(automaticFind, parent));

        int textStyle = SWT.SINGLE;
        int numColumns = 1;
        if (useNativeSearchField(automaticFind, parent)) {
            if (automaticFind) {
                textStyle |= SWT.SEARCH | ICON_CANCEL;
            } else {
                textStyle |= SWT.SEARCH | ICON_SEARCH | ICON_CANCEL;
            }
        } else {
            super.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
            super.setFont(parent.getFont());
            numColumns = 2;
            if (!automaticFind) {
                numColumns += 1;
            }
        }
        GridLayoutFactory.swtDefaults().margins(0, 0).extendedMargins(0, 0, 0, 0).spacing(0, 1)
                .numColumns(numColumns).applyTo(this);

        textControl = new Text(this, textStyle);
        GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);

        textControl.setLayoutData(gridData);

        KeyStroke stroke;
        String proposalKey = null;
        try {
            stroke = KeyStroke.getInstance("M1+SPACE"); //$NON-NLS-1$
            proposalKey = stroke.format();
        } catch (ParseException e1) {
            JBossCentralActivator.log(e1);
        }
        stroke = null;
        final ControlDecoration dec = new ControlDecoration(textControl, SWT.TOP | SWT.LEFT);
        FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
        FieldDecoration fd = registry.getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
        dec.setImage(fd.getImage());
        String description;
        if (proposalKey == null) {
            description = fd.getDescription();
        } else {
            description = fd.getDescription() + "(" + proposalKey + ")";
        }
        dec.setDescriptionText(description);

        dec.setImage(FieldDecorationRegistry.getDefault()
                .getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL).getImage());

        dec.setShowOnlyOnFocus(true);
        dec.setShowHover(true);

        ContentProposalAdapter adapter = new ContentProposalAdapter(textControl, new TextContentAdapter(),
                new SearchContentProposalProvider(), null, null);
        adapter.setPropagateKeys(true);
        adapter.setProposalAcceptanceStyle(ContentProposalAdapter.PROPOSAL_REPLACE);

        if (useNativeSearchField == null || !useNativeSearchField) {
            findControl = createLabelButtonControl(this, JFaceResources.getImageRegistry().getDescriptor(FIND_ICON),
                    Messages.TextControl_AccessibleListenerFindButton, Messages.TextControl_FindToolTip,
                    ICON_SEARCH);
            Point size = findControl.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            GridData data = (GridData) textControl.getLayoutData();
            data.heightHint = size.y;
            clearControl = createLabelButtonControl(this,
                    JFaceResources.getImageRegistry().getDescriptor(CLEAR_ICON),
                    WorkbenchMessages.FilteredTree_ClearToolTip, //FilteredTree_AccessibleListenerClearButton,
                    WorkbenchMessages.FilteredTree_ClearToolTip, ICON_CANCEL);
            addModifyListener(new ModifyListener() {

                public void modifyText(ModifyEvent e) {
                    updateButtonVisibilityAndEnablement();

                }
            });
            updateButtonVisibilityAndEnablement();
        }

        IDialogSettings section = getSearchSettings();
        proposals = section.getArray(SEARCH_KEY);
        if (proposals == null) {
            proposals = new String[0];
            section.put(SEARCH_KEY, proposals);
        }
        String message = section.get(INITIAL_MESSAGE);
        if (message == null || message.isEmpty()) {
            message = JBossCentralActivator.SEARCH_THE_COMMUNITY;
        }
        setInitialMessage(message);

        registerListeners();
    }

    private void registerListeners() {
        addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
                if (textControl != null && !textControl.isDisposed()) {
                    addSearchSettings();
                }

            }
        });
        textControl.addFocusListener(new FocusAdapter() {

            @Override
            public void focusLost(FocusEvent e) {
                if (textControl != null && !textControl.isDisposed()) {
                    // addSearchSettings();
                    if (textControl.getText().isEmpty()) {
                        setInitialMessage(initialMessage);
                    }
                    updateButtonVisibilityAndEnablement();
                }
            }

        });
    }

    private static int getCompositeStyle(boolean automaticFind, Composite parent) {
        if (useNativeSearchField(automaticFind, parent)) {
            return SWT.NONE;
        }
        return SWT.BORDER;
    }

    private static boolean useNativeSearchField(boolean automaticFind, Composite parent) {
        if (parent != null) {
            if (useNativeSearchField == null) {
                useNativeSearchField = Boolean.FALSE;
                Text testText = null;
                try {
                    int style = SWT.SEARCH | ICON_CANCEL;
                    if (automaticFind) {
                        style |= ICON_SEARCH;
                    }
                    testText = new Text(parent, style);
                    useNativeSearchField = new Boolean((testText.getStyle() & ICON_CANCEL) != 0
                            && (!automaticFind || (testText.getStyle() & ICON_SEARCH) != 0));
                } finally {
                    if (testText != null) {
                        testText.dispose();
                    }
                }

            }
        } else {
            useNativeSearchField = Boolean.FALSE;
        }
        return useNativeSearchField.booleanValue();
    }

    private Control createLabelButtonControl(Composite parent, ImageDescriptor activeImageDescriptor,
            final String accessibilityText, String toolTipText, final int detail) {

        final Image nativeImage = parent.getDisplay().getSystemImage(detail);

        final Image activeImage = nativeImage != null ? nativeImage : activeImageDescriptor.createImage();
        final Image inactiveImage = new Image(parent.getDisplay(), activeImage, SWT.IMAGE_GRAY);
        final Image pressedImage = inactiveImage;

        final Label labelButton = new Label(parent, SWT.NONE);
        labelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
        labelButton.setImage(inactiveImage);
        labelButton.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
        labelButton.setToolTipText(toolTipText);
        labelButton.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                if (nativeImage == null && activeImage != null && !activeImage.isDisposed()) {
                    activeImage.dispose();
                }
                if (inactiveImage != null && !inactiveImage.isDisposed()) {
                    inactiveImage.dispose();
                }
                if (pressedImage != null && !pressedImage.isDisposed()) {
                    pressedImage.dispose();
                }
            }
        });
        labelButton.addMouseListener(new MouseAdapter() {
            private MouseMoveListener fMoveListener;

            @Override
            public void mouseDown(MouseEvent e) {
                labelButton.setImage(pressedImage);
                fMoveListener = new MouseMoveListener() {
                    private boolean fMouseInButton = true;

                    public void mouseMove(MouseEvent e) {
                        boolean mouseInButton = isMouseInButton(e);
                        if (mouseInButton != fMouseInButton) {
                            fMouseInButton = mouseInButton;
                            labelButton.setImage(mouseInButton ? pressedImage : inactiveImage);
                        }
                    }
                };
                labelButton.addMouseMoveListener(fMoveListener);
            }

            @Override
            public void mouseUp(MouseEvent e) {
                if (fMoveListener != null) {
                    labelButton.removeMouseMoveListener(fMoveListener);
                    fMoveListener = null;
                    boolean mouseInButton = isMouseInButton(e);
                    labelButton.setImage(mouseInButton ? activeImage : inactiveImage);
                    if (mouseInButton) {
                        if (textControl != null && textControl.isEnabled() && textControl.getText().length() > 0) {
                            notifySelectionChanged(detail);
                        }
                    }
                }
            }

            private boolean isMouseInButton(MouseEvent e) {
                Point buttonSize = labelButton.getSize();
                return 0 <= e.x && e.x < buttonSize.x && 0 <= e.y && e.y < buttonSize.y;
            }
        });

        labelButton.addMouseTrackListener(new MouseTrackListener() {
            public void mouseEnter(MouseEvent e) {
                if (labelButton.getImage() != activeImage) {
                    labelButton.setImage(activeImage);
                }
            }

            public void mouseExit(MouseEvent e) {
                if (labelButton.getImage() != inactiveImage) {
                    labelButton.setImage(inactiveImage);
                }
            }

            public void mouseHover(MouseEvent e) {
            }
        });

        labelButton.getAccessible().addAccessibleListener(new AccessibleAdapter() {
            @Override
            public void getName(AccessibleEvent e) {
                e.result = accessibilityText;
            }
        });
        labelButton.getAccessible().addAccessibleControlListener(new AccessibleControlAdapter() {
            @Override
            public void getRole(AccessibleControlEvent e) {
                e.detail = ACC.ROLE_PUSHBUTTON;
            }
        });
        return labelButton;
    }

    @Override
    public void addTraverseListener(TraverseListener listener) {
        textControl.addTraverseListener(listener);
    }

    @Override
    public void removeTraverseListener(TraverseListener listener) {
        textControl.removeTraverseListener(listener);
    }

    public void addSelectionListener(SelectionListener listener) {
        textControl.addSelectionListener(listener);
        selectionListeners.add(listener);
    }

    public void removeSelectionListener(SelectionListener listener) {
        textControl.removeSelectionListener(listener);
        selectionListeners.remove(listener);
    }

    public void addModifyListener(ModifyListener listener) {
        textControl.addModifyListener(listener);
    }

    public void removeModifyListener(ModifyListener listener) {
        textControl.removeModifyListener(listener);
    }

    private void notifySelectionChanged(int detail) {
        if (useNativeSearchField != null && useNativeSearchField) {
            // notification should happen via the widgets selection listener
            return;
        }
        Event event = new Event();
        event.detail = detail;
        event.widget = textControl;
        event.display = textControl.getDisplay();

        SelectionEvent e = new SelectionEvent(event);
        for (Object element : selectionListeners) {
            ((SelectionListener) element).widgetDefaultSelected(e);
        }
    }

    private void updateButtonVisibilityAndEnablement() {
        if (textControl != null && !textControl.isDisposed()) {
            boolean hasText = textControl.getText().length() > 0;

            //setFindButtonVisibility(!(hasText && automaticFind));
            setFindButtonVisibility(hasText);
            setClearButtonVisibility(hasText);
        }
    }

    private void setFindButtonVisibility(boolean visible) {
        if (findControl != null && !findControl.isDisposed()) {
            findControl.setVisible(visible);
            if (findControl.getLayoutData() instanceof GridData) {
                ((GridData) findControl.getLayoutData()).exclude = !visible;
                findControl.getParent().layout();
            }
        }
    }

    private void setClearButtonVisibility(boolean visible) {
        if (clearControl != null && !clearControl.isDisposed()) {
            clearControl.setVisible(visible);
            if (clearControl.getLayoutData() instanceof GridData) {
                ((GridData) clearControl.getLayoutData()).exclude = !visible;
                clearControl.getParent().layout();
            }
        }
    }

    public Text getTextControl() {
        return textControl;
    }

    public String getText() {
        if (textControl != null && !textControl.isDisposed()) {
            return textControl.getText();
        }
        return ""; //$NON-NLS-1$
    }

    public void setText(String text) {
        if (textControl != null && !textControl.isDisposed()) {
            textControl.setText(text);
        }
    }

    @Override
    public void setBackground(Color color) {
        if (useNativeSearchField != null && useNativeSearchField) {
            super.setBackground(color);
        }
    }

    public String getInitialMessage() {
        return initialMessage;
    }

    public void setInitialMessage(String initialMessage) {
        this.initialMessage = initialMessage;
        if (textControl != null && !textControl.isDisposed() && textControl.getText().isEmpty()) {
            textControl.setMessage(initialMessage);
            IDialogSettings section = getSearchSettings();
            section.put(INITIAL_MESSAGE, initialMessage);
        }
    }

    private IDialogSettings getSearchSettings() {
        IDialogSettings settings = JBossCentralActivator.getDefault().getDialogSettings();
        IDialogSettings section = settings.getSection(SEARCH_SECTION);
        if (section == null) {
            section = settings.addNewSection(SEARCH_SECTION);
        }
        return section;
    }

    private void addSearchSettings() {
        String text = textControl.getText().trim();
        if (!text.isEmpty()) {
            boolean found = false;
            for (String proposal : proposals) {
                if (text.equals(proposal)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                int length = proposals.length;
                if (length > MAX_PROPOSAL_ITEMS) {
                    length = MAX_PROPOSAL_ITEMS;
                }
                String[] newProposals = new String[length + 1];
                System.arraycopy(proposals, 0, newProposals, 1, length);
                newProposals[0] = text;
                proposals = newProposals;
                IDialogSettings section = getSearchSettings();
                section.put(SEARCH_KEY, proposals);
            }
        }
    }

    private class SearchContentProposalProvider implements IContentProposalProvider {

        @Override
        public IContentProposal[] getProposals(String contents, int position) {
            if (contents != null) {
                if (position > 0) {
                    contents = contents.substring(0, position);
                }
                contents = contents.trim();
            }
            List<IContentProposal> contentProposals = new ArrayList<IContentProposal>();
            for (String proposal : proposals) {
                if (proposal != null && proposal.startsWith(contents)) {
                    contentProposals.add(new ContentProposal(proposal));
                }
            }
            return contentProposals.toArray(new IContentProposal[0]);
        }

    }

}