blob: 01f7bf0d1db553bb51f66a56bc5c79127793825a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2009 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
* QNX Software System
* Sergey Prigogin, Google - https://bugs.eclipse.org/bugs/show_bug.cgi?id=13221
* Ed Swartz (Nokia)
* Anton Leherbauer (Wind River Systems)
*******************************************************************************/
package org.eclipse.ptp.internal.rdt.ui.editor;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.IInclude;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IExtendedScannerInfo;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.IScannerInfoProvider;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
import org.eclipse.cdt.internal.ui.CPluginImages;
import org.eclipse.cdt.internal.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.cdt.internal.ui.util.EditorUtility;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.utils.PathUtil;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.ptp.rdt.core.RDTLog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
/**
* Action to open an include file from the Outline view
* @author vkong
*
*/
public class OpenIncludeAction extends
org.eclipse.cdt.internal.ui.editor.OpenIncludeAction {
private static final String PREFIX= "OpenIncludeAction."; //$NON-NLS-1$
private static final String DIALOG_TITLE= PREFIX + "dialog.title"; //$NON-NLS-1$
private static final String DIALOG_MESSAGE= PREFIX + "dialog.message"; //$NON-NLS-1$
private ISelectionProvider fSelectionProvider;
public OpenIncludeAction(ISelectionProvider provider) {
super(provider);
setDescription(CUIPlugin.getResourceString(PREFIX + "description")); //$NON-NLS-1$
setToolTipText(CUIPlugin.getResourceString(PREFIX + "tooltip")); //$NON-NLS-1$
CPluginImages.setImageDescriptors(this, CPluginImages.T_LCL, CPluginImages.IMG_MENU_OPEN_INCLUDE);
fSelectionProvider= provider;
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.ui.editor.OpenIncludeAction#run()
*/
@Override
public void run() {
IInclude include= getIncludeStatement(fSelectionProvider.getSelection());
if (include == null) {
return;
}
try {
ArrayList<URI> filesFound = new ArrayList<URI>(4);
IResource res = include.getUnderlyingResource(); //the resource that contains this include
String fullFileName= include.getFullFileName(); //the full path, if there is one
if (fullFileName != null) {
IPath fullPath= new Path(fullFileName);
if (fullPath.isAbsolute() && fullPath.toFile().exists()) { //local
filesFound.add(fullPath.toFile().toURI());
}
if (filesFound.isEmpty()) {
//remote: get host information and try again
URI locationURI = include.getLocationURI(); //the location of the innermost file enclosing this include
URI includeURI = replacePath(locationURI, fullFileName);
IFileStore fileStore = EFS.getStore(includeURI);
if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) {
filesFound.add(includeURI);
}
}
}
if (filesFound.isEmpty() && res != null) {
boolean isSystemInclude = include.isStandard();
IProject proj = res.getProject();
String includeName = include.getElementName();
URI locationURI = include.getLocationURI(); //the location of the innermost file enclosing this include
// Search in the scannerInfo information
IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(proj);
if (provider != null) {
IScannerInfo info = provider.getScannerInformation(res);
// XXXX this should fall back to project by itself
if (info == null) {
info = provider.getScannerInformation(proj);
}
if (info != null) {
IExtendedScannerInfo scanInfo = new ExtendedScannerInfo(info);
if (!isSystemInclude) {
IPath pathURI = new Path(locationURI.toString());
// search in current directory
if (pathURI != null) {
String currentDir= pathURI.removeLastSegments(1).toOSString();
findFile(new String[] { currentDir }, includeName, filesFound);
}
if (filesFound.isEmpty()) {
// search in "..." include directories
String[] localIncludePaths = scanInfo.getLocalIncludePath();
String[] includePaths = new String[localIncludePaths.length];
for (int i = 0; i < localIncludePaths.length; i++) {
includePaths[i] = locationURI.getScheme() + "://" + locationURI.getHost() + new String(localIncludePaths[i]); //$NON-NLS-1$
}
findFile(includePaths, includeName, filesFound);
}
}
if (filesFound.isEmpty()) {
// search in <...> include directories
String[] includePaths = scanInfo.getIncludePaths(); //these include paths do not have host information
String[] newIncludePaths = new String[includePaths.length];
for (int i = 0; i < includePaths.length; i++) {
newIncludePaths[i] = locationURI.getScheme() + "://" + locationURI.getHost() + new String(includePaths[i]); //$NON-NLS-1$
}
findFile(newIncludePaths, includeName, filesFound);
}
}
if (filesFound.isEmpty()) {
// Fall back and search the project
IResource resource = include.getCProject().getProject().findMember(include.getElementName());
if (!isSystemInclude && resource != null && resource instanceof IFile)
filesFound.add(resource.getLocationURI());
}
}
}
Object fileToOpen;
int nElementsFound= filesFound.size();
if (nElementsFound == 0) {
noElementsFound();
fileToOpen= null;
} else if (nElementsFound == 1) {
fileToOpen= filesFound.get(0);
} else {
fileToOpen= chooseFile(filesFound);
}
if (fileToOpen != null)
EditorUtility.openInEditor((URI)fileToOpen, include.getCProject());
} catch (CModelException e) {
CUIPlugin.log(e.getStatus());
} catch (CoreException e) {
CUIPlugin.log(e.getStatus());
}
}
/**
*
*/
private void noElementsFound() {
MessageBox errorMsg = new MessageBox(CUIPlugin.getActiveWorkbenchShell(), SWT.ICON_ERROR | SWT.OK);
errorMsg.setText(CUIPlugin.getResourceString("OpenIncludeAction.error")); //$NON-NLS-1$
errorMsg.setMessage (CUIPlugin.getResourceString("OpenIncludeAction.error.description")); //$NON-NLS-1$
errorMsg.open();
}
private boolean isInProject(IPath path) {
return getWorkspaceRoot().getFileForLocation(path) != null;
}
/**
* Returns the path as is, if it points to a workspace resource. If the path
* does not point to a workspace resource, but there are linked workspace
* resources pointing to it, returns the paths of these resources.
* Otherwise, returns the path as is.
*/
private IPath[] resolveIncludeLink(IPath path) {
if (!isInProject(path)) {
IFile[] files = ResourceLookup.findFilesForLocation(path);
if (files.length > 0) {
IPath[] paths = new IPath[files.length];
for (int i = 0; i < files.length; i++) {
paths[i] = files[i].getFullPath();
}
return paths;
}
}
return new IPath[] { path };
}
private IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
private void findFile(String[] includePaths, String name, ArrayList<URI> list)
throws CoreException {
// in case it is an absolute path and it's local
IPath includeFile= new Path(name);
if (includeFile.isAbsolute()) {
includeFile = PathUtil.getCanonicalPath(includeFile);
if (includeFile.toFile().exists()) {
list.add(includeFile.toFile().toURI());
return;
}
}
HashSet<IPath> foundSet = new HashSet<IPath>();
for (String includePath : includePaths) {
IPath path = PathUtil.getCanonicalPath(new Path(includePath).append(includeFile));
//local case:
File file = path.toFile();
if (file.exists()) {
IPath[] paths = resolveIncludeLink(path);
for (IPath p : paths) {
if (foundSet.add(p)) {
list.add(p.toFile().toURI());
}
}
} else { //remote case include paths:
try {
URI uri = new URI(path.toPortableString());
IFileStore fileStore = EFS.getStore(uri);
if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) {
list.add(uri);
}
} catch (URISyntaxException e) {
RDTLog.logError(e);
}
}
}
}
private Object chooseFile(ArrayList<URI> filesFound) {
ILabelProvider renderer= new LabelProvider() {
@Override
public String getText(Object element) {
if (element instanceof URI) {
URI uri= (URI)element;
IPath path = new Path(uri.getPath());
return path.lastSegment() + " - " + path.toString(); //$NON-NLS-1$
}
return super.getText(element);
}
};
ElementListSelectionDialog dialog= new ElementListSelectionDialog(CUIPlugin.getActiveWorkbenchShell(), renderer, false, false);
dialog.setTitle(CUIPlugin.getResourceString(DIALOG_TITLE));
dialog.setMessage(CUIPlugin.getResourceString(DIALOG_MESSAGE));
dialog.setElements(filesFound);
if (dialog.open() == Window.OK) {
return (IFile)((IPath) dialog.getSelectedElement()).toFile();
}
return null;
}
private static IInclude getIncludeStatement(ISelection sel) {
if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
List<?> list= ((IStructuredSelection)sel).toList();
if (list.size() == 1) {
Object element= list.get(0);
if (element instanceof IInclude) {
return (IInclude)element;
}
}
}
return null;
}
/**
* Replaces the path portion of the given URI.
*/
private URI replacePath(URI u, String path) {
try {
return new URI(u.getScheme(), u.getUserInfo(), u.getHost(), u.getPort(),
path, // replaced!
u.getQuery(),u.getFragment());
} catch (URISyntaxException e) {
RDTLog.logError(e);
return null;
}
}
}