blob: 77aaf09dea2756d7366081aa8b1fee5d8c0d6386 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign 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:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IContainer;
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.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.rephraserengine.core.resources.DefaultResourceFilter;
import org.eclipse.rephraserengine.core.resources.IResourceFilter;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Class providing information about the active page/editor/shell, current selection, etc. in the
* Eclipse workbench.
* <p>
* This information is populated immediately when the class is constructed and is not updated. If
* the workbench selection changes between the time this object is constructed and the time one of
* its methods is called, the information provided will be based on the old selection (i.e., what
* was selected when the constructor was called). Thus, {@link WorkbenchSelectionInfo} objects
* should be created and then immediately used and disposed of.
*
* @author Jeff Overbey, Tim Yuvashev
*/
@SuppressWarnings("restriction")
public class WorkbenchSelectionInfo
{
private IResourceFilter resourceFilter;
private String errorMsg;
private IEditorPart activeEditor;
private IFile fileInEditor;
private ISelection selection;
private List<IResource> selectedResources;
private List<IFile> allFilesInSelectedResources;
private ITextSelection selectionInEditor;
private Boolean someFilesAreSelected;
/**
* Default constructor; uses a {@link DefaultResourceFilter} and tracks the selection in the
* active workbench window.
*
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public WorkbenchSelectionInfo()
{
this(new DefaultResourceFilter());
}
/**
* Constructor; uses the given resource filter and tracks the selection in the active workbench
* window.
*
* @param resourceFilter the resource filter that will be used to determine what resources are
* included in the results of {@link #getAllFilesInSelectedResources()}
* and {@link #getFileInEditor()}
*/
public WorkbenchSelectionInfo(IResourceFilter resourceFilter)
{
this(resourceFilter, Workbench.getInstance().getActiveWorkbenchWindow());
}
/**
* Constructor; uses a {@link DefaultResourceFilter} and tracks the selection in the active
* workbench window.
*
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public WorkbenchSelectionInfo(IWorkbenchWindow workbenchWindow)
{
this(new DefaultResourceFilter(), workbenchWindow);
}
/**
* Constructor; uses the given resource filter and tracks the selection in the given workbench
* window.
*
* @param resourceFilter the resource filter that will be used to determine what resources are
* included in the results of {@link #getAllFilesInSelectedResources()}
* and {@link #getFileInEditor()}
* @param workbenchWindow the workbench window whose selection will be tracked
*/
public WorkbenchSelectionInfo(IResourceFilter resourceFilter, IWorkbenchWindow workbenchWindow)
{
this.resourceFilter = resourceFilter;
selection = null;
selectedResources = Collections.<IResource>emptyList();
activeEditor = null;
fileInEditor = null;
selectionInEditor = null;
if (workbenchWindow == null) return;
selection = workbenchWindow.getSelectionService().getSelection();
if (selection instanceof IStructuredSelection)
{
selectedResources = getResourcesSelectedIn((IStructuredSelection)selection);
allFilesInSelectedResources = null; // Populate on demand (see getAllFilesInSelectedResources())
}
IWorkbenchPage activePage = workbenchWindow.getActivePage();
if (activePage == null) return;
activeEditor = activePage.getActiveEditor();
if (activeEditor == null) return;
IEditorInput input = activeEditor.getEditorInput();
if (!(input instanceof IFileEditorInput)) return;
IFileEditorInput fileInput = (IFileEditorInput)input;
fileInEditor = fileInput.getFile();
if (!resourceFilter.shouldProcess(fileInEditor))
{
errorMsg = resourceFilter.getError(fileInEditor);
fileInEditor = null;
}
if (selection instanceof ITextSelection)
{
selectionInEditor = (ITextSelection)selection;
if (fileInEditor != null)
{
selectedResources = Collections.<IResource>singletonList(fileInEditor);
allFilesInSelectedResources = Collections.<IFile>singletonList(fileInEditor);
}
}
}
private List<IResource> getResourcesSelectedIn(IStructuredSelection selection)
{
List<IResource> result = new ArrayList<IResource>();
for (Object selectedItem : selection.toList())
{
if (selectedItem instanceof IAdaptable)
{
IAdaptable item = (IAdaptable)selectedItem;
IResource res = (IResource)item.getAdapter(IResource.class);
if (res != null)
{
if (resourceFilter.shouldProcess(res))
result.add(res);
else
errorMsg = resourceFilter.getError(res);
}
}
}
if (!result.isEmpty()) errorMsg = null;
return result;
}
/**
* Returns true if there is at least one file selected.
* <p>
* If the <code>canGuess</code> parameter is <code>true</code>, folders and projects will not be
* traversed recursively; instead, the method will optimistically return true iff the project is
* refactorable. The caller must then test whether {@link #getAllFilesInSelectedResources()} is
* empty. This can be used to improve performance.
* <p>
* If the <code>canGuess</code> parameter is <code>false<c/ode>, then this method returns true
* iff {@link #getAllFilesInSelectedResources()} is non-empty.
*/
public boolean someFilesAreSelected(boolean canGuess)
{
if (someFilesAreSelected == null)
someFilesAreSelected = internalSomeFilesAreSelected(canGuess);
return someFilesAreSelected;
}
public boolean someFilesAreSelected()
{
return someFilesAreSelected(false);
}
private boolean internalSomeFilesAreSelected(boolean canGuess)
{
if (allFilesInSelectedResources != null)
return !allFilesInSelectedResources.isEmpty();
else
return internalSomeFilesAreSelected(
selectedResources.toArray(new IResource[selectedResources.size()]),
canGuess);
}
private boolean internalSomeFilesAreSelected(IResource[] resources, boolean canGuess)
{
for (IResource r : resources)
{
if (resourceFilter.shouldProcess(r))
{
if (r instanceof IFile)
{
return true;
}
else if (r instanceof IFolder || r instanceof IProject)
{
if (r.isAccessible())
{
if (canGuess)
{
// Guess that there are resources iff the project is refactorable
return resourceFilter.shouldProcess(r.getProject());
}
else
{
try
{
if (internalSomeFilesAreSelected(((IContainer)r).members(), canGuess))
return true;
}
catch (CoreException e)
{
e.printStackTrace();
}
}
}
}
}
}
return false;
}
/** @return true iff the active editor in the workbench is editing a document based on an
* {@link IFile}, and that file was accepted by the resource filter passed to the
* <code>WorkbenchSelectionInfo</code> constructor
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public boolean editingAnIFile()
{
return fileInEditor != null;
}
/**
* @return the active editor in the workbench, or <code>null</code> if no editor is active
*/
public IEditorPart getActiveEditor()
{
return activeEditor;
}
/**
* @return the active editor in the workbench, if it is a text editor, or <code>null</code>
* if no editor is active or it is not a text editor
*/
public ITextEditor getActiveTextEditor()
{
return activeEditor instanceof ITextEditor ? (ITextEditor)activeEditor : null;
}
/** @return the file open in the active editor in the workbench, or <code>null</code> if there
* is no editor open, it is editing a document not based on an {@link IFile}, or the
* file being edited was not accepted by the resource filter passed to the
* <code>WorkbenchSelectionInfo</code> constructor
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public IFile getFileInEditor()
{
return fileInEditor;
}
/** @return true iff the active editor in the workbench is a text editor, and the current
* workbench selection is a text selection
*/
public boolean isTextSelectedInEditor()
{
return selectionInEditor != null;
}
/** @return the text selection in the active editor in the workbench (if the active editor is a
* text editor and the current workbench selection is a text selection), or
* <code>null</code>
*/
public ITextSelection getSelectionInEditor()
{
return selectionInEditor;
}
/**
* @return the contents of the active editor in the workbench (if the active editor is a
* text editor and its contents can be retrieved), or <code>null</code> otherwise.
* Note that, if the editor's contents have not been saved, the <i>unsaved</i>
* version (i.e., the current text in the editor) will be returned.
*/
public String getEditorContents()
{
if (activeEditor == null || !(activeEditor instanceof ITextEditor)) return null;
ITextEditor textEditor = (ITextEditor)activeEditor;
IDocumentProvider dp = textEditor.getDocumentProvider();
if (dp == null) return null;
IDocument doc = dp.getDocument(textEditor.getEditorInput());
if (doc == null) return null;
return doc.get();
}
/**
* Returns a list of all of the resources in the current workbench selection.
* <p>
* If the user has selected one or more resources (i.e., files, folder, or projects, usually
* selected in the Project Explorer view), then this list will include all of those resources
* that are acceptable to the resource filter passed to the <code>WorkbenchSelectionInfo</code>
* constructor.
* <p>
* If the selection includes projects or folders, the {@link IResource} objects for the projects
* or folders themselves will be returned. To traverse these recursively and retrieve the files
* in them, use {@link #getAllFilesInSelectedResources()} instead.
* <p>
* If the user has selected text in a text editor, and the active editor in the workbench is
* editing a document based on an {@link IFile}, and that file was accepted by the resource
* filter passed to the <code>WorkbenchSelectionInfo</code> constructor, then this list contains
* only one file: the file in the active editor.
*
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public List<IResource> getSelectedResources()
{
return selectedResources;
}
/**
* Returns a list of all acceptable files in the current workbench selection.
* <p>
* If the user has selected one or more resources (i.e., files, folder, or projects, usually
* selected in the Project Explorer view), then this list will include all of the files in the
* selected resources that are acceptable to the resource filter passed to the
* <code>WorkbenchSelectionInfo</code> constructor. Projects and folders acceptable to the
* resource filter are traversed recursively, so this list will include all acceptable files
* in those resources.
* <p>
* If the user has selected text in a text editor, and the active editor in the workbench is
* editing a document based on an {@link IFile}, and that file was accepted by the resource
* filter passed to the <code>WorkbenchSelectionInfo</code> constructor, then this list contains
* only one file: the file in the active editor.
*
* @see #WorkbenchSelectionInfo(IResourceFilter)
*/
public List<IFile> getAllFilesInSelectedResources()
{
if (allFilesInSelectedResources == null)
allFilesInSelectedResources = findAllFilesIn(selectedResources);
return allFilesInSelectedResources;
}
private List<IFile> findAllFilesIn(Collection<IResource> resources)
{
return findAllFilesIn(resources.toArray(new IResource[resources.size()]));
}
private List<IFile> findAllFilesIn(IResource[] resources)
{
ArrayList<IFile> files = new ArrayList<IFile>();
for (IResource r : resources)
{
if (resourceFilter.shouldProcess(r))
{
if (r instanceof IFile)
{
files.add((IFile)r);
}
else if (r instanceof IFolder || r instanceof IProject)
{
if (r.isAccessible())
{
try
{
files.addAll(findAllFilesIn(((IContainer)r).members()));
}
catch (CoreException e)
{
e.printStackTrace();
}
}
}
}
}
return files;
}
/**
* @return an error message to display to the user, if all of the files in the selection were
* filtered out, which describes why that happened and possibly what the user can do about it;
* may be <code>null</code>
*/
public String getErrorMessage()
{
return errorMsg;
}
}