org.eclipse.jubula.client.ui.rcp.dialogs.FindDialog.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jubula.client.ui.rcp.dialogs.FindDialog.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2010 BREDEX GmbH.
 * 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:
 *     BREDEX GmbH - initial API and implementation and/or initial documentation
 *******************************************************************************/
package org.eclipse.jubula.client.ui.rcp.dialogs;

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

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jubula.client.ui.constants.ContextHelpIds;
import org.eclipse.jubula.client.ui.rcp.Plugin;
import org.eclipse.jubula.client.ui.rcp.businessprocess.UINodeBP;
import org.eclipse.jubula.client.ui.rcp.i18n.Messages;
import org.eclipse.jubula.client.ui.rcp.search.query.Operation;
import org.eclipse.jubula.client.ui.rcp.search.query.TextFinder;
import org.eclipse.jubula.client.ui.utils.JobUtils;
import org.eclipse.jubula.client.ui.utils.TreeViewerIterator;
import org.eclipse.jubula.client.ui.views.IMultiTreeViewerContainer;
import org.eclipse.jubula.client.ui.views.ITreeViewerContainer;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;

/**
 * This class creates a dialog, where you can search a TreeViewer for specified
 * string. The search is performed by using content- and labelprovider of the 
 * treeviewer.
 * 
 * @author BREDEX GmbH
 * @created 22.02.2005
 * @param <NODE> INodePO or TestResultNodeGUI
 */
public class FindDialog<NODE> implements DisposeListener {

    /** recent queries */
    private static final List<String> RECENT = new ArrayList<String>(5);
    /** recent option */
    private static boolean lastforward = true;
    /** recent option */
    private static boolean lastwrapsearch = true;
    /** recent option */
    private static boolean lastregex = false;
    /** recent option */
    private static boolean lastcasesensitive = false;
    /** the shell depends on the object that is selected */
    private Shell m_shell;
    /** find listener for callback */
    private ITreeViewerContainer m_treeViewContainer;
    /** search Text Field */
    private Combo m_searchStringCombo;
    /** Directions Group */
    private Group m_directionGroup;
    /** Combo to select Find Forward */
    private Button m_findForwardButton;
    /** Combo to select Find Backward */
    private Button m_findBackwardButton;
    /** Options Group */
    private Group m_optionsGroup;
    /** CheckbBox to select Wrap Search */
    private Button m_wrapSearchCheck;
    /** CheckbBox to select use regular expression */
    private Button m_useRegExCheck;
    /** CheckbBox to select use search case sensitiv */
    private Button m_caseSensitivCheck;
    /** help Link */
    private Link m_helpLink;
    /** find Button */
    private Button m_findButton;
    /** cancel Button */
    private Button m_cancelButton;
    /** Label for showing errors */
    private Label m_errorLabel;

    /**
     * @param parentShell The parent shell.
     * @param listener IFindListener
     */
    public FindDialog(Shell parentShell, ITreeViewerContainer listener) {
        m_shell = new Shell(parentShell);
        setTreeViewContainer(listener);
        init();
        Plugin.getHelpSystem().setHelp(parentShell, ContextHelpIds.FIND_DIALOG);
    }

    /**
     * initializes search window
     */
    private void init() {
        m_shell.setText(Messages.FindDialogTitle);
        createContent();
        Point location = m_shell.getDisplay().getCursorLocation();
        if ((location.x + m_shell.getSize().x) > m_shell.getDisplay().getPrimaryMonitor().getBounds().width) {
            location.x = m_shell.getDisplay().getPrimaryMonitor().getBounds().width - m_shell.getSize().x;
        }
        if ((location.y + m_shell.getSize().y) > m_shell.getDisplay().getPrimaryMonitor().getBounds().height) {
            location.y = m_shell.getDisplay().getPrimaryMonitor().getBounds().height - m_shell.getSize().y;
        }
        m_shell.setLocation(location);
    }

    /**
     * creates all the dialog content
     */
    private void createContent() {
        FormLayout layout = new FormLayout();
        layout.marginHeight = 5;
        layout.marginWidth = 10;
        m_shell.setLayout(layout);
        Label findLabel = new Label(m_shell, SWT.NONE);
        findLabel.setText(Messages.FindDialogFind + StringConstants.COLON);
        FormData findLabelData = new FormData();
        // set position and size with relative values
        findLabelData.left = new FormAttachment(0, 0);
        findLabelData.top = new FormAttachment(0, 10);
        findLabel.setLayoutData(findLabelData);
        m_searchStringCombo = new Combo(m_shell, SWT.BORDER);
        FormData searchStringTextData = new FormData();
        searchStringTextData.top = new FormAttachment(findLabel, 0, SWT.TOP);
        searchStringTextData.left = new FormAttachment(findLabel, 10, SWT.RIGHT);
        searchStringTextData.right = new FormAttachment(100, 0);
        m_searchStringCombo.setLayoutData(searchStringTextData);
        m_searchStringCombo.setItems(RECENT.toArray(new String[RECENT.size()]));
        if (m_searchStringCombo.getItemCount() == 0) {
            m_searchStringCombo.setText(Messages.FindDialogPhrase);
        } else {
            m_searchStringCombo.select(0);
        }
        m_searchStringCombo.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (e.keyCode == 13) {
                    doCallBack();
                }
            }
        });
        createDirectionGroup();
        createOptionsGroup();
        createButtons();
        createHelpLink();
        m_errorLabel = new Label(m_shell, SWT.NONE);
        m_errorLabel.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
        FormData errorLabelData = new FormData();
        errorLabelData.top = new FormAttachment(m_findButton, 5, SWT.BOTTOM);
        errorLabelData.left = new FormAttachment(5, 0);
        errorLabelData.right = new FormAttachment(100, 0);
        m_errorLabel.setLayoutData(errorLabelData);
        m_shell.pack();
    }

    /**
     * creates the find and the close button
     */
    private void createButtons() {
        m_findButton = new Button(m_shell, SWT.PUSH);
        m_findButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                doCallBack();
            }
        });
        m_findButton.setText(Messages.FindDialogFind);
        FormData findButtonData = new FormData();
        findButtonData.top = new FormAttachment(m_optionsGroup, 15, SWT.BOTTOM);
        findButtonData.left = new FormAttachment(20, 0);
        findButtonData.right = new FormAttachment(58, 0);
        m_findButton.setLayoutData(findButtonData);
        m_cancelButton = new Button(m_shell, SWT.NONE);
        m_cancelButton.setText(Messages.FindDialogClose);
        m_cancelButton.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                m_shell.close();
            }
        });
        FormData cancelButtonData = new FormData();
        cancelButtonData.top = new FormAttachment(m_optionsGroup, 15, SWT.BOTTOM);
        cancelButtonData.left = new FormAttachment(62, 0);
        cancelButtonData.right = new FormAttachment(100, 0);
        m_cancelButton.setLayoutData(cancelButtonData);
    }

    /**
     * creates the help link
     * borrowed from TrayDialog
     * adapted for FormLayout
     */
    private void createHelpLink() {
        m_helpLink = new Link(m_shell, SWT.WRAP | SWT.NO_FOCUS);
        m_helpLink.setText("<a>" + IDialogConstants.HELP_LABEL + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$
        m_helpLink.setToolTipText(IDialogConstants.HELP_LABEL);
        FormData helpLinkData = new FormData();
        helpLinkData.bottom = new FormAttachment(m_findButton, 0, SWT.BOTTOM);
        helpLinkData.left = new FormAttachment(0, 0);
        helpLinkData.right = new FormAttachment(16, 0);
        m_helpLink.setLayoutData(helpLinkData);
        m_helpLink.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                helpPressed();
            }
        });
    }

    /**
     * performs the the action for the help link
     * borrowed and adapted from TrayDialog
     */
    private void helpPressed() {
        if (m_shell != null) {
            Control c = m_shell.getDisplay().getFocusControl();
            while (c != null) {
                if (c.isListening(SWT.Help)) {
                    c.notifyListeners(SWT.Help, new Event());
                    break;
                }
                c = c.getParent();
            }
        }
    }

    /**
     * creates the Direction Group
     */
    private void createDirectionGroup() {
        m_directionGroup = new Group(m_shell, SWT.NONE);
        m_directionGroup.setText(Messages.FindDialogDirection);
        FormLayout groupLayout = new FormLayout();
        m_directionGroup.setLayout(groupLayout);
        groupLayout.marginHeight = 5;
        groupLayout.marginWidth = 5;
        FormData groupDirectionData = new FormData();
        groupDirectionData.top = new FormAttachment(m_searchStringCombo, 15, SWT.BOTTOM);
        groupDirectionData.right = new FormAttachment(100, 0);
        groupDirectionData.left = new FormAttachment(0, 0);
        m_directionGroup.setLayoutData(groupDirectionData);
        m_findForwardButton = new Button(m_directionGroup, SWT.RADIO);
        m_findForwardButton.setText(Messages.FindDialogForward);
        m_findForwardButton.setSelection(lastforward);
        FormData findForwardData = new FormData();
        findForwardData.left = new FormAttachment(0, 0);
        findForwardData.right = new FormAttachment(48, 0);
        m_findForwardButton.setLayoutData(findForwardData);
        m_findBackwardButton = new Button(m_directionGroup, SWT.RADIO);
        m_findBackwardButton.setText(Messages.FindDialogBackward);
        m_findBackwardButton.setSelection(!lastforward);
        FormData findBackwardData = new FormData();
        findBackwardData.left = new FormAttachment(52, 0);
        findBackwardData.right = new FormAttachment(100, 0);
        m_findBackwardButton.setLayoutData(findBackwardData);
    }

    /**
     * creates the Direction Group
     */
    private void createOptionsGroup() {
        m_optionsGroup = new Group(m_shell, SWT.NONE);
        m_optionsGroup.setText(Messages.FindDialogOptions);
        FormData groupDirectionData = new FormData();
        groupDirectionData.top = new FormAttachment(m_directionGroup, 10, SWT.BOTTOM);
        groupDirectionData.right = new FormAttachment(100, 0);
        groupDirectionData.left = new FormAttachment(0, 0);
        m_optionsGroup.setLayoutData(groupDirectionData);
        FormLayout layout = new FormLayout();
        layout.marginHeight = 5;
        layout.marginWidth = 5;
        m_optionsGroup.setLayout(layout);
        m_caseSensitivCheck = new Button(m_optionsGroup, SWT.CHECK);
        m_caseSensitivCheck.setText(Messages.FindDialogCaseSen);
        m_caseSensitivCheck.setSelection(lastcasesensitive);
        FormData sensitiveData = new FormData();
        sensitiveData.left = new FormAttachment(0, 0);
        sensitiveData.right = new FormAttachment(48, 0);
        m_caseSensitivCheck.setLayoutData(sensitiveData);
        m_wrapSearchCheck = new Button(m_optionsGroup, SWT.CHECK);
        m_wrapSearchCheck.setText(Messages.FindDialogWrap);
        m_wrapSearchCheck.setSelection(lastwrapsearch);
        FormData warpSearchData = new FormData();
        warpSearchData.left = new FormAttachment(52, 0);
        warpSearchData.right = new FormAttachment(100, 0);
        m_wrapSearchCheck.setLayoutData(warpSearchData);
        m_useRegExCheck = new Button(m_optionsGroup, SWT.CHECK);
        m_useRegExCheck.setText(Messages.FindDialogRegEx);
        m_useRegExCheck.setSelection(lastregex);
        FormData regExData = new FormData();
        regExData.left = new FormAttachment(0, 0);
        regExData.top = new FormAttachment(m_wrapSearchCheck, 5, SWT.BOTTOM);
        m_useRegExCheck.setLayoutData(regExData);
    }

    /**
     * opens the shell
     */
    public void open() {
        m_shell.open();
    }

    /**
     * @return true if shell is disposed
     */
    public boolean isDisposed() {
        return (m_shell == null) ? true : m_shell.isDisposed();
    }

    /**
     * calls find method on callback object
     */
    private void doCallBack() {
        if (!isValidPart(m_treeViewContainer)) {
            m_shell.close();
            return;
        }
        final String searchText = m_searchStringCombo.getText();

        lastcasesensitive = m_caseSensitivCheck.getSelection();
        lastregex = m_useRegExCheck.getSelection();
        lastwrapsearch = m_wrapSearchCheck.getSelection();
        lastforward = m_findForwardButton.getSelection();
        if (RECENT.contains(searchText)) {
            RECENT.remove(searchText);
        }
        m_findButton.setEnabled(false);
        m_errorLabel.setText(StringConstants.EMPTY);
        if (RECENT.size() > 4) {
            RECENT.remove(RECENT.size() - 1);
        }
        RECENT.add(0, searchText);

        ISelection treeSelection = getActiveTreeViewer().getSelection();
        final Object nodeToStart = treeSelection instanceof IStructuredSelection
                ? ((IStructuredSelection) treeSelection).getFirstElement()
                : null;
        final String jobName = Messages.UIJobFindingNodes;
        Job findingNodes = new Job(jobName) {
            protected IStatus run(IProgressMonitor monitor) {
                monitor.beginTask(jobName, IProgressMonitor.UNKNOWN);
                final boolean result = find(searchText, lastcasesensitive, lastregex, lastwrapsearch, lastforward,
                        nodeToStart, monitor);
                Plugin.getDisplay().syncExec(new Runnable() {
                    public void run() {
                        if (!m_errorLabel.isDisposed()) {
                            if (!result) {
                                m_errorLabel.setText(Messages.FindDialogError);
                            } else {
                                m_errorLabel.setText(StringConstants.EMPTY);
                            }
                            m_searchStringCombo.setItems(RECENT.toArray(new String[RECENT.size()]));
                            m_searchStringCombo.select(0);
                            m_searchStringCombo.setFocus();
                            m_findButton.setEnabled(true);
                        }
                    }
                });
                monitor.done();
                return Status.OK_STATUS;
            }
        };
        JobUtils.executeJob(findingNodes, null);
    }

    /**
     * @param queryString queryString
     * @param caseSensitive caseSensitive
     * @param useRegex useRegex
     * @param wrapSearch wrapSearch
     * @param forward forward
     * @param nodeToStart
     *            the node to start the search; may be null --> root is used as
     *            search start point
     * @param monitor the progress monitor to use to communicate progress
     * @return boolean
     */
    private boolean find(String queryString, boolean caseSensitive, boolean useRegex, boolean wrapSearch,
            boolean forward, Object nodeToStart, IProgressMonitor monitor) {
        final Object node = findGuiNode(queryString, caseSensitive, useRegex, wrapSearch, forward, nodeToStart,
                monitor);
        if (node != null) {
            // I don't know why it doesn't always work the first
            // time, but calling this method twice seems to fix the problem
            Plugin.getDisplay().syncExec(new Runnable() {
                public void run() {
                    UINodeBP.selectNodeInTree(node, getActiveTreeViewer());
                }
            });
            return true;
        }
        return false;
    }

    /**
     * 
     * @param treeViewerContainer The container to check.
     * @return <code>true</code> if the tree of the given container can be 
     *         operated on (i.e. not <code>null</code>, not disposed, etc.). 
     *         Otherwise, <code>false</code>.
     */
    private boolean isValidPart(ITreeViewerContainer treeViewerContainer) {
        return !(treeViewerContainer == null || treeViewerContainer.getTreeViewer() == null
                || treeViewerContainer.getTreeViewer().getTree().isDisposed());
    }

    /**
     * First flattens INodePO hierarchy to list, then iterate over list
     * 
     * @param queryString
     *            queryString
     * @param caseSensitive
     *            caseSensitive
     * @param useRegex
     *            useRegex
     * @param wrapSearch
     *            wrapSearch
     * @param forward
     *            forward
     * @param nodeToStart
     *            the node to start the search; may be null --> root is used as
     *            search start point
     * @param monitor the progress monitor to use to communicate progress
     * @return NODE
     */
    private Object findGuiNode(String queryString, boolean caseSensitive, boolean useRegex, boolean wrapSearch,
            boolean forward, Object nodeToStart, IProgressMonitor monitor) {
        TextFinder searcher = new TextFinder(queryString, Operation.create(caseSensitive, useRegex));
        if (monitor.isCanceled()) {
            return null;
        }
        if (wrapSearch || nodeToStart != null) {
            TreeViewerIterator iterator = new TreeViewerIterator(getActiveTreeViewer(), nodeToStart, forward);
            int noOfElements = iterator.getElements().size();
            monitor.beginTask(
                    Messages.SearchingIn + StringConstants.SPACE + noOfElements + StringConstants.SPACE
                            + Messages.Elements + StringConstants.DOT + StringConstants.DOT + StringConstants.DOT,
                    noOfElements);
            ILabelProvider labelProv = (ILabelProvider) getActiveTreeViewer().getLabelProvider();
            while (iterator.hasNext()) {
                monitor.worked(1);
                if (monitor.isCanceled()) {
                    return null;
                }
                Object o = iterator.next();
                if (searcher.matchSearchString(labelProv.getText(o))) {
                    monitor.done();
                    return o;
                }
            }
        }
        return null;
    }

    /**
     * Listener method reacting on dispose events
     * @param e DisposeEvent
     */
    public void widgetDisposed(DisposeEvent e) {
        closeShell();
    }

    /**
     * Closes the shell for this dialog, if it is not already closed.
     */
    private void closeShell() {
        if (!isDisposed()) {
            m_shell.close();
        }
    }

    /**
     * Method for setting acutal part
     * @param viewContainer TreeViewContainer
     */
    public void setTreeViewContainer(ITreeViewerContainer viewContainer) {

        // Remove old listener, if necessary 
        if (isValidPart(m_treeViewContainer)) {
            m_treeViewContainer.getTreeViewer().getTree().removeDisposeListener(this);
        }

        // Add new listener
        if (isValidPart(viewContainer)) {
            viewContainer.getTreeViewer().getTree().addDisposeListener(this);
        }

        m_treeViewContainer = viewContainer;
    }

    /**
     * 
     * @return the tree viewer on which operations should be performed, or 
     *         <code>null</code> if no such tree viewer exists.
     */
    private TreeViewer getActiveTreeViewer() {
        if (m_treeViewContainer instanceof IMultiTreeViewerContainer) {
            return ((IMultiTreeViewerContainer) m_treeViewContainer).getActiveTreeViewer();
        }

        return m_treeViewContainer.getTreeViewer();
    }
}