blob: 8340503eec7cce799d5f92b2283a022bf3594794 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* IBM Corp. - Rational Software - initial implementation
******************************************************************************/
/*
* Created on Jun 10, 2003
*/
package org.eclipse.cdt.internal.ui.search;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.search.ICSearchConstants;
import org.eclipse.cdt.core.search.ICSearchScope;
import org.eclipse.cdt.core.search.SearchEngine;
import org.eclipse.cdt.internal.ui.ICHelpContextIds;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.search.internal.ui.util.RowLayouter;
import org.eclipse.search.ui.ISearchPage;
import org.eclipse.search.ui.ISearchPageContainer;
import org.eclipse.search.ui.ISearchResultViewEntry;
import org.eclipse.search.ui.SearchUI;
import org.eclipse.swt.SWT;
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.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.model.IWorkbenchAdapter;
/**
* @author aniefer
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class CSearchPage extends DialogPage implements ISearchPage, ICSearchConstants {
public static final String EXTENSION_POINT_ID= "org.eclipse.cdt.ui.CSearchPage"; //$NON-NLS-1$
public boolean performAction() {
SearchUI.activateSearchResultView();
SearchPatternData data = getPatternData();
IWorkspace workspace = CUIPlugin.getWorkspace();
ICSearchScope scope = null;
String scopeDescription = ""; //$NON-NLS-1$
switch( getContainer().getSelectedScope() ) {
case ISearchPageContainer.SELECTION_SCOPE:
if( fStructuredSelection != null && fStructuredSelection.iterator().hasNext() ){
scopeDescription = CSearchMessages.getString("SelectionScope"); //$NON-NLS-1$
scope = CSearchScopeFactory.getInstance().createCSearchScope(fStructuredSelection);
break;
}
/* else fall through to workspace scope */
case ISearchPageContainer.WORKSPACE_SCOPE:
scopeDescription = CSearchMessages.getString("WorkspaceScope"); //$NON-NLS-1$
scope = SearchEngine.createWorkspaceScope();
break;
case ISearchPageContainer.WORKING_SET_SCOPE:
IWorkingSet[] workingSets= getContainer().getSelectedWorkingSets();
// should not happen - just to be sure
if (workingSets == null || workingSets.length < 1)
return false;
scopeDescription = CSearchMessages.getFormattedString("WorkingSetScope", CSearchUtil.toString(workingSets)); //$NON-NLS-1$
scope= CSearchScopeFactory.getInstance().createCSearchScope(getContainer().getSelectedWorkingSets());
CSearchUtil.updateLRUWorkingSets(getContainer().getSelectedWorkingSets());
}
data.cElement= null;
CSearchResultCollector collector= new CSearchResultCollector();
List searching = null;
if( data.searchFor.contains( UNKNOWN_SEARCH_FOR ) ){
//UNKNOWN_SEARCH_FOR means search for anything, make a list with everything
searching = new LinkedList();
for( int i = 0; i < fSearchFor.length - 1; i++ ){
searching.add( fSearchForValues[ i ] );
}
//include those items not represented in the UI
searching.add( MACRO );
searching.add( TYPEDEF );
} else {
searching = data.searchFor;
}
CSearchOperation op = new CSearchOperation(workspace, data.pattern, data.isCaseSensitive, searching, data.limitTo, scope, scopeDescription, collector);
try {
getContainer().getRunnableContext().run(true, true, op);
} catch (InvocationTargetException ex) {
Shell shell = getControl().getShell();
//ExceptionHandler.handle(ex, shell, CSearchMessages.getString("Search.Error.search.title"), CSearchMessages.getString("Search.Error.search.message")); //$NON-NLS-2$ //$NON-NLS-1$
return false;
} catch (InterruptedException ex) {
return false;
}
return true;
}
public void createControl(Composite parent) {
initializeDialogUnits( parent );
readConfiguration();
GridData gd;
Composite result = new Composite( parent, SWT.NONE );
GridLayout layout = new GridLayout( 2, false );
layout.horizontalSpacing = 10;
result.setLayout( layout );
result.setLayoutData( new GridData(GridData.FILL_HORIZONTAL) );
RowLayouter layouter = new RowLayouter( layout.numColumns );
gd = new GridData();
gd.horizontalAlignment = GridData.FILL;
gd.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_FILL;
layouter.setDefaultGridData( gd, 0 );
layouter.setDefaultGridData( gd, 1 );
layouter.setDefaultSpan();
layouter.perform( createExpression(result) );
layouter.perform( createSearchFor(result), createLimitTo(result), -1 );
SelectionAdapter cElementInitializer = new SelectionAdapter() {
public void widgetSelected( SelectionEvent event ) {
if( getSearchFor() == fInitialData.searchFor )
fCElement= fInitialData.cElement;
else
fCElement= null;
handleAllElements( event );
setLimitTo( getSearchFor() );
updateCaseSensitiveCheckbox();
}
};
for( int i = 0; i < fSearchFor.length; i++ ){
fSearchFor[ i ].addSelectionListener( cElementInitializer );
}
setControl( result );
Dialog.applyDialogFont( result );
WorkbenchHelp.setHelp(result, ICHelpContextIds.C_SEARCH_PAGE);
}
private Control createExpression( Composite parent ) {
Composite result = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout(2, false);
result.setLayout(layout);
GridData gd = new GridData( GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL );
gd.horizontalSpan = 2;
gd.horizontalIndent = 0;
result.setLayoutData( gd );
// Pattern text + info
Label label = new Label( result, SWT.LEFT );
label.setText( CSearchMessages.getString( "CSearchPage.expression.label" ) ); //$NON-NLS-1$
gd = new GridData( GridData.BEGINNING );
gd.horizontalSpan = 2;
label.setLayoutData( gd );
// Pattern combo
fPattern = new Combo( result, SWT.SINGLE | SWT.BORDER );
fPattern.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
handlePatternSelected();
}
});
fPattern.addModifyListener( new ModifyListener() {
public void modifyText( ModifyEvent e ) {
getContainer().setPerformActionEnabled( getPattern().length() > 0 );
updateCaseSensitiveCheckbox();
}
});
gd = new GridData( GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL );
gd.horizontalIndent = -gd.horizontalIndent;
fPattern.setLayoutData( gd );
// Ignore case checkbox
fCaseSensitive= new Button(result, SWT.CHECK);
fCaseSensitive.setText(CSearchMessages.getString("CSearchPage.expression.caseSensitive")); //$NON-NLS-1$
gd= new GridData();
fCaseSensitive.setLayoutData(gd);
fCaseSensitive.addSelectionListener( new SelectionAdapter() {
public void widgetSelected( SelectionEvent e ) {
fIsCaseSensitive= fCaseSensitive.getSelection();
writeConfiguration();
}
});
return result;
}
private void handleAllElements( SelectionEvent event ){
Button allElements = fSearchFor[ fSearchFor.length - 1 ];
if( event.widget == allElements ){
for( int i = 0; i < fSearchFor.length - 1; i++ )
fSearchFor[i].setEnabled( ! allElements.getSelection() );
}
}
private void handlePatternSelected() {
if( fPattern.getSelectionIndex() < 0 )
return;
int index = fgPreviousSearchPatterns.size() - 1 - fPattern.getSelectionIndex();
fInitialData = (SearchPatternData) fgPreviousSearchPatterns.get( index );
updateSelections();
if( fInitialData.workingSets != null )
getContainer().setSelectedWorkingSets( fInitialData.workingSets );
else
getContainer().setSelectedScope( fInitialData.scope );
}
private String getPattern() {
return fPattern.getText();
}
private Control createLimitTo( Composite parent ) {
Group result = new Group(parent, SWT.NONE);
result.setText( CSearchMessages.getString("CSearchPage.limitTo.label") ); //$NON-NLS-1$
GridLayout layout = new GridLayout();
layout.numColumns = 2;
result.setLayout( layout );
fLimitTo = new Button[fLimitToText.length];
for( int i = 0; i < fLimitToText.length; i++ ){
Button button = new Button(result, SWT.RADIO);
button.setText( fLimitToText[i] );
fLimitTo[i] = button;
}
// Fill with dummy radio buttons
Button filler= new Button(result, SWT.RADIO);
filler.setVisible(false);
filler= new Button(result, SWT.RADIO);
filler.setVisible(false);
return result;
}
private LimitTo getLimitTo() {
for (int i= 0; i < fLimitTo.length; i++) {
if (fLimitTo[i].getSelection())
return fLimitToValues[ i ];
}
return null;
}
private void setLimitTo( List searchFor ) {
HashSet set = new HashSet();
set.add( DECLARATIONS );
set.add( REFERENCES );
set.add( ALL_OCCURRENCES );
for (Iterator iter = searchFor.iterator(); iter.hasNext();) {
SearchFor element = (SearchFor) iter.next();
if( element == FUNCTION || element == METHOD || element == VAR ||
element == FIELD || element == NAMESPACE || element == UNKNOWN_SEARCH_FOR ){
set.add( DEFINITIONS );
break;
}
}
for( int i = 0; i < fLimitTo.length; i++ )
fLimitTo[ i ].setEnabled( set.contains( fLimitToValues[ i ] ) );
}
private Control createSearchFor(Composite parent) {
Group result= new Group(parent, SWT.NONE);
result.setText(CSearchMessages.getString("CSearchPage.searchFor.label")); //$NON-NLS-1$
GridLayout layout= new GridLayout();
layout.numColumns= 3;
result.setLayout(layout);
fSearchFor= new Button[fSearchForText.length];
for (int i= 0; i < fSearchForText.length; i++) {
Button button= new Button(result, SWT.CHECK);
button.setText(fSearchForText[i]);
fSearchFor[i]= button;
}
return result;
}
private List getSearchFor() {
List search = new LinkedList( );
// boolean all = fSearchFor[ fSearchFor.length - 1 ].getSelection();
for (int i= 0; i < fSearchFor.length; i++) {
if( fSearchFor[i].getSelection() /*|| all */)
search.add( fSearchForValues[i] );
}
return search;
}
public void setContainer(ISearchPageContainer container) {
fContainer = container;
}
private ISearchPageContainer getContainer() {
return fContainer;
}
private IDialogSettings getDialogSettings() {
IDialogSettings settings = CUIPlugin.getDefault().getDialogSettings();
fDialogSettings = settings.getSection( PAGE_NAME );
if( fDialogSettings == null )
fDialogSettings = settings.addNewSection( PAGE_NAME );
return fDialogSettings;
}
private void readConfiguration() {
IDialogSettings s = getDialogSettings();
fIsCaseSensitive = s.getBoolean( STORE_CASE_SENSITIVE );
}
private void writeConfiguration() {
IDialogSettings s = getDialogSettings();
s.put( STORE_CASE_SENSITIVE, fIsCaseSensitive );
}
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());
initSelections();
}
fPattern.setFocus();
getContainer().setPerformActionEnabled(fPattern.getText().length() > 0);
}
super.setVisible(visible);
}
private void updateCaseSensitiveCheckbox() {
if (fInitialData != null && getPattern().equals(fInitialData.pattern) && fCElement != null) {
fCaseSensitive.setEnabled(false);
fCaseSensitive.setSelection(true);
}
else {
fCaseSensitive.setEnabled(true);
fCaseSensitive.setSelection(fIsCaseSensitive);
}
}
private void initSelections() {
fStructuredSelection = asStructuredSelection();
fInitialData = tryStructuredSelection( fStructuredSelection );
updateSelections();
}
private void updateSelections(){
if (fInitialData == null)
fInitialData = trySimpleTextSelection( getContainer().getSelection() );
if (fInitialData == null)
fInitialData = getDefaultInitValues();
fCElement = fInitialData.cElement;
fIsCaseSensitive = fInitialData.isCaseSensitive;
fCaseSensitive.setSelection( fInitialData.isCaseSensitive );
fCaseSensitive.setEnabled( fInitialData.cElement == null );
HashSet set = new HashSet( fInitialData.searchFor );
boolean enabled = ! set.contains( fSearchForValues[ fSearchFor.length - 1 ] );
for (int i = 0; i < fSearchFor.length; i++){
fSearchFor[i].setSelection( set.contains( fSearchForValues[i] ) );
fSearchFor[i].setEnabled( enabled );
}
if( !enabled )
fSearchFor[ fSearchFor.length - 1 ].setEnabled( true );
setLimitTo( fInitialData.searchFor );
for (int i = 0; i < fLimitTo.length; i++)
fLimitTo[i].setSelection( fLimitToValues[i] == fInitialData.limitTo );
fPattern.setText( fInitialData.pattern );
}
private SearchPatternData tryStructuredSelection( IStructuredSelection selection ) {
if( selection == null || selection.size() > 1 )
return null;
Object o = selection.getFirstElement();
if( o instanceof ICElement ) {
return determineInitValuesFrom( (ICElement)o );
} else if( o instanceof ISearchResultViewEntry ) {
ICElement element = CSearchUtil.getCElement( ((ISearchResultViewEntry)o).getSelectedMarker() );
return determineInitValuesFrom( element );
//} else if( o instanceof LogicalPackage ) {
// LogicalPackage lp = (LogicalPackage)o;
// return new SearchPatternData( PACKAGE, REFERENCES, fIsCaseSensitive, lp.getElementName(), null );
} else if( o instanceof IAdaptable ) {
ICElement element = (ICElement)((IAdaptable)o).getAdapter( ICElement.class );
if( element != null ) {
return determineInitValuesFrom( element );
} else {
IWorkbenchAdapter adapter= (IWorkbenchAdapter)((IAdaptable)o).getAdapter( IWorkbenchAdapter.class );
if( adapter != null ){
List searchFor = new LinkedList();
searchFor.add( UNKNOWN_SEARCH_FOR );
return new SearchPatternData( searchFor, DECLARATIONS, fIsCaseSensitive, adapter.getLabel(o), null );
}
}
}
return null;
}
/**
* try to initialize the Search pattern data based on the current text selection.
* @param selection
* @return
*/
private SearchPatternData trySimpleTextSelection(ISelection selection) {
SearchPatternData result= null;
if (selection instanceof ITextSelection) {
BufferedReader reader= new BufferedReader(new StringReader(((ITextSelection)selection).getText()));
String text;
try {
text= reader.readLine();
if (text == null)
text= ""; //$NON-NLS-1$
} catch (IOException ex) {
text= ""; //$NON-NLS-1$
}
List searchFor = new LinkedList();
searchFor.add( UNKNOWN_SEARCH_FOR );
result= new SearchPatternData( searchFor, DECLARATIONS, fIsCaseSensitive, text, null);
}
return result;
}
private SearchPatternData getDefaultInitValues() {
List searchFor = new LinkedList();
searchFor.add( CLASS_STRUCT );
return new SearchPatternData( searchFor, DECLARATIONS, fIsCaseSensitive, "", null); //$NON-NLS-1$
}
private String[] getPreviousSearchPatterns() {
// Search results are not persistent
int patternCount= fgPreviousSearchPatterns.size();
String [] patterns= new String[patternCount];
for (int i= 0; i < patternCount; i++)
patterns[i]= ((SearchPatternData) fgPreviousSearchPatterns.get(patternCount - 1 - i)).pattern;
return patterns;
}
private IStructuredSelection asStructuredSelection() {
IWorkbenchWindow wbWindow= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (wbWindow != null) {
IWorkbenchPage page= wbWindow.getActivePage();
if (page != null) {
IWorkbenchPart part= page.getActivePart();
if (part != null){
ISelectionProvider provider = part.getSite().getSelectionProvider();
if( provider != null ){
ISelection selection = provider.getSelection();
if( selection instanceof IStructuredSelection ){
return (IStructuredSelection)selection;
}
}
}
}
}
return StructuredSelection.EMPTY;
}
private SearchPatternData determineInitValuesFrom( ICElement element ) {
if( element == null )
return null;
List searchFor = new LinkedList();
//outliune view will confuse methods with functions, so if the
//name contains a "::", treat it as a method
String pattern = element.getElementName();
boolean forceMethod = ( pattern.indexOf("::") != -1 );
switch ( element.getElementType() ){
case ICElement.C_TEMPLATE_FUNCTION: /*fall through to function */
case ICElement.C_FUNCTION_DECLARATION: /*fall through to function */
case ICElement.C_FUNCTION: if( forceMethod ) searchFor.add( METHOD );
else searchFor.add( FUNCTION );
break;
case ICElement.C_VARIABLE: searchFor.add( VAR ); break;
case ICElement.C_TEMPLATE_CLASS:/* fall through to CLASS */
case ICElement.C_STRUCT: /* fall through to CLASS */
case ICElement.C_CLASS: searchFor.add( CLASS_STRUCT ); break;
case ICElement.C_UNION: searchFor.add( UNION ); break;
case ICElement.C_ENUMERATOR: /* fall through to FIELD */
case ICElement.C_FIELD: searchFor.add( FIELD ); break;
case ICElement.C_TEMPLATE_METHOD : /*fall through to METHOD */
case ICElement.C_METHOD_DECLARATION : /*fall through to METHOD */
case ICElement.C_METHOD: searchFor.add( METHOD ); break;
case ICElement.C_NAMESPACE: searchFor.add( NAMESPACE ); break;
case ICElement.C_ENUMERATION: searchFor.add( ENUM ); break;
default: searchFor.add( UNKNOWN_SEARCH_FOR ); break;
}
LimitTo limitTo = ALL_OCCURRENCES;
return new SearchPatternData( searchFor, limitTo, true, pattern, element );
}
private SearchPatternData getPatternData() {
String pattern= getPattern();
SearchPatternData match= null;
int i= 0;
int size= fgPreviousSearchPatterns.size();
while (match == null && i < size) {
match= (SearchPatternData) fgPreviousSearchPatterns.get(i);
i++;
if (!pattern.equals(match.pattern))
match= null;
};
if (match == null) {
match= new SearchPatternData(
getSearchFor(),
getLimitTo(),
pattern,
fCaseSensitive.getSelection(),
fCElement,
getContainer().getSelectedScope(),
getContainer().getSelectedWorkingSets());
fgPreviousSearchPatterns.add(match);
}
else {
match.searchFor= getSearchFor();
match.limitTo= getLimitTo();
match.isCaseSensitive= fCaseSensitive.getSelection();
match.cElement= fCElement;
match.scope= getContainer().getSelectedScope();
match.workingSets= getContainer().getSelectedWorkingSets();
};
return match;
}
private static class SearchPatternData {
List searchFor;
LimitTo limitTo;
String pattern;
boolean isCaseSensitive;
ICElement cElement;
int scope;
IWorkingSet[] workingSets;
public SearchPatternData(List s, LimitTo l, boolean i, String p, ICElement element) {
this(s, l, p, i, element, ISearchPageContainer.WORKSPACE_SCOPE, null);
}
public SearchPatternData(List s, LimitTo l, String p, boolean i, ICElement element, int scope, IWorkingSet[] workingSets) {
searchFor= s;
limitTo= l;
pattern= p;
isCaseSensitive= i;
cElement= element;
this.scope = scope;
this.workingSets = workingSets;
}
}
//Dialog store id constants
private final static String PAGE_NAME= "CSearchPage"; //$NON-NLS-1$
private final static String STORE_CASE_SENSITIVE= PAGE_NAME + "CASE_SENSITIVE"; //$NON-NLS-1$
private static List fgPreviousSearchPatterns = new ArrayList(20);
private Button[] fSearchFor;
private SearchFor[] fSearchForValues = { CLASS_STRUCT, FUNCTION, VAR, UNION, METHOD, FIELD, ENUM, NAMESPACE, UNKNOWN_SEARCH_FOR };
private String[] fSearchForText= {
CSearchMessages.getString("CSearchPage.searchFor.classStruct"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.function"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.variable"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.union"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.method"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.field"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.enum"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.namespace"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.searchFor.any") }; //$NON-NLS-1$
private Button[] fLimitTo;
private LimitTo[] fLimitToValues = { DECLARATIONS, DEFINITIONS, REFERENCES, ALL_OCCURRENCES };
private String[] fLimitToText= {
CSearchMessages.getString("CSearchPage.limitTo.declarations"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.limitTo.definitions"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.limitTo.references"), //$NON-NLS-1$
CSearchMessages.getString("CSearchPage.limitTo.allOccurrences") }; //$NON-NLS-1$
//CSearchMessages.getString("CSearchPage.limitTo.readReferences"), //$NON-NLS-1$
//CSearchMessages.getString("CSearchPage.limitTo.writeReferences")}; //$NON-NLS-1$
private SearchPatternData fInitialData;
private IStructuredSelection fStructuredSelection;
private ICElement fCElement;
private boolean fFirstTime= true;
private IDialogSettings fDialogSettings;
private boolean fIsCaseSensitive;
private Combo fPattern;
private ISearchPageContainer fContainer;
private Button fCaseSensitive;
}