srcanaapps/depexplorer/com.nokia.s60tools.appdep/src/com/nokia/s60tools/appdep/locatecomponent/ShowMethodCallLocationsJob.java
author noe\swadi
Tue, 23 Feb 2010 10:27:57 +0530
changeset 3 ec51f72aa69a
parent 0 a02c979e8dfd
permissions -rw-r--r--
Licenses updated to EPL.

/*
* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/


package com.nokia.s60tools.appdep.locatecomponent;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.index.IIndexChangeEvent;
import org.eclipse.cdt.core.index.IIndexChangeListener;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IIndexerStateEvent;
import org.eclipse.cdt.core.index.IIndexerStateListener;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.internal.ui.search.CSearchMessages;
import org.eclipse.cdt.internal.ui.search.PDOMSearchPatternQuery;
import org.eclipse.cdt.internal.ui.search.PDOMSearchQuery;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.search.ui.IQueryListener;
import org.eclipse.search.ui.ISearchQuery;
import org.eclipse.search.ui.NewSearchUI;
import org.eclipse.swt.widgets.Display;

import com.nokia.s60tools.appdep.core.AppDepSettings;
import com.nokia.s60tools.appdep.exceptions.CacheFileDoesNotExistException;
import com.nokia.s60tools.appdep.exceptions.CacheIndexNotReadyException;
import com.nokia.s60tools.appdep.resources.Messages;
import com.nokia.s60tools.appdep.ui.views.main.MainViewDataPopulator;
import com.nokia.s60tools.appdep.util.AppDepConsole;
import com.nokia.s60tools.sdk.SdkInformation;
import com.nokia.s60tools.util.console.IConsolePrintUtility;
import com.nokia.s60tools.util.debug.DbgUtility;
import com.nokia.s60tools.util.exceptions.JobCancelledByUserException;
import com.nokia.s60tools.util.sourcecode.CannotFoundFileException;
import com.nokia.s60tools.util.sourcecode.IProjectFinder;
import com.nokia.s60tools.util.sourcecode.ISourcesFinder;
import com.nokia.s60tools.util.sourcecode.ProjectFinderFactory;
import com.nokia.s60tools.util.sourcecode.SourceFinderFactory;

/**
 * Job for seeking possible concrete implementation of generic component name.
 */
// If public access to {@link PDOMSearchPatternQuery} is provided later on, the suppressing of warnings in here is no more needed.
@SuppressWarnings("restriction")
public class ShowMethodCallLocationsJob extends Job implements IQueryListener {

	/**
	 * Amount of steps used for the create project job progress follow-up.
	 */
	private static final int CREATING_PROJECT_STEPS = 5;
	/**
	 * Step amounts reserved for searching and indexing phase.
	 */
	private static final int SEARCH_AND_INDEX_STEPS = 85;

	/**
	 * Search string formed for the used search service-
	 */
	private String searchString = null;

	/**
	 * Project to be created for which contents the search is done.
	 */
	private ICProject cProject;

	/**
	 * File list defining valid search scope.
	 */
	private String[] filesBelongsToComponent;

	/**
	 * Job's progress monitor.
	 */
	private IProgressMonitor progressMonitor;
	/**
	 * Name of the component the method call locations are searched from.
	 */
	private String componentName = null;
	
	/**
	 * Method name to be searched from the component.
	 */
	private String methodName = null;
	/**
	 * Name of main task that is show to the user in job progress dialog.
	 */
	private final String mainTaskMessage;

	/**
	 * Constructor.
	 * @param jobName Job name 
	 * @param mainTaskMessage Task name used for main task message
	 * @param componentName Component name to search method calls from.
	 * @param methodName Method name which occurrences to search from the component..
	 * @param isUserJob if <code>true</code> job is set as user level job that prompts dialog.
	 */
	public ShowMethodCallLocationsJob(String jobName, String mainTaskMessage, String componentName, String methodName, boolean isUserJob) {
		super(jobName);
		this.mainTaskMessage = mainTaskMessage;
		this.componentName = componentName;
		this.methodName = methodName;
		setUser(isUserJob);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IStatus run(IProgressMonitor monitor) {
		
		progressMonitor = monitor;
		IStatus status;		

		try {
		
			progressMonitor.beginTask(mainTaskMessage,  100);

			AppDepSettings settings = AppDepSettings.getActiveSettings();

			SdkInformation sdkInfo = settings.getCurrentlyUsedSdk();
			String epocRootPath = sdkInfo.getEpocRootDir(); 			

			progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.SearchingFiles_SubTask_Msg") +"\n" +componentName +"'..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			
			filesBelongsToComponent = getUsedComponentSourceFiles(settings, componentName, epocRootPath);			
			//Limit number of files simple founding part of the method name, to decrease project files
			setSearchString(methodName);
									
			checkIfCancelled();
			progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.SearchingBldInf_SubTask_Msg")); //$NON-NLS-1$
			progressMonitor.worked(CREATING_PROJECT_STEPS);
			
			//Finds and sets source files as IFile to variables
			String bldFile = getBldInfFileName(filesBelongsToComponent);
			
			//If the project already exist, just executing the search
			if(isProjectAllreadyExistingAndOpenIfClosed(bldFile, progressMonitor)){

				progressMonitor.worked(SEARCH_AND_INDEX_STEPS);
				checkIfCancelled();
				executeSearch(searchString);
				status = Status.OK_STATUS;

			}
			//otherwise first create a project, wait until indexed, and then execute the search
			else{			
				//Create a job to create project by bld.inf file if needed, and then execute search
				progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.CreatingProjectFromBldInf_SubTask_Msg") +"\n" +bldFile +"'..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				checkIfCancelled();
				status = createAndRunProjectCreatingJobAndExecuteSearch(bldFile, progressMonitor);				
				progressMonitor.worked(CREATING_PROJECT_STEPS);

				if(status.getSeverity() == IStatus.ERROR){
					this.cancel();
				}
				else{
					startIndexingAndSearch();					
					status = Job.ASYNC_FINISH;
				}
			}
			
		} catch (JobCancelledByUserException e) {
			// Job cancel because of user request 
			this.cancel();
			status = Status.CANCEL_STATUS;
		}catch (Exception e) {
			// Job cancel because of an exception 
			e.printStackTrace();
			String errMsg = Messages.getString("CreateProjectJob.Err_Msg") + ": " + e.getMessage(); //$NON-NLS-1$ //$NON-NLS-2$ 
			status = reportError(e, errMsg);
			this.cancel();	
		}
		return status;
	}

	/**
	 * Reports error to user.
	 * @param e Encountered exception.
	 * @param errMsg Error message.
	 * @return status object.
	 */
	private IStatus reportError(Exception e, String errMsg) {
		IStatus status;
		status = new Status(
				Status.ERROR,Platform.PI_RUNTIME,
				Status.ERROR,errMsg, e);
		AppDepConsole.getInstance().println(errMsg, IConsolePrintUtility.MSG_ERROR);
		return status;
	}
	
	/**
	 * Gets all source files belonging to the given component.
	 * @param settings Tool settings.
	 * @param componentName component name to search method call locations from.
	 * @param epocRootPath EPOCROOT path
	 * @return Source file name array
	 * @throws CannotFoundFileException
	 * @throws CacheFileDoesNotExistException 
	 * @throws CacheIndexNotReadyException 
	 * @throws IOException 
	 */
	private String[] getUsedComponentSourceFiles(AppDepSettings settings,
			String componentName, String epocRootPath)
			throws CannotFoundFileException, IOException, CacheIndexNotReadyException, CacheFileDoesNotExistException {

		ISourcesFinder finder = SourceFinderFactory.createSourcesFinder(AppDepConsole.getInstance());
		String  variant = MainViewDataPopulator.getTargetPlatformIdStringForComponent(settings, componentName);
		String build = settings.getBuildType().getBuildTypeName();		
		String [] files = finder.findSourceFiles(componentName, variant, build, epocRootPath);
		return files;
	}

	/**
	 * Sets search string based on the method name.
	 * @param methodName Method name.
	 */
	private void setSearchString(String methodName) {
		String shortMethodName = methodName;
		int start = methodName.indexOf("::"); //$NON-NLS-1$
		if(start != -1){
			shortMethodName = methodName.substring(start + 2);
			
		}
		int end = shortMethodName.indexOf("("); //$NON-NLS-1$
		if(end != -1){
			shortMethodName = shortMethodName.substring(0, end);
		}
		
		String longMethodNameWithOutParams;
		if(methodName.indexOf("(") != -1){ //$NON-NLS-1$
			longMethodNameWithOutParams = methodName.substring(0, methodName.indexOf("(")); //$NON-NLS-1$
		}else{
			longMethodNameWithOutParams = methodName;
		}
		
		searchString  =  longMethodNameWithOutParams;// methodName;// shortMethodName;				
	}


	/**
	 * Seeks all files by bld.inf file and set them to filesInBldInf 
	 * and seeks all bld.inf to add them to bldInfFiles
	 * @param files File name array.
	 * @return bld.inf file path and an empty string if not found.
	 * @throws URISyntaxException
	 * @throws JobCancelledByUserException 
	 */
	private String getBldInfFileName(String[] files) throws URISyntaxException, JobCancelledByUserException {
		//Opening project(s) where source files belongs to
		IProjectFinder prjFinder = ProjectFinderFactory.createProjectFinder(AppDepConsole.getInstance(), progressMonitor);
		Vector<String> bldInfFiles = new Vector<String>();
		int errorsCount = 0;
		for (int i = 0; i < files.length; i++) {
			String bldInfFile;
			try {
				String mmpFile = prjFinder.findMMPFile(files[i]);
				//If search is canceled, null was returned from the previously called method				
				if(mmpFile == null){
					checkIfCancelled();
				}else{
					bldInfFile = prjFinder.findBLDINFFile(mmpFile);
					//If search is canceled, null is returned, cancellation check will be check if null is returned
					if(bldInfFile != null){
						bldInfFiles.add(bldInfFile);
					}else {
						checkIfCancelled();
					}
				}
			} catch (CannotFoundFileException e) {
				errorsCount++;//Just counting errors, really doing nothing with those but skipping if some file does not exist
			}
		}

		// Throwing an error in case bld.inf file was not found
		if(bldInfFiles.size() == 0){
			String errMsg = Messages.getString("ShowMethodCallLocationsJob.CouldNotFindBldInfFile_ErrMsg") //$NON-NLS-1$
							+ componentName
							+ "'"; //$NON-NLS-1$
			throw new RuntimeException(errMsg);
		}
		// Returning found bld.inf file path name on success
		return bldInfFiles.elementAt(0);
	}

	/**
	 * Checks if job was cancelled by user.
	 * @throws JobCancelledByUserException
	 */
	private void checkIfCancelled() throws JobCancelledByUserException {
		if(progressMonitor.isCanceled()){
			throw new JobCancelledByUserException(Messages.getString("ShowMethodCallLocationsJob.JobCanceledByUser_ErrMsg")); //$NON-NLS-1$
		}
	}	
	
	/**
	 * Creates a project.
	 * @param bldFile bld.inf file to create project based on.
	 * @param monitor Progress monitor object
	 * @throws IOException 
	 * @throws CoreException 
	 */
	private IStatus createAndRunProjectCreatingJobAndExecuteSearch(String bldFile, IProgressMonitor monitor) throws IOException, CoreException {		
			
			DEProjectUtils utils = new DEProjectUtils(AppDepConsole.getInstance());
			CProjectJobStatus stat = utils.createProjectImpl(progressMonitor, bldFile);

			this.cProject = stat.getCProject();		
			IStatus status = stat.getStatus();
		
			return status;
	}	
	
	/**
	 * Checks if project already exist in workspace.
	 * @param bldFile bld.inf file to create project based on.
	 * @param monitor Progress monitor object
	 * @return <code>true</code> if project is found from workspace, otherwise <code>false</code>.
	 * @throws IOException
	 * @throws CoreException 
	 */
	private boolean isProjectAllreadyExistingAndOpenIfClosed(String bldFile, IProgressMonitor monitor) throws IOException, CoreException {

		IPath path = new Path(bldFile);	
		IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(path);
		
		if(files.length > 0){	
			
			IProject prj = files[0].getProject();
			if(prj.isOpen()){
				return true;
			}
			else{
				prj.open(monitor);				
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Creates query and execute the search
	 * @param searchText Search text
	 * @throws JobCancelledByUserException 
	 */
	private void executeSearch(final String searchText){

		progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.ExcecutingSearch_SubTask_Msg")); //$NON-NLS-1$
		
		final IResource[] resources = createResourcesTable();
		
		
		DbgUtility.println(DbgUtility.PRIORITY_OPERATION, "Starting to execute search with " +resources.length +" resources..."); //$NON-NLS-1$ //$NON-NLS-2$
		
			Runnable runSeach = new Runnable(){
				public void run(){
					try {
						if(progressMonitor.isCanceled()){
							cancelProgress();
						}else{
							ISearchQuery query = null;
							//Query is created by CDT:s interal API
							query = getSearchQuery(searchText, resources);
							//Start to listen search query for noticing done() when its completed
							NewSearchUI.addQueryListener(getIQueryListener());
							NewSearchUI.activateSearchResultView();		
							NewSearchUI.runQueryInBackground(query);
						}
					}
					catch (Exception e) {
						e.printStackTrace();
						AppDepConsole.getInstance().println(Messages.getString("ShowMethodCallLocationsJob.UnableToExecuteSearch_ErrMsg_Part2") +e, AppDepConsole.MSG_ERROR); //$NON-NLS-1$
						errorProgress(Messages.getString("ShowMethodCallLocationsJob.UnableToExecuteSearch_ErrMsg_Part1"), e);  //$NON-NLS-1$
					}
				}

			};
			
			// Showing a visible message in its own thread
			// in order not to cause invalid thread access
			Display.getDefault().asyncExec(runSeach);									
	}		
	
	/**
	 * Get search query.
	 * <p>
	 * This method is using CDT:s internal API:s and if public access to {@link PDOMSearchPatternQuery}
	 * is provided, implementation should be changed to use public implementation. 
	 * Internal API is used, because of ready made implementation of find functions and methods references
	 * is found in there. 
	 * @param searchText, text to search, without parameters. Cut search String before first brace "(". 
	 * With parameters and braces, you don't get any results. 
	 * @param resources
	 * @return query to give to Search engine.
	 * @throws CoreException
	 */
	private ISearchQuery getSearchQuery(
			final String searchText, final IResource[] resources)
			throws CoreException {
		
		// get the list of elements for the scope
		List<Object> elements = new ArrayList<Object>();
		//Search from the given source files found in .map file
		String scopeDescription = CSearchMessages.SelectionScope; 

		for (int i = 0; i < resources.length; i++) {
			elements.add(CoreModel.getDefault().create(resources[i]));
		}

		boolean isCaseSensitive = true;
		//to Search query, we must give resources as ICElement
		ICElement[] scope = elements.isEmpty() ? null : elements.toArray(new ICElement[elements.size()]);
		//Same flags covers search for and limit to selections, we want to search functions/methods and only references
		int searchFlags = PDOMSearchPatternQuery.FIND_FUNCTION | PDOMSearchPatternQuery.FIND_METHOD
							| PDOMSearchQuery.FIND_REFERENCES;

		//class to execute search is interal class provided in CDT, permission to use internal classes is granted.
		//Parameters cannot be used wih Query, only class name(s) and method name
		PDOMSearchPatternQuery query = new PDOMSearchPatternQuery(scope, scopeDescription, searchText, 
				isCaseSensitive , searchFlags );		
		
		return query;
	}
	
	/**
	 * Creates a array containing IFile links to files that were found from map file.
	 * @return Resource object array.
	 */
	private IResource[] createResourcesTable() {
		HashSet<IFile> filesInBldInf = new HashSet<IFile>();
		
		for (int i = 0; i < filesBelongsToComponent.length; i++) {
			String uriStr = filesBelongsToComponent[i].replace("\\", "/");; //$NON-NLS-1$ //$NON-NLS-2$
			uriStr = "file://" + uriStr; //$NON-NLS-1$
			IFile[] wsFile;
			try {
				wsFile = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(
						new URI( uriStr));
				for (int j = 0; j < wsFile.length; j++) {
					filesInBldInf.add(wsFile[j]);							
				}			
			} catch (URISyntaxException e) {
				e.printStackTrace();
				AppDepConsole.getInstance().println(
						Messages.getString("ShowMethodCallLocationsJob.UnableToAddFile_ErrMsg_Part1") +uriStr  //$NON-NLS-1$
						+Messages.getString("ShowMethodCallLocationsJob.UnableToAddFile_ErrMsg_Part2") +e, AppDepConsole.MSG_ERROR); //$NON-NLS-1$
				
			}
		}
		
		final IResource[] resources = (IFile[])filesInBldInf.toArray(new IFile[0]);
		return resources;
	}		

	/**
	 * Triggers indexing and searching.
	 * @throws JobCancelledByUserException
	 */
	private void startIndexingAndSearch() throws JobCancelledByUserException {
		checkIfCancelled();
		IIndexManager indexManager = CCorePlugin.getIndexManager();		
		boolean projectIndexed = indexManager.isProjectIndexed(cProject);
		DbgUtility.println(DbgUtility.PRIORITY_OPERATION, "Project: " +cProject.getElementName() + " indexed: " +projectIndexed + " and indexer is idling: " +indexManager.isIndexerIdle()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		
		//If project is already indexed, search can be started right away
		if(projectIndexed && indexManager.isIndexerIdle()){
			executeSearch( searchString);								
		}
		//otherwise starting to listen indexer, and when its done, executing search
		else{						
			progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.StartingIndexing_SubTask_Msg")); //$NON-NLS-1$
			IndexerStateListener listener = new IndexerStateListener();
			indexManager.addIndexerStateListener(listener);			
			indexManager.addIndexChangeListener(listener);
		}
	}	
	
	/**
	 * Listener class implementation for listening indexer state changes and start
	 * execution of search when indexer is in idle state.
	 */
	private class IndexerStateListener implements IIndexerStateListener, IIndexChangeListener {
	
		public IndexerStateListener(){
			progressMonitor.subTask(Messages.getString("ShowMethodCallLocationsJob.IndexingProject_SubTask_Msg") +cProject.getProject().getName() +"'..."); //$NON-NLS-1$ //$NON-NLS-2$
		}
		
		private Double step = new Double (new Double(SEARCH_AND_INDEX_STEPS) / new Double( filesBelongsToComponent.length));
		private double workLeftFromPreviousStep = 0;

		/* (non-Javadoc)
		 * @see org.eclipse.cdt.core.index.IIndexerStateListener#indexChanged(org.eclipse.cdt.core.index.IIndexerStateEvent)
		 */
		public void indexChanged(IIndexerStateEvent event) {
			try {
				boolean indexerIsIdle = event.indexerIsIdle();
				if(indexerIsIdle){
					execute();
				}
			} catch (Exception e) {
				errorProgress(Messages.getString("ShowMethodCallLocationsJob.UnableToExecuteSearch_ErrMsg_Part1"), e); //$NON-NLS-1$
			}
		}

		/* (non-Javadoc)
		 * @see org.eclipse.cdt.core.index.IIndexChangeListener#indexChanged(org.eclipse.cdt.core.index.IIndexChangeEvent)
		 */
		public void indexChanged(IIndexChangeEvent event) {

			try{
				if(progressMonitor.isCanceled()){
					IIndexManager indexManager = CCorePlugin.getIndexManager();
					removeListeners(indexManager);
					cancelProgress();
				}
				
				//Counting what's left from previous step and number of one step
				double stepTo = workLeftFromPreviousStep + step;
				Double stepNow = new Double(stepTo);
				//Take out int value of this step (x from x.yyyyyy)
				int workNow = stepNow.intValue();
				stepNow = stepNow-workNow;
				//put on hold what was left from this step to next step (yyyy from x.yyyy)			
				workLeftFromPreviousStep = stepNow.doubleValue();
				
				progressMonitor.worked(workNow);
				
				//Continuing execution if indexer is idle.
				IIndexManager indexManager = CCorePlugin.getIndexManager();
				if(indexManager.isIndexerIdle()){
					execute();
				}
			} catch (Exception e) {
				errorProgress(Messages.getString("ShowMethodCallLocationsJob.UnableToExecuteSearch_ErrMsg_Part1"), e);//$NON-NLS-1$
			}			
		}
		
		/**
		 * Starts execution of search 
		 * @throws JobCancelledByUserException 
		 */
		private void execute() {
			IIndexManager indexManager = CCorePlugin.getIndexManager();
			boolean projectIndexed = indexManager.isProjectIndexed(cProject);
			
			DbgUtility.println(DbgUtility.PRIORITY_OPERATION, "Project indexed: " +projectIndexed  + " and indexer is idling: " +indexManager.isIndexerIdle());	//$NON-NLS-1$ //$NON-NLS-2$
			//Search can be started if project is indexed and indexer is ready (not doing anything anymore).
			if(projectIndexed && indexManager.isIndexerIdle()){
				
				removeListeners(indexManager);
				executeSearch( searchString);								
			}
		}

		/**
		 * Removes listeners from index manager.
		 * @param indexManager Index manager.
		 */
		private void removeListeners(IIndexManager indexManager) {
			indexManager.removeIndexChangeListener(this);
			indexManager.removeIndexerStateListener(this);
		}
		
	}

	/**
	 * An error occurred, cancels progress and sends an error.
	 */
	private void errorProgress(String errMsg, Exception e) {
		// Cancelling query
		progressMonitor.done();
		IStatus status = new Status(
				Status.ERROR,Platform.PI_RUNTIME,
				Status.ERROR,errMsg, e);		
		done(status);
	}	
	
	/**
	 * Cancels progress without sending exception. 
	 */
	private void cancelProgress() {
		// Cancelling query
		progressMonitor.done();
		done(Status.CANCEL_STATUS);
	}

	/**
	 * Gets query listener interface.
	 * @return this
	 */
	public IQueryListener getIQueryListener(){
		return this;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.search.ui.IQueryListener#queryAdded(org.eclipse.search.ui.ISearchQuery)
	 */
	public void queryAdded(ISearchQuery query) {
		// not needed
	}

	/* (non-Javadoc)
	 * @see org.eclipse.search.ui.IQueryListener#queryFinished(org.eclipse.search.ui.ISearchQuery)
	 */
	public void queryFinished(ISearchQuery query) {
		//When query is finished, returning OK status
		progressMonitor.done();
        // Job has completed successfully
	    done(Status.OK_STATUS);				
	}

	/* (non-Javadoc)
	 * @see org.eclipse.search.ui.IQueryListener#queryRemoved(org.eclipse.search.ui.ISearchQuery)
	 */
	public void queryRemoved(ISearchQuery query) {
		cancelProgress();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.search.ui.IQueryListener#queryStarting(org.eclipse.search.ui.ISearchQuery)
	 */
	public void queryStarting(ISearchQuery query) {
		// not needed		
	}		
	
}