com.nokia.carbide.search.system.internal.ui.text.TextSearchPage.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.carbide.search.system.internal.ui.text.TextSearchPage.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation 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:
 *     IBM Corporation - initial API and implementation
 *     Juerg Billeter, juergbi@ethz.ch - 47136 Search view should show match objects
 *     Ulrich Etter, etteru@ethz.ch - 47136 Search view should show match objects
 *     Roman Fuchs, fuchsro@ethz.ch - 47136 Search view should show match objects
 *******************************************************************************/
package com.nokia.carbide.search.system.internal.ui.text;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.fieldassist.ComboContentAdapter;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.FindReplaceDocumentAdapterContentProposalProvider;

import org.eclipse.search.ui.ISearchPage;
import org.eclipse.search.ui.ISearchPageContainer;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.ide.FileStoreEditorInput;

import com.nokia.carbide.search.system.internal.ui.ISearchHelpContextIds;
import com.nokia.carbide.search.system.internal.ui.SearchMessages;
import com.nokia.carbide.search.system.internal.ui.SearchPlugin;
import com.nokia.carbide.search.system.internal.ui.util.FileTypeEditor;
import com.nokia.carbide.search.system.internal.ui.util.SWTUtil;
import com.nokia.carbide.search.system.ui.ISearchQuery;
import com.nokia.carbide.search.system.ui.ISearchResultPage;
import com.nokia.carbide.search.system.ui.ISearchResultViewPart;
import com.nokia.carbide.search.system.ui.NewSearchUI;
import com.nokia.carbide.search.system.ui.text.FileTextSearchScope;
import com.nokia.carbide.search.system.ui.text.TextSearchQueryProvider;
import com.nokia.carbide.search.system.ui.text.TextSearchQueryProvider.TextSearchInput;

public class TextSearchPage extends DialogPage implements ISearchPage {//, IReplacePage {

    private static final int HISTORY_SIZE = 12;
    public static final String EXTENSION_POINT_ID = "com.nokia.carbide.search.system.internal.ui.text.TextSearchPage"; //$NON-NLS-1$

    // Dialog store id constants
    private static final String PAGE_NAME = "TextSearchPage"; //$NON-NLS-1$
    private static final String STORE_CASE_SENSITIVE = "CASE_SENSITIVE"; //$NON-NLS-1$
    private static final String STORE_IS_REG_EX_SEARCH = "REG_EX_SEARCH"; //$NON-NLS-1$
    private static final String STORE_SEARCH_DERIVED = "SEARCH_DERIVED"; //$NON-NLS-1$
    private static final String STORE_ADDED_FILENAMES = "ADDED_FILENAMES"; //$NON-NLS-1$
    private static final String STORE_ADDED_FOLDERS = "ADDED_FOLDERS"; //$NON-NLS-1$
    private static final String STORE_INCLUDE_SUBFOLDERS = "INCLUDE_SUBFOLDERS"; //$NON-NLS-1$
    private static final String STORE_INCLUDE_HIDDEN = "INCLUDE_HIDDEN"; //$NON-NLS-1$
    private static final String STORE_HISTORY = "HISTORY"; //$NON-NLS-1$
    private static final String STORE_HISTORY_SIZE = "HISTORY_SIZE"; //$NON-NLS-1$

    // a list to hold previous search data
    private ArrayList<SearchPatternData> fPreviousSearchPatterns = new ArrayList<SearchPatternData>();

    // search utility
    //   private SystemSearchUtil fUtil;

    // flag to indicate whether showing the dialog for the first time
    private boolean fFirstTime = true;

    private boolean fIsCaseSensitive;
    private boolean fIsRegExSearch;
    private boolean fIncludeSubfolders;
    private boolean fIncludeHidden;
    private boolean fSearchDerived = false;
    private boolean fIncludeArchives = false;

    private ArrayList<String> fFileExtensions = new ArrayList<String>();
    private ArrayList<String> fFolders = new ArrayList<String>();

    private Combo fPattern;
    private Button fIsCaseSensitiveCheckbox;

    private Combo fExtensions;
    private Button fIsRegExCheckbox;
    private CLabel fStatusLabel;

    private Combo fFolder;
    private Button fIncludeSubfoldersCheckbox;
    private Button fIncludeHiddenCheckbox;
    private Button fIncludeArchivesCheckbox;

    // folder name editor
    private FolderNameEditor folderNameEditor;

    // search page fContainer
    private ISearchPageContainer fContainer;

    private FileTypeEditor fFileTypeEditor;

    private ContentAssistCommandAdapter fPatterFieldContentAssist;

    private static class SearchPatternData {
        public final boolean isCaseSensitive;
        public final boolean isRegExSearch;
        public final String textPattern;
        public final String[] fileNamePatterns;
        public final int scope;
        public final String folderName;
        public final boolean includeSubfolders;
        public final boolean includeHidden;
        public final boolean includeArchives;

        private static final String STORE_DATA_TEXT_PATTERN = "textPattern"; //$NON-NLS-1$
        private static final String STORE_DATA_CASE_SENSITIVE = "caseSensitive"; //$NON-NLS-1$
        private static final String STORE_DATA_STRING_REGEX = "regExSearch"; //$NON-NLS-1$
        private static final String STORE_DATA_FILE_NAMES = "fileNames"; //$NON-NLS-1$
        private static final String STORE_DATA_SCOPE = "scope"; //$NON-NLS-1$
        private static final String STORE_DATA_FOLDER_NAME = "folderName"; //$NON-NLS-1$
        private static final String STORE_DATA_INCLUDE_SUBFOLDERS = "includeSubfolders"; //$NON-NLS-1$
        private static final String STORE_DATA_INCLUDE_HIDDEN = "includeHidden"; //$NON-NLS-1$
        private static final String STORE_DATA_INCLUDE_ARCHIVES = "includeArchives"; //$NON-NLS-1$

        public SearchPatternData(String textPattern, boolean isCaseSensitive, boolean isRegExSearch,
                String[] fileNamePatterns, int scope, String folderName, boolean includeSubfolders,
                boolean includeHidden, boolean includeArchives) {
            Assert.isNotNull(fileNamePatterns);
            this.isCaseSensitive = isCaseSensitive;
            this.isRegExSearch = isRegExSearch;
            this.textPattern = textPattern;
            this.fileNamePatterns = fileNamePatterns;
            this.scope = scope;
            this.folderName = folderName; // can be null
            this.includeSubfolders = includeSubfolders;
            this.includeHidden = includeHidden;
            this.includeArchives = includeArchives;
        }

        public void store(IDialogSettings settings) {
            settings.put(STORE_DATA_CASE_SENSITIVE, isCaseSensitive); //$NON-NLS-1$
            settings.put(STORE_DATA_STRING_REGEX, isRegExSearch); //$NON-NLS-1$
            settings.put(STORE_DATA_TEXT_PATTERN, textPattern); //$NON-NLS-1$
            settings.put(STORE_DATA_FILE_NAMES, fileNamePatterns); //$NON-NLS-1$
            settings.put(STORE_DATA_SCOPE, scope); //$NON-NLS-1$
            settings.put(STORE_DATA_FOLDER_NAME, folderName);
            settings.put(STORE_DATA_INCLUDE_SUBFOLDERS, includeSubfolders);
            settings.put(STORE_DATA_INCLUDE_HIDDEN, includeHidden);
            settings.put(STORE_DATA_INCLUDE_ARCHIVES, includeArchives);
        }

        public static SearchPatternData create(IDialogSettings settings) {
            String textPattern = settings.get(STORE_DATA_TEXT_PATTERN); //$NON-NLS-1$
            String[] fileNamePatterns = settings.getArray(STORE_DATA_FILE_NAMES); //$NON-NLS-1$
            if (fileNamePatterns == null) {
                fileNamePatterns = new String[0];
            }
            String folderName = settings.get(STORE_DATA_FOLDER_NAME);
            try {
                int scope = settings.getInt(STORE_DATA_SCOPE); //$NON-NLS-1$
                boolean isRegExSearch = settings.getBoolean(STORE_DATA_STRING_REGEX); //$NON-NLS-1$
                boolean isCaseSensitive = settings.getBoolean(STORE_DATA_CASE_SENSITIVE); //$NON-NLS-1$
                boolean includeSubfolders = settings.getBoolean(STORE_DATA_INCLUDE_SUBFOLDERS); //$NON-NLS-1$
                boolean includeHidden = settings.getBoolean(STORE_DATA_INCLUDE_HIDDEN); //$NON-NLS-1$
                boolean includeArchives = settings.getBoolean(STORE_DATA_INCLUDE_ARCHIVES); //$NON-NLS-1$

                return new SearchPatternData(textPattern, isCaseSensitive, isRegExSearch, fileNamePatterns, scope,
                        folderName, includeSubfolders, includeHidden, includeArchives);
            } catch (NumberFormatException e) {
                return null;
            }
        }
    }

    private static class TextSearchPageInput extends TextSearchInput {

        private final String fSearchText;
        private final boolean fIsCaseSensitive;
        private final boolean fIsRegEx;
        private final FileTextSearchScope fScope;

        public TextSearchPageInput(String searchText, boolean isCaseSensitive, boolean isRegEx,
                FileTextSearchScope scope) {
            fSearchText = searchText;
            fIsCaseSensitive = isCaseSensitive;
            fIsRegEx = isRegEx;
            fScope = scope;
        }

        public String getSearchText() {
            return fSearchText;
        }

        public boolean isCaseSensitiveSearch() {
            return fIsCaseSensitive;
        }

        public boolean isRegExSearch() {
            return fIsRegEx;
        }

        public FileTextSearchScope getScope() {
            return fScope;
        }
    }

    //---- Action Handling ------------------------------------------------

    private ISearchQuery newQuery() throws CoreException {
        SearchPatternData data = getPatternData();
        TextSearchPageInput input = new TextSearchPageInput(data.textPattern, data.isCaseSensitive,
                data.isRegExSearch, createTextSearchScope(data.folderName, data.includeSubfolders,
                        data.includeHidden, data.includeArchives));
        return TextSearchQueryProvider.getPreferred().createQuery(input);
    }

    public boolean performAction() {
        try {
            NewSearchUI.runQueryInBackground(newQuery());
        } catch (CoreException e) {
            ErrorDialog.openError(getShell(), SearchMessages.TextSearchPage_replace_searchproblems_title,
                    SearchMessages.TextSearchPage_replace_searchproblems_message, e.getStatus());
            return false;
        }
        return true;
    }

    /* (non-Javadoc)
     * @see com.nokia.carbide.search.system.ui.IReplacePage#performReplace()
     */
    public boolean performReplace() {
        try {
            IStatus status = NewSearchUI.runQueryInForeground(getContainer().getRunnableContext(), newQuery());
            if (status.matches(IStatus.CANCEL)) {
                return false;
            }
            if (!status.isOK()) {
                ErrorDialog.openError(getShell(), SearchMessages.TextSearchPage_replace_searchproblems_title,
                        SearchMessages.TextSearchPage_replace_runproblem_message, status);
            }

            Display.getCurrent().asyncExec(new Runnable() {
                public void run() {
                    ISearchResultViewPart view = NewSearchUI.activateSearchResultView();
                    if (view != null) {
                        ISearchResultPage page = view.getActivePage();
                        if (page instanceof FileSearchPage) {
                            FileSearchPage filePage = (FileSearchPage) page;
                            Object[] elements = filePage.getInput().getElements();
                            IFileStore[] files = new IFileStore[elements.length];
                            System.arraycopy(elements, 0, files, 0, files.length);
                            new ReplaceAction2(filePage, files).run();
                        }
                    }
                }
            });
            return true;
        } catch (CoreException e) {
            ErrorDialog.openError(getShell(), SearchMessages.TextSearchPage_replace_searchproblems_title,
                    SearchMessages.TextSearchPage_replace_querycreationproblem_message, e.getStatus());
            return false;
        }
    }

    private String getPattern() {
        return fPattern.getText();
    }

    // system search does not use the regular scope widgets 
    private FileTextSearchScope createTextSearchScope(String folderName, boolean includeSubfolders,
            boolean includeHidden, boolean includeArchives) {
        return FileTextSearchScope.newSystemScope(folderName, getExtensions(), folderName, includeSubfolders,
                includeHidden, includeArchives);
    }

    private SearchPatternData findInPrevious(String pattern) {
        for (Iterator<SearchPatternData> iter = fPreviousSearchPatterns.iterator(); iter.hasNext();) {
            SearchPatternData element = (SearchPatternData) iter.next();
            if (pattern.equals(element.textPattern)) {
                return element;
            }
        }
        return null;
    }

    /**
     * Return search pattern data and update previous searches.
     * An existing entry will be updated.
     * @return the search pattern data
     */
    private SearchPatternData getPatternData() {
        SearchPatternData match = findInPrevious(fPattern.getText());
        if (match != null) {
            fPreviousSearchPatterns.remove(match);
        }
        match = new SearchPatternData(getPattern(), isCaseSensitive(), fIsRegExCheckbox.getSelection(),
                getExtensions(), com.nokia.carbide.search.system.ui.ISearchPageContainer.SYSTEM_SCOPE,
                fFolder.getText(), fIncludeSubfoldersCheckbox.getSelection(), fIncludeHiddenCheckbox.getSelection(),
                fIncludeArchivesCheckbox != null ? fIncludeArchivesCheckbox.getSelection() : false);
        fPreviousSearchPatterns.add(0, match);
        return match;
    }

    private String[] getPreviousExtensions() {
        return (String[]) fFileExtensions.toArray(new String[fFileExtensions.size()]);
    }

    private String[] getPreviousSearchPatterns() {
        int size = fPreviousSearchPatterns.size();
        String[] patterns = new String[size];
        for (int i = 0; i < size; i++)
            patterns[i] = ((SearchPatternData) fPreviousSearchPatterns.get(i)).textPattern;
        return patterns;
    }

    private String[] getPreviousFolders() {
        return (String[]) fFolders.toArray(new String[fFolders.size()]);
    }

    private String[] getExtensions() {
        return fFileTypeEditor.getFileTypes();
    }

    private boolean isCaseSensitive() {
        return fIsCaseSensitiveCheckbox.getSelection();
    }

    /*
     * Implements method from IDialogPage
     */
    public void setVisible(boolean visible) {
        if (visible && fPattern != null) {
            if (fFirstTime) {
                fFirstTime = false;
                // Set item and text here to prevent page from resizing
                fPattern.setItems(getPreviousSearchPatterns());

                String[] values = getPreviousExtensions();
                if (values != null)
                    fExtensions.setItems(values);
                values = getPreviousFolders();
                if (values != null)
                    fFolder.setItems(values);

                if (!initializePatternControl()) {
                    fPattern.select(0);
                    fExtensions.setText("*"); //$NON-NLS-1$
                    fFolder.select(0);
                    fIncludeSubfoldersCheckbox.setSelection(true);
                    fIncludeSubfolders = true;
                    handleWidgetSelected();
                }
            }
            fPattern.setFocus();
        }
        updateOKStatus();
        super.setVisible(visible);
    }

    final void updateOKStatus() {
        boolean regexStatus = validateRegex();
        boolean hasFilePattern = fExtensions.getText().length() > 0;
        getContainer().setPerformActionEnabled(isFolderNameValid() && regexStatus && hasFilePattern);
    }

    //---- Widget creation ------------------------------------------------

    public void createControl(Composite parent) {

        // compute horizontal and vertical units
        initializeDialogUnits(parent);

        // read configuration
        readConfiguration();

        // main composite
        Composite result = new Composite(parent, SWT.NONE);
        result.setFont(parent.getFont());
        GridLayout layout = new GridLayout(2, false);
        result.setLayout(layout);

        // create controls for search string
        addTextPatternControls(result);

        Label separator = new Label(result, SWT.NONE);
        separator.setVisible(false);
        GridData data = new GridData(GridData.FILL, GridData.FILL, false, false, 2, 1);
        data.heightHint = convertHeightInCharsToPixels(1) / 3;
        separator.setLayoutData(data);

        // create controls for file names
        addFileNameControls(result);

        separator = new Label(result, SWT.NONE);
        separator.setVisible(false);
        data = new GridData(GridData.FILL, GridData.FILL, false, false, 2, 1);
        data.heightHint = convertHeightInCharsToPixels(1) / 3;
        separator.setLayoutData(data);

        // create controls for folder name
        addFolderControls(result);

        setControl(result);
        Dialog.applyDialogFont(result);
        PlatformUI.getWorkbench().getHelpSystem().setHelp(result, ISearchHelpContextIds.TEXT_SEARCH_PAGE);
    }

    // inner class to handle folder name editing
    private class FolderNameEditor extends SelectionAdapter implements DisposeListener {

        // holds info for each item in the folder combo
        private Combo folderCombo;
        private Button browseButton;

        /**
         * Constructor for folder name editor.
         * @param folderCombo the folder name combo.
         * @param browseButton the folder browse button.
         */
        private FolderNameEditor(Combo folderCombo, Button browseButton) {
            this.folderCombo = folderCombo;
            this.browseButton = browseButton;

            // add dispose listeners to both the combo and the button
            // we make them null when they are disposed for cleanup to occur
            folderCombo.addDisposeListener(this);
            browseButton.addDisposeListener(this);

            // add selection listener to the browse button
            browseButton.addSelectionListener(this);
        }

        /**
         * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
         */
        public void widgetDisposed(DisposeEvent e) {

            if (e.widget == folderCombo) {
                folderCombo = null;
            } else if (e.widget == browseButton) {
                browseButton = null;
            }
        }

        /**
         * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
         */
        public void widgetSelected(SelectionEvent e) {

            if (e.widget == browseButton) {

                // get the shell from the page
                Shell shell = TextSearchPage.this.getShell();

                DirectoryDialog folder = new DirectoryDialog(shell);
                String filterPath = fFolder.getText();
                if (filterPath != null)
                    folder.setFilterPath(filterPath);
                folder.setMessage(SearchMessages.TextSearchPage_browseToFolder);
                String selectedFilePath = folder.open();
                if (selectedFilePath != null) {
                    setFolderText(selectedFilePath);
                }
            }
        }

        /**
         * Sets the folder name combo text. Also sets the profile name, connection name and folder path.
         * @param profileName the profile name.
         */
        private void setFolderText(String folderPath) {
            fFolder.setText(folderPath);
        }
    }

    private boolean validateRegex() {
        if (fIsRegExCheckbox.getSelection()) {
            try {
                Pattern.compile(fPattern.getText());
            } catch (PatternSyntaxException e) {
                String locMessage = e.getLocalizedMessage();
                int i = 0;
                while (i < locMessage.length() && "\n\r".indexOf(locMessage.charAt(i)) == -1) { //$NON-NLS-1$
                    i++;
                }
                statusMessage(true, locMessage.substring(0, i)); // only take first line
                return false;
            }
            statusMessage(false, ""); //$NON-NLS-1$
        } else {
            statusMessage(false, SearchMessages.SearchPage_containingText_hint);
        }
        return true;
    }

    /**
     * Returns whether folder name is valid.
     * @return <code>true</code> if folder name is not <code>null</code> or empty, <code>false</code> otherwise.
     */
    private boolean isFolderNameValid() {

        String folderName = fFolder.getText();

        if (folderName == null || folderName.trim().length() == 0) {
            return false;
        }

        File file = new File(folderName);

        return file.exists() && file.isDirectory();
    }

    private void addTextPatternControls(Composite group) {
        // grid layout with 2 columns

        // Info text      
        Label label = new Label(group, SWT.LEAD);
        label.setText(SearchMessages.TextSearchPage_searchString);
        label.setToolTipText(SearchMessages.TextSearchPage_searchStringToolTip);
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        label.setFont(group.getFont());

        // Pattern combo
        fPattern = new Combo(group, SWT.SINGLE | SWT.BORDER);
        fPattern.setToolTipText(SearchMessages.TextSearchPage_enterOrSelectToolTip);
        // Not done here to prevent page from resizing
        // fPattern.setItems(getPreviousSearchPatterns());

        fPattern.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                handleWidgetSelected();
                updateOKStatus();
            }
        });
        // add some listeners for regex syntax checking
        fPattern.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                updateOKStatus();
            }
        });
        fPattern.setFont(group.getFont());
        GridData data = new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1);
        data.widthHint = convertWidthInCharsToPixels(50);
        fPattern.setLayoutData(data);

        ComboContentAdapter contentAdapter = new ComboContentAdapter();
        FindReplaceDocumentAdapterContentProposalProvider findProposer = new FindReplaceDocumentAdapterContentProposalProvider(
                true);
        fPatterFieldContentAssist = new ContentAssistCommandAdapter(fPattern, contentAdapter, findProposer,
                ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, new char[] { '\\', '[', '(' }, true);
        fPatterFieldContentAssist.setEnabled(fIsRegExSearch);

        fIsCaseSensitiveCheckbox = new Button(group, SWT.CHECK);
        fIsCaseSensitiveCheckbox.setText(SearchMessages.SearchPage_caseSensitive);
        fIsCaseSensitiveCheckbox.setToolTipText(SearchMessages.TextSearchPage_caseSensitiveToolTip);
        fIsCaseSensitiveCheckbox.setSelection(fIsCaseSensitive);

        fIsCaseSensitiveCheckbox.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                fIsCaseSensitive = fIsCaseSensitiveCheckbox.getSelection();
            }
        });
        fIsCaseSensitiveCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        fIsCaseSensitiveCheckbox.setFont(group.getFont());

        // Text line which explains the special characters
        fStatusLabel = new CLabel(group, SWT.LEAD);
        fStatusLabel.setToolTipText("");
        fStatusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        fStatusLabel.setFont(group.getFont());
        fStatusLabel.setAlignment(SWT.LEFT);
        fStatusLabel.setText(SearchMessages.SearchPage_containingText_hint);

        // RegEx checkbox
        fIsRegExCheckbox = new Button(group, SWT.CHECK);
        fIsRegExCheckbox.setText(SearchMessages.SearchPage_regularExpression);
        fIsRegExCheckbox.setSelection(fIsRegExSearch);

        fIsRegExCheckbox.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                fIsRegExSearch = fIsRegExCheckbox.getSelection();
                updateOKStatus();

                writeConfiguration();
                fPatterFieldContentAssist.setEnabled(fIsRegExSearch);
            }
        });
        fIsRegExCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        fIsRegExCheckbox.setFont(group.getFont());
    }

    private void handleWidgetSelected() {
        int selectionIndex = fPattern.getSelectionIndex();
        if (selectionIndex < 0 || selectionIndex >= fPreviousSearchPatterns.size())
            return;

        SearchPatternData patternData = (SearchPatternData) fPreviousSearchPatterns.get(selectionIndex);
        if (patternData == null || !fPattern.getText().equals(patternData.textPattern))
            return;

        // set case sensitive
        fIsCaseSensitiveCheckbox.setSelection(patternData.isCaseSensitive);

        // set string regex
        fIsRegExCheckbox.setSelection(patternData.isRegExSearch);

        // set search string properties
        fPattern.setText(patternData.textPattern);

        // set types list
        fFileTypeEditor.setFileTypes(patternData.fileNamePatterns);

        // set working sets
        getContainer().setSelectedScope(patternData.scope);

        // set the system folder properties
        folderNameEditor.setFolderText(patternData.folderName);

        // set search subfolders
        fIncludeSubfoldersCheckbox.setSelection(patternData.includeSubfolders);

        // set search hidden files
        fIncludeHiddenCheckbox.setSelection(patternData.includeHidden);

        // set search archives
        //      fIncludeArchivesCheckbox.setSelection(patternData.includeArchives);
    }

    private boolean initializePatternControl() {
        ISelection selection = getSelection();
        if (selection instanceof ITextSelection && !selection.isEmpty()) {
            String text = ((ITextSelection) selection).getText();
            if (text != null) {
                fPattern.setText(insertEscapeChars(text));

                if (getPreviousExtensions().length > 0) {
                    fExtensions.setText(getPreviousExtensions()[0]);
                } else {
                    String extension = getExtensionFromEditor();
                    if (extension != null)
                        fExtensions.setText(extension);
                    else
                        fExtensions.setText("*"); //$NON-NLS-1$
                }

                if (getPreviousFolders().length > 0) {
                    fFolder.setText(getPreviousFolders()[0]);
                }
                return true;
            }
        }
        return false;
    }

    private String insertEscapeChars(String text) {
        if (text == null || text.equals("")) //$NON-NLS-1$
            return ""; //$NON-NLS-1$
        StringBuffer sbIn = new StringBuffer(text);
        BufferedReader reader = new BufferedReader(new StringReader(text));
        int lengthOfFirstLine = 0;
        try {
            lengthOfFirstLine = reader.readLine().length();
        } catch (IOException ex) {
            return ""; //$NON-NLS-1$
        }
        StringBuffer sbOut = new StringBuffer(lengthOfFirstLine + 5);
        int i = 0;
        while (i < lengthOfFirstLine) {
            char ch = sbIn.charAt(i);
            if (ch == '*' || ch == '?' || ch == '\\')
                sbOut.append("\\"); //$NON-NLS-1$
            sbOut.append(ch);
            i++;
        }
        return sbOut.toString();
    }

    private String getExtensionFromEditor() {
        IEditorPart ep = SearchPlugin.getActivePage().getActiveEditor();
        if (ep != null) {
            Object elem = ep.getEditorInput();
            if (elem instanceof IFileEditorInput) {
                String extension = ((IFileEditorInput) elem).getFile().getFileExtension();
                if (extension == null)
                    return ((IFileEditorInput) elem).getFile().getName();
                return "*." + extension; //$NON-NLS-1$
            } else if (elem instanceof FileStoreEditorInput) {
                FileStoreEditorInput input = (FileStoreEditorInput) elem;
                URI uri = input.getURI();
                String extension = uri.getPath();
                if (extension.contains(".")) { //$NON-NLS-1$
                    extension = extension.substring(extension.lastIndexOf('.'));
                } else if (extension.replace('\\', '/').contains("/")) { //$NON-NLS-1$
                    extension = extension.substring(extension.replace('\\', '/').lastIndexOf('/'));
                }

            }
        }
        return null;
    }

    private void addFileNameControls(Composite group) {
        // grid layout with 2 columns

        // Line with label, combo and button
        Label label = new Label(group, SWT.LEAD);
        label.setText(SearchMessages.SearchPage_fileNamePatterns_text);
        label.setToolTipText(SearchMessages.TextSearchPage_fileNamePatterns);
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        label.setFont(group.getFont());

        fExtensions = new Combo(group, SWT.SINGLE | SWT.BORDER);
        fExtensions.setToolTipText(SearchMessages.TextSearchPage_enterOrSelectFileNamePatternsToolTip);

        if (getPreviousExtensions().length > 0) {
            fExtensions.setText(getPreviousExtensions()[0]);
        }

        fExtensions.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                updateOKStatus();
            }
        });
        GridData data = new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1);
        data.widthHint = convertWidthInCharsToPixels(50);
        fExtensions.setLayoutData(data);
        fExtensions.setFont(group.getFont());

        Button button = new Button(group, SWT.PUSH);
        button.setText(SearchMessages.SearchPage_browse);
        GridData gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1);
        gridData.widthHint = SWTUtil.getButtonWidthHint(button);
        button.setLayoutData(gridData);
        button.setFont(group.getFont());

        fFileTypeEditor = new FileTypeEditor(fExtensions, button);

        // Text line which explains the special characters
        Label description = new Label(group, SWT.LEAD);
        description.setText(SearchMessages.SearchPage_fileNamePatterns_hint);
        description.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        description.setFont(group.getFont());
    }

    /**
     * Adds controls to specify folder name.
     */
    private void addFolderControls(Composite group) {
        // grid layout with 2 columns

        // Line with label, combo and button
        Label label = new Label(group, SWT.LEFT);
        label.setText(SearchMessages.TextSearchPage_folder);
        label.setToolTipText(SearchMessages.TextSearchPage_folderPath);
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
        label.setFont(group.getFont());

        fFolder = new Combo(group, SWT.SINGLE | SWT.BORDER);
        fFolder.setToolTipText(SearchMessages.TextSearchPage_folderPathToolTip);
        fFolder.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                updateOKStatus();
            }
        });
        GridData data = new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1);
        data.widthHint = convertWidthInCharsToPixels(50);
        fFolder.setLayoutData(data);
        fFolder.setFont(group.getFont());

        // browse types button
        Button button = new Button(group, SWT.PUSH);
        button.setText(SearchMessages.TextSearchPage_browse);
        button.setToolTipText(SearchMessages.TextSearchPage_browseToolTip);
        GridData gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1);
        gridData.widthHint = SWTUtil.getButtonWidthHint(button);
        button.setLayoutData(gridData);
        button.setFont(group.getFont());

        // create the folder name editor
        folderNameEditor = new FolderNameEditor(fFolder, button);

        // line up the checkbox
        new Label(group, SWT.NONE).setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1));

        // checkbox for search in subfolders
        fIncludeSubfoldersCheckbox = new Button(group, SWT.CHECK);
        fIncludeSubfoldersCheckbox.setText(SearchMessages.TextSearchPage_searchSubfolders);
        fIncludeSubfoldersCheckbox.setToolTipText(SearchMessages.TextSearchPage_searchSubfoldersToolTip);
        fIncludeSubfoldersCheckbox.setSelection(fIncludeSubfolders);
        fIncludeSubfoldersCheckbox.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                fIncludeSubfolders = fIncludeSubfoldersCheckbox.getSelection();
                updateOKStatus();
            }
        });
        fIncludeSubfoldersCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        fIncludeSubfoldersCheckbox.setFont(group.getFont());

        // line up the checkbox
        new Label(group, SWT.NONE).setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1));

        // checkbox for search in subfolders
        fIncludeHiddenCheckbox = new Button(group, SWT.CHECK);
        fIncludeHiddenCheckbox.setText(SearchMessages.TextSearchPage_hiddenFiles);
        fIncludeHiddenCheckbox.setToolTipText(SearchMessages.TextSearchPage_hiddenFilesToolTip);
        fIncludeHiddenCheckbox.setSelection(fIncludeHidden);
        fIncludeHiddenCheckbox.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                fIncludeHidden = fIncludeHiddenCheckbox.getSelection();
                updateOKStatus();
            }
        });
        fIncludeHiddenCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        fIncludeHiddenCheckbox.setFont(group.getFont());
    }

    /**
     * Sets the search page's container.
     * @param container the container to set
     */
    public void setContainer(ISearchPageContainer container) {
        fContainer = container;
    }

    private ISearchPageContainer getContainer() {
        return fContainer;
    }

    private ISelection getSelection() {
        return fContainer.getSelection();
    }

    //--------------- Configuration handling --------------

    /* (non-Javadoc)
    * @see org.eclipse.jface.dialogs.DialogPage#dispose()
    */
    public void dispose() {
        writeConfiguration();
        super.dispose();
    }

    /**
     * Returns the page settings for this Text search page.
     * 
     * @return the page settings to be used
     */
    private IDialogSettings getDialogSettings() {
        return SearchPlugin.getDefault().getDialogSettingsSection(PAGE_NAME);
    }

    /**
     * Initializes itself from the stored page settings.
     */
    private void readConfiguration() {
        IDialogSettings s = getDialogSettings();
        fIsCaseSensitive = s.getBoolean(STORE_CASE_SENSITIVE);
        fIsRegExSearch = s.getBoolean(STORE_IS_REG_EX_SEARCH);
        fSearchDerived = s.getBoolean(STORE_SEARCH_DERIVED);
        fIncludeSubfolders = s.getBoolean(STORE_INCLUDE_SUBFOLDERS);
        fIncludeHidden = s.getBoolean(STORE_INCLUDE_HIDDEN);

        String[] values;

        values = s.getArray(STORE_ADDED_FILENAMES);
        fFileExtensions.clear();
        for (int i = 0; values != null && i < values.length; i++)
            fFileExtensions.add(values[i]);

        values = s.getArray(STORE_ADDED_FOLDERS);
        fFolders.clear();
        for (int i = 0; values != null && i < values.length; i++)
            fFolders.add(values[i]);

        try {
            int historySize = s.getInt(STORE_HISTORY_SIZE);
            for (int i = 0; i < historySize; i++) {
                IDialogSettings histSettings = s.getSection(STORE_HISTORY + i);
                if (histSettings != null) {
                    SearchPatternData data = SearchPatternData.create(histSettings);
                    if (data != null) {
                        fPreviousSearchPatterns.add(data);
                    }
                }
            }
        } catch (NumberFormatException e) {
            // ignore
        }
    }

    /**
     * Stores the current configuration in the dialog store.
     */
    private void writeConfiguration() {
        IDialogSettings s = getDialogSettings();
        s.put(STORE_CASE_SENSITIVE, fIsCaseSensitive);
        s.put(STORE_IS_REG_EX_SEARCH, fIsRegExSearch);
        s.put(STORE_SEARCH_DERIVED, fSearchDerived);
        s.put(STORE_INCLUDE_SUBFOLDERS, fIncludeSubfolders);
        s.put(STORE_INCLUDE_HIDDEN, fIncludeHidden);

        boolean matchFound;

        // add the current folder to the start of the list;
        // if it's in the list twice, remove the second time 
        String folder = fFolder.getText();
        fFolder.add(folder, 0);

        for (int i = 1; i < fFolder.getItemCount(); i++) {
            if (fFolder.getItem(i).equals(folder)) {
                fFolder.remove(i);
                break;
            }
        }

        // if there are too many members, remove the highest indexed element
        // not associated with a search pattern
        if (fFolder.getItemCount() > HISTORY_SIZE + 2) {
            matchFound = true;
            int size = fPreviousSearchPatterns.size();
            for (int j = fFolder.getItemCount() - 1; j > 0 && matchFound; j--) {
                matchFound = false;
                String currentFolder = fFolder.getItem(j);
                for (int i = 0; i < size && !matchFound; i++) {
                    SearchPatternData data = (SearchPatternData) fPreviousSearchPatterns.get(i);
                    matchFound = currentFolder.equals(data.folderName);
                }

                if (matchFound) {
                    fFolder.remove(j);
                    break;
                }
            }
        }

        s.put(STORE_ADDED_FOLDERS, fFolder.getItems());

        // add the current file extension to the start of the list;
        // if it's in the list twice, remove the second time
        String fileExtensions = fFileTypeEditor.getFileTypesString();
        fFileExtensions.add(0, fileExtensions);

        for (int i = 1; i < fFileExtensions.size(); i++) {
            if (fileExtensions.equals(fFileExtensions.get(i))) {
                fFileExtensions.remove(i);
                break;
            }
        }

        // if there are too many members, remove the highest indexed element
        // not associated with a search pattern
        if (fFileExtensions.size() >= HISTORY_SIZE + 2) {
            matchFound = true;
            int size = fPreviousSearchPatterns.size();
            for (int j = fFileExtensions.size() - 1; j > 0 && matchFound; j--) {
                matchFound = false;
                String currentExtension = fFileExtensions.get(j);
                for (int i = 0; i < size && !matchFound; i++) {
                    SearchPatternData data = (SearchPatternData) fPreviousSearchPatterns.get(i);
                    matchFound = currentExtension.equals(FileTypeEditor.typesToString(data.fileNamePatterns));
                }

                if (matchFound) {
                    fFileExtensions.remove(j);
                    break;
                }
            }
        }

        String[] extensions = new String[fFileExtensions.size()];
        for (int i = 0; i < fFileExtensions.size(); i++)
            extensions[i] = fFileExtensions.get(i);
        s.put(STORE_ADDED_FILENAMES, extensions);

        int historySize = Math.min(fPreviousSearchPatterns.size(), HISTORY_SIZE);
        s.put(STORE_HISTORY_SIZE, historySize);
        for (int i = 0; i < historySize; i++) {
            IDialogSettings histSettings = s.addNewSection(STORE_HISTORY + i);
            SearchPatternData data = ((SearchPatternData) fPreviousSearchPatterns.get(i));
            data.store(histSettings);
        }
    }

    private void statusMessage(boolean error, String message) {
        fStatusLabel.setText(message);
        if (error)
            fStatusLabel.setForeground(JFaceColors.getErrorText(fStatusLabel.getDisplay()));
        else
            fStatusLabel.setForeground(null);
    }

}