srcanaapps/apiquerytool/com.nokia.s60tools.apiquery/src/com/nokia/s60tools/apiquery/popup/actions/OpenFileAction.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) 2007 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.apiquery.popup.actions;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
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.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;

import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
import com.nokia.carbide.cdt.builder.EpocEngineHelper;
import com.nokia.carbide.cdt.builder.ICarbideBuildManager;
import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
import com.nokia.s60tools.apiquery.shared.exceptions.QueryOperationFailedException;
import com.nokia.s60tools.apiquery.shared.job.FindFileFromFoldersJob;
import com.nokia.s60tools.apiquery.shared.plugin.APIQueryPlugin;
import com.nokia.s60tools.apiquery.shared.resources.Messages;
import com.nokia.s60tools.apiquery.shared.ui.dialogs.APIQueryMessageBox;
import com.nokia.s60tools.apiquery.shared.util.console.APIQueryConsole;

/**
 * Action class for find and then open wanted file to Editor area. 
 * File can be seeked under SDK include paths or
 * under given project in Carbides Workspace.
 */
public class OpenFileAction implements IJobChangeListener{
	
	/**
	 * Current default build configuration SDK ID. 
	 */
	private String sdkUniqueId = null;
	private String fileName = null;
	private String projectName;

	/**
	 * Opens file from given project in Carbide workspace.
	 * @param fileName
	 * @param projectName
	 */
	public void openFileFromProject(String fileName, String projectName) {

		this.fileName = fileName;
		this.projectName = projectName;
		try {
			
			APIQueryConsole.getInstance().println(Messages.getString("OpenFileAction.StartingSeek_Msg_Part1") +fileName +Messages.getString("OpenFileAction.StartingSeek_Msg_Part2") +projectName +"'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
			
			IProject project = getProject(projectName);
			
			IResource[] members = project.members();
		
			Vector<IResource> files = getMatchingResources(fileName, members);
			
			if(!files.isEmpty()){
				
				//It should not be possible that there is multiple foundings for resource, because path is added when file was seeked
				IResource res = files.get(0);									
				IPath path = res.getFullPath();
				URI uri = res.getLocationURI();
				openFile(uri, path.lastSegment());
			}else{
				String message = Messages.getString("OpenFileAction.CannotFoundFile_ErrMsg_Part1") +fileName +Messages.getString("OpenFileAction.CannotFoundFile_ErrMsg_Part2") +projectName +"'."; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				showErrorMessage(message);		

			}
		
		} catch (Exception e) {
			showUnexpectedErrorMsg(e);
		}

	}


	/**
	 * Logs and shows error message for unexpected error situations.
	 * @param fileName
	 * @param projectName
	 * @param e {@link Exception}
	 */
 private void showUnexpectedErrorMsg(Exception e) {
		e.printStackTrace();
		String msg = Messages.getString("OpenFileAction.Unexpected_ErrMsg_Part1")+fileName +Messages.getString("OpenFileAction.Unexpected_ErrMsg_Part2") +projectName +"'."; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		String consoleMsg = msg +Messages.getString("OpenFileAction.Unexpected_ErrMsg_Part3") +e; //$NON-NLS-1$
		APIQueryConsole.getInstance().println(consoleMsg, APIQueryConsole.MSG_ERROR);
		showErrorMessage(msg);
	}



	/**
	 * Show an error message to user and logs same message to console.
	 * @param message
	 */
	private void showErrorMessage(final String message) {
		APIQueryConsole.getInstance().println(message, APIQueryConsole.MSG_ERROR);		
		Runnable run = new Runnable(){
			public void run(){
				new APIQueryMessageBox(message,
						SWT.ICON_ERROR | SWT.OK).open();
				
			}
		};
		Display.getDefault().asyncExec(run);
	}
	


	/** 
	 * Check recursively all folders inside given resources and seeks give file
	 * @param fileName
	 * @param members
	 * @return resources found
	 * @throws CoreException
	 */
	private Vector<IResource> getMatchingResources(String fileName,
			IResource[] members) throws CoreException {
		Vector<IResource> files = new Vector<IResource>();

		for (int i = 0; i < members.length; i++) {
			IResource res = members[i];
			//If resource is folder, seeking all folders and files under it
			if (res instanceof IFolder) {
				IFolder fold = (IFolder) res;
				IResource[] folderMembers = fold.members();
				files.addAll(getMatchingResources(fileName, folderMembers));
			}
			//If resource is file, checking if thats file we are interest of
			else if (res instanceof IFile) {

				String name = res.getName();
				//If file name match to resource name adding to
				if (fileName.equalsIgnoreCase(name)) {
					files.add(res);
				}else if(fileName.equalsIgnoreCase(res.getProjectRelativePath().toOSString())){
					files.add(res);
				}
			}
			//Else we have no interest of resource
		}
		return files;
	}
	
	/**
	 * Open file given to Editor area. 
	 * @param uri
	 * @param fileName
	 */
	public void openFile(final URI uri, final String fileName) {		
		
		//Runnable to open new file
		final Runnable runOpen = new Runnable() {
			public void run() {
				// do the actual work in here
								
				try {
					IWorkbench workbench = PlatformUI.getWorkbench();
					IWorkbenchPage page = APIQueryPlugin.getCurrentlyActivePage();
					//Find default editor for that file
					IEditorRegistry reg = workbench.getEditorRegistry();					
					IEditorDescriptor editor = reg.getDefaultEditor(fileName);
					//We open editor by it's ID
					final String editorId = editor.getId();
					//Opening file in editor
					IDE.openEditor(page, uri, editorId, true);
					
				} catch (Exception e) {
					showUnexpectedErrorMsg(e);
				} 

			}
		};		
		Display.getDefault().asyncExec(runOpen);
	}	
	

	/**
	 * Open file to Editor area
	 * @param file
	 * @throws URISyntaxException 
	 */
	private void openFile(File file) throws URISyntaxException {
		String path = file.getAbsolutePath();
		String uriStr = path.replace("\\", "/");; //$NON-NLS-1$ //$NON-NLS-2$
		uriStr = "file://" + uriStr; //$NON-NLS-1$			
		URI uri = new URI(uriStr);
		openFile(uri, file.getName());
	}	
	
	/**
	 * Opens file from SDK. Projects default build configuration is used as SDK,
	 * MMP files from that project is seeked, and file is seeked under inc paths found in 
	 * MMP files.
	 * 
	 * File is opened or error message is shown when done.
	 * 
	 * @param fileName
	 * @param projectName
	 */
	public void openFileFromSDK(String fileName, String projectName) {

		this.fileName = fileName;
		this.projectName = projectName;
		try {
			//Get project by name
			IProject project = getProject(projectName);
			//Gets Include paths for project. Header files must be found from includepaths.
			List<File> paths = getIncludePaths(project);
			APIQueryConsole.getInstance().println(
					Messages.getString("OpenFileAction.TargetFound_Msg_Part1") +sdkUniqueId  //$NON-NLS-1$
					+Messages.getString("OpenFileAction.TargetFound_Msg_Part2") +projectName  //$NON-NLS-1$
					+Messages.getString("OpenFileAction.TargetFound_Msg_Part3") +fileName +"'."); //$NON-NLS-1$ //$NON-NLS-2$
			
			//Seeking paths where file(s) are found
			//it will happened asynchronously, and when done, file will be opened.
			findFiles(fileName, paths);
			
		} catch (QueryOperationFailedException e) {
			showErrorMessage(e.getMessage());
		}catch (Exception e) {
			showUnexpectedErrorMsg(e);
		}
		

	}


	/**
	 * Get include paths for project
	 * @param project
	 * @return absolutely include paths for project, found in MMP files.
	 * @throws QueryOperationFailedException 
	 */
	private List<File> getIncludePaths(IProject project) throws QueryOperationFailedException {
		List<File> paths = new ArrayList<File>();
		
		ICarbideBuildManager buildMgr = CarbideBuilderPlugin.getBuildManager();
		ICarbideProjectInfo cpi = null;
		if (buildMgr.isCarbideProject(project)){
		  // check to make sure this is a Carbide project
		  cpi = buildMgr.getProjectInfo(project);
			// Get the default build configuration
			ICarbideBuildConfiguration defaultConfig = cpi.getDefaultConfiguration();
			sdkUniqueId = defaultConfig.getSDK().getUniqueId();
			
			List<File> _userPaths = new ArrayList<File>();
			List<File> _systemPaths = new ArrayList<File>();
			EpocEngineHelper.getProjectIncludePaths(cpi, defaultConfig, _userPaths, _systemPaths) ;
			paths.addAll(_userPaths);
			paths.addAll(_systemPaths);
		}		
		else{
			throw new QueryOperationFailedException(Messages.getString("OpenFileAction.NotCarbideProject_ErrMsg_Part1") +projectName +Messages.getString("OpenFileAction.NotCarbideProject_ErrMsg_Part2")); //$NON-NLS-1$ //$NON-NLS-2$
		}

		
		return paths;
	}

	/**
	 * Get project by name.
	 * @param projectName
	 * @return project
	 * @throws CoreException 
	 * @throws QueryOperationFailedException 
	 */
	private IProject getProject(String projectName) throws CoreException, QueryOperationFailedException {
		IProject prj = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
		if(!prj.exists()){
			 throw new QueryOperationFailedException (Messages.getString("OpenFileAction.ProjectNotExist_ErrMsg_Part1") +projectName +Messages.getString("OpenFileAction.ProjectNotExist_ErrMsg_Part2")); //$NON-NLS-1$ //$NON-NLS-2$
		}
		if(!prj.isOpen()){
			//If project is closed, just opening it before returning
			prj.open(new NullProgressMonitor());
		}
		prj.getWorkspace();
		return prj;
	}


	
	/**
	 * Find file under folders given
	 * @param fileName
	 * @param includePaths
	 */
	private void findFiles(String fileName, List<File> includePaths) {
			//	System.out.println(Messages.getString("OpenFileAction.18")); //$NON-NLS-1$
		FindFileFromFoldersJob job = new FindFileFromFoldersJob(Messages.getString("OpenFileAction.JobName_Msg") +fileName, includePaths, fileName, sdkUniqueId); //$NON-NLS-1$
		job.setPriority(Job.DECORATE);
		//Listener will be called when seeking is done
		job.addJobChangeListener(this);
		job.schedule();	
		
	}




	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void done(IJobChangeEvent event) {

		//
		// When job is done, this will be called, and found file will be opened

		try {
			FindFileFromFoldersJob job = (FindFileFromFoldersJob) event
					.getJob();
			Collection<File> files = job.getFoundSourceFiles();

			if (files.isEmpty()) {
				String message = Messages.getString("OpenFileAction.CannotFoundFile_Msg_Part1") + fileName //$NON-NLS-1$
						+ Messages.getString("OpenFileAction.CannotFoundFile_Msg_Part2") + sdkUniqueId //$NON-NLS-1$
						+ "'."; //$NON-NLS-1$
				showErrorMessage(message);
			}
			//Else we just open first file that we found
			else{
				File file = ((File[]) files.toArray(new File[0]))[0];
				openFile(file);
			}
		} catch (Exception e) {
			showUnexpectedErrorMsg(e);
		}

	}



	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#aboutToRun(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void aboutToRun(IJobChangeEvent event) {
		//Not needed
	}


	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#awake(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void awake(IJobChangeEvent event) {
		//Not needed
		
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#running(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void running(IJobChangeEvent event) {
		//Not needed		
	}


	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#scheduled(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void scheduled(IJobChangeEvent event) {
		//Not needed		
	}


	/* (non-Javadoc)
	 * @see org.eclipse.core.runtime.jobs.IJobChangeListener#sleeping(org.eclipse.core.runtime.jobs.IJobChangeEvent)
	 */
	public void sleeping(IJobChangeEvent event) {
		//Not needed		
	}



}