blob: 180123459efd862fe4874a3c7e98be7171b73333 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 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
* James Blackburn (Broadcom Corp.) Bug 86973 Allow path pattern matching
* Anton Leherbauer (Wind River Systems, Inc.) - Bug 415099 Terminating with "<" or " " (space) does not work for extensions
* Mickael Istria (Red Hat Inc.) - Bug 460749: filter resources with same location
*******************************************************************************/
package org.eclipse.ui.dialogs;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.IWorkspace;
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.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ResourceWorkingSetFilter;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.ide.model.ResourceFactory;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.statushandlers.StatusManager;
import com.ibm.icu.text.Collator;
/**
* Shows a list of resources to the user with a text entry field for a string
* pattern used to filter the list of resources.
*
* @since 3.3
*/
public class FilteredResourcesSelectionDialog extends
FilteredItemsSelectionDialog {
private static final String DIALOG_SETTINGS = "org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog"; //$NON-NLS-1$
private static final String WORKINGS_SET_SETTINGS = "WorkingSet"; //$NON-NLS-1$
private static final String SHOW_DERIVED = "ShowDerived"; //$NON-NLS-1$
private static final String FILTER_BY_LOCATION = "FilterByLocation"; //$NON-NLS-1$
private ShowDerivedResourcesAction showDerivedResourcesAction;
private ResourceItemLabelProvider resourceItemLabelProvider;
private ResourceItemDetailsLabelProvider resourceItemDetailsLabelProvider;
private WorkingSetFilterActionGroup workingSetFilterActionGroup;
private CustomWorkingSetFilter workingSetFilter = new CustomWorkingSetFilter();
private FilterResourcesByLocation filterResourceByLocation = new FilterResourcesByLocation();
private GroupResourcesByLocationAction groupResourcesByLocationAction;
private String title;
/**
* The base outer-container which will be used to search for resources. This
* is the root of the tree that spans the search space. Often, this is the
* workspace root.
*/
private IContainer container;
/**
* The container to use as starting point for relative search, or
* <code>null</code> if none.
* @since 3.6
*/
private IContainer searchContainer;
private int typeMask;
private boolean isDerived;
/**
* Creates a new instance of the class
*
* @param shell
* the parent shell
* @param multi
* the multi selection flag
* @param container
* the container to select resources from, e.g. the workspace root
* @param typesMask
* a mask specifying which resource types should be shown in the dialog.
* The mask should contain one or more of the resource type bit masks
* defined in {@link IResource#getType()}
*/
public FilteredResourcesSelectionDialog(Shell shell, boolean multi,
IContainer container, int typesMask) {
super(shell, multi);
setSelectionHistory(new ResourceSelectionHistory());
setTitle(IDEWorkbenchMessages.OpenResourceDialog_title);
setMessage(IDEWorkbenchMessages.OpenResourceDialog_message);
/*
* Allow location of paths relative to a searchContainer, which is
* initialized from the active editor or the selected element.
*/
IWorkbenchWindow ww = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (ww != null) {
IWorkbenchPage activePage = ww.getActivePage();
if (activePage != null) {
IResource resource = null;
IEditorPart activeEditor = activePage.getActiveEditor();
if (activeEditor != null && activeEditor == activePage.getActivePart()) {
IEditorInput editorInput = activeEditor.getEditorInput();
resource = ResourceUtil.getResource(editorInput);
} else {
ISelection selection = ww.getSelectionService().getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
if (structuredSelection.size() == 1) {
resource = ResourceUtil.getResource(structuredSelection.getFirstElement());
}
}
}
if (resource != null) {
if (!(resource instanceof IContainer)) {
resource = resource.getParent();
}
searchContainer = (IContainer) resource;
}
}
}
this.container = container;
this.typeMask = typesMask;
resourceItemLabelProvider = new ResourceItemLabelProvider();
resourceItemDetailsLabelProvider = new ResourceItemDetailsLabelProvider();
setListLabelProvider(resourceItemLabelProvider);
setDetailsLabelProvider(resourceItemDetailsLabelProvider);
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IIDEHelpContextIds.OPEN_RESOURCE_DIALOG);
}
@Override
public void setTitle(String title) {
super.setTitle(title);
this.title = title;
}
/**
* Adds or replaces subtitle of the dialog
*
* @param text
* the new subtitle
*/
private void setSubtitle(String text) {
if (text == null || text.length() == 0) {
getShell().setText(title);
} else {
getShell().setText(title + " - " + text); //$NON-NLS-1$
}
}
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = IDEWorkbenchPlugin.getDefault()
.getDialogSettings().getSection(DIALOG_SETTINGS);
if (settings == null) {
settings = IDEWorkbenchPlugin.getDefault().getDialogSettings()
.addNewSection(DIALOG_SETTINGS);
}
return settings;
}
@Override
protected void storeDialog(IDialogSettings settings) {
super.storeDialog(settings);
settings.put(SHOW_DERIVED, showDerivedResourcesAction.isChecked());
settings.put(FILTER_BY_LOCATION, this.groupResourcesByLocationAction.isChecked());
XMLMemento memento = XMLMemento.createWriteRoot("workingSet"); //$NON-NLS-1$
workingSetFilterActionGroup.saveState(memento);
workingSetFilterActionGroup.dispose();
StringWriter writer = new StringWriter();
try {
memento.save(writer);
settings.put(WORKINGS_SET_SETTINGS, writer.getBuffer().toString());
} catch (IOException e) {
StatusManager.getManager().handle(
new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
IStatus.ERROR, "", e)); //$NON-NLS-1$
// don't do anything. Simply don't store the settings
}
}
@Override
protected void restoreDialog(IDialogSettings settings) {
super.restoreDialog(settings);
boolean showDerived = settings.getBoolean(SHOW_DERIVED);
showDerivedResourcesAction.setChecked(showDerived);
this.isDerived = showDerived;
boolean groupByLoation = settings.getBoolean(FILTER_BY_LOCATION);
this.groupResourcesByLocationAction.setChecked(groupByLoation);
this.filterResourceByLocation.setEnabled(groupByLoation);
addListFilter(this.filterResourceByLocation);
String setting = settings.get(WORKINGS_SET_SETTINGS);
if (setting != null) {
try {
IMemento memento = XMLMemento.createReadRoot(new StringReader(
setting));
workingSetFilterActionGroup.restoreState(memento);
} catch (WorkbenchException e) {
StatusManager.getManager().handle(
new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
IStatus.ERROR, "", e)); //$NON-NLS-1$
// don't do anything. Simply don't restore the settings
}
}
addListFilter(workingSetFilter);
applyFilter();
}
@Override
protected void fillViewMenu(IMenuManager menuManager) {
super.fillViewMenu(menuManager);
showDerivedResourcesAction = new ShowDerivedResourcesAction();
menuManager.add(showDerivedResourcesAction);
this.groupResourcesByLocationAction = new GroupResourcesByLocationAction();
menuManager.add(this.groupResourcesByLocationAction);
workingSetFilterActionGroup = new WorkingSetFilterActionGroup(
getShell(), event -> {
String property = event.getProperty();
if (WorkingSetFilterActionGroup.CHANGE_WORKING_SET
.equals(property)) {
IWorkingSet workingSet = (IWorkingSet) event
.getNewValue();
if (workingSet != null
&& !(workingSet.isAggregateWorkingSet() && workingSet
.isEmpty())) {
workingSetFilter.setWorkingSet(workingSet);
setSubtitle(workingSet.getLabel());
} else {
IWorkbenchWindow window = PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window
.getActivePage();
workingSet = page.getAggregateWorkingSet();
if (workingSet.isAggregateWorkingSet()
&& workingSet.isEmpty()) {
workingSet = null;
}
}
workingSetFilter.setWorkingSet(workingSet);
setSubtitle(null);
}
scheduleRefresh();
}
});
menuManager.add(new Separator());
workingSetFilterActionGroup.fillContextMenu(menuManager);
}
@Override
protected Control createExtendedContentArea(Composite parent) {
return null;
}
@Override
public Object[] getResult() {
Object[] result = super.getResult();
if (result == null)
return null;
List resultToReturn = new ArrayList();
for (Object element : result) {
if (element instanceof IResource) {
resultToReturn.add((element));
}
}
return resultToReturn.toArray();
}
@Override
public int open() {
if (getInitialPattern() == null) {
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
if (window != null) {
ISelection selection = window.getSelectionService()
.getSelection();
if (selection instanceof ITextSelection) {
String text = ((ITextSelection) selection).getText();
if (text != null) {
text = text.trim();
if (text.length() > 0) {
IWorkspace workspace = ResourcesPlugin
.getWorkspace();
IStatus result = workspace.validateName(text,
IResource.FILE);
if (result.isOK()) {
setInitialPattern(text);
}
}
}
}
}
}
return super.open();
}
@Override
public String getElementName(Object item) {
IResource resource = (IResource) item;
return resource.getName();
}
@Override
protected IStatus validateItem(Object item) {
return new Status(IStatus.OK, WorkbenchPlugin.PI_WORKBENCH, 0, "", null); //$NON-NLS-1$
}
@Override
protected ItemsFilter createFilter() {
return new ResourceFilter(container, searchContainer, isDerived, typeMask);
}
@Override
protected void applyFilter() {
super.applyFilter();
}
@Override
protected Comparator getItemsComparator() {
return (o1, o2) -> {
Collator collator = Collator.getInstance();
IResource resource1 = (IResource) o1;
IResource resource2 = (IResource) o2;
String s1 = resource1.getName();
String s2 = resource2.getName();
// Compare names without extension first
int s1Dot = s1.lastIndexOf('.');
int s2Dot = s2.lastIndexOf('.');
String n1 = s1Dot == -1 ? s1 : s1.substring(0, s1Dot);
String n2 = s2Dot == -1 ? s2 : s2.substring(0, s2Dot);
int comparability = collator.compare(n1, n2);
if (comparability != 0)
return comparability;
// Compare full names
if (s1Dot != -1 || s2Dot != -1) {
comparability = collator.compare(s1, s2);
if (comparability != 0)
return comparability;
}
// Search for resource relative paths
if (searchContainer != null) {
IContainer c11 = resource1.getParent();
IContainer c21 = resource2.getParent();
// Return paths 'closer' to the searchContainer first
comparability = pathDistance(c11) - pathDistance(c21);
if (comparability != 0)
return comparability;
}
// Finally compare full path segments
IPath p1 = resource1.getFullPath();
IPath p2 = resource2.getFullPath();
// Don't compare file names again, so subtract 1
int c12 = p1.segmentCount() - 1;
int c22 = p2.segmentCount() - 1;
for (int i= 0; i < c12 && i < c22; i++) {
comparability = collator.compare(p1.segment(i), p2.segment(i));
if (comparability != 0)
return comparability;
}
comparability = c12 - c22;
return comparability;
};
}
/**
* Return the "distance" of the item from the root of the relative search
* container. Distances can be compared (smaller numbers are better).
* <br>
* - Closest distance is if the item is the same folder as the search container.<br>
* - Next are folders inside the search container.<br>
* - After all those, distance increases with decreasing matching prefix folder count.<br>
*
* @param item
* parent of the resource being examined
* @return the "distance" of the passed in IResource from the search
* container
* @since 3.6
*/
private int pathDistance(IContainer item) {
// Container search path: e.g. /a/b/c
IPath containerPath = searchContainer.getFullPath();
// itemPath: distance:
// /a/b/c ==> 0
// /a/b/c/d/e ==> 2
// /a/b ==> Integer.MAX_VALUE/4 + 1
// /a/x/e/f ==> Integer.MAX_VALUE/4 + 2
// /g/h ==> Integer.MAX_VALUE/2
IPath itemPath = item.getFullPath();
if (itemPath.equals(containerPath))
return 0;
int matching = containerPath.matchingFirstSegments(itemPath);
if (matching == 0)
return Integer.MAX_VALUE / 2;
int containerSegmentCount = containerPath.segmentCount();
if (matching == containerSegmentCount) {
// inside searchContainer:
return itemPath.segmentCount() - matching;
}
//outside searchContainer:
return Integer.MAX_VALUE / 4 + containerSegmentCount - matching;
}
@Override
protected void fillContentProvider(AbstractContentProvider contentProvider,
ItemsFilter itemsFilter, IProgressMonitor progressMonitor)
throws CoreException {
if (itemsFilter instanceof ResourceFilter) {
IResource[] members = container.members();
progressMonitor
.beginTask(
WorkbenchMessages.FilteredItemsSelectionDialog_searchJob_taskName,
members.length);
ResourceProxyVisitor visitor = new ResourceProxyVisitor(
contentProvider, (ResourceFilter) itemsFilter,
progressMonitor);
if (visitor.visit(container.createProxy())) {
for (IResource member : members) {
if (member.isAccessible())
member.accept(visitor, IResource.NONE);
progressMonitor.worked(1);
if (progressMonitor.isCanceled())
break;
}
}
}
progressMonitor.done();
}
/**
* Sets the derived flag on the ResourceFilter instance
*/
private class ShowDerivedResourcesAction extends Action {
/**
* Creates a new instance of the action.
*/
public ShowDerivedResourcesAction() {
super(
IDEWorkbenchMessages.FilteredResourcesSelectionDialog_showDerivedResourcesAction,
IAction.AS_CHECK_BOX);
}
@Override
public void run() {
FilteredResourcesSelectionDialog.this.isDerived = isChecked();
applyFilter();
}
}
/**
* Sets the groupByLocation flag on the FilterResourceByLocation instance
*/
private class GroupResourcesByLocationAction extends Action {
/**
* Creates a new instance of the action.
*/
public GroupResourcesByLocationAction() {
super(IDEWorkbenchMessages.FilteredResourcesSelectionDialog_groupResourcesWithSameUndelyingLocation,
IAction.AS_CHECK_BOX);
}
@Override
public void run() {
FilteredResourcesSelectionDialog.this.filterResourceByLocation.setEnabled(isChecked());
scheduleRefresh();
applyFilter();
}
}
/**
* A label provider for ResourceDecorator objects. It creates labels with a
* resource full path for duplicates. It uses the Platform UI label
* decorator for providing extra resource info.
*/
private class ResourceItemLabelProvider extends LabelProvider implements
ILabelProviderListener, IStyledLabelProvider {
// Need to keep our own list of listeners
private ListenerList listeners = new ListenerList();
WorkbenchLabelProvider provider = new WorkbenchLabelProvider();
/**
* Creates a new instance of the class
*/
public ResourceItemLabelProvider() {
super();
provider.addListener(this);
}
@Override
public Image getImage(Object element) {
if (!(element instanceof IResource)) {
return super.getImage(element);
}
IResource res = (IResource) element;
return provider.getImage(res);
}
@Override
public String getText(Object element) {
if (!(element instanceof IResource)) {
return super.getText(element);
}
IResource res = (IResource) element;
String str = res.getName();
// extra info for duplicates
if (isDuplicateElement(element))
str = str
+ " - " + res.getParent().getFullPath().makeRelative().toString(); //$NON-NLS-1$
return str;
}
@Override
public StyledString getStyledText(Object element) {
if (!(element instanceof IResource)) {
return new StyledString(super.getText(element));
}
IResource res = (IResource) element;
StyledString str = new StyledString(res.getName());
// extra info for duplicates
if (isDuplicateElement(element)) {
str.append(" - ", StyledString.QUALIFIER_STYLER); //$NON-NLS-1$
str.append(res.getParent().getFullPath().makeRelative().toString(), StyledString.QUALIFIER_STYLER);
}
//Debugging:
// int pathDistance = pathDistance(res.getParent());
// if (pathDistance != Integer.MAX_VALUE / 2) {
// if (pathDistance > Integer.MAX_VALUE / 4)
// str.append(" (" + (pathDistance - Integer.MAX_VALUE / 4) + " folders up from current selection)", StyledString.QUALIFIER_STYLER);
// else
// str.append(" (" + pathDistance + " folders down from current selection)", StyledString.QUALIFIER_STYLER);
// }
return str;
}
@Override
public void dispose() {
provider.removeListener(this);
provider.dispose();
super.dispose();
}
@Override
public void addListener(ILabelProviderListener listener) {
listeners.add(listener);
}
@Override
public void removeListener(ILabelProviderListener listener) {
listeners.remove(listener);
}
@Override
public void labelProviderChanged(LabelProviderChangedEvent event) {
Object[] l = listeners.getListeners();
for (int i = 0; i < listeners.size(); i++) {
((ILabelProviderListener) l[i]).labelProviderChanged(event);
}
}
}
/**
* A label provider for details of ResourceItem objects.
*/
private class ResourceItemDetailsLabelProvider extends
ResourceItemLabelProvider {
@Override
public Image getImage(Object element) {
if (!(element instanceof IResource)) {
return super.getImage(element);
}
IResource parent = ((IResource) element).getParent();
return provider.getImage(parent);
}
@Override
public String getText(Object element) {
if (!(element instanceof IResource)) {
return super.getText(element);
}
IResource parent = ((IResource) element).getParent();
if (parent.getType() == IResource.ROOT) {
// Get readable name for workspace root ("Workspace"), without
// duplicating language-specific string here.
return null;
}
return parent.getFullPath() .makeRelative().toString();
}
@Override
public void labelProviderChanged(LabelProviderChangedEvent event) {
Object[] l = super.listeners.getListeners();
for (int i = 0; i < super.listeners.size(); i++) {
((ILabelProviderListener) l[i]).labelProviderChanged(event);
}
}
}
/**
* Viewer filter which filters resources due to current working set
*/
private class CustomWorkingSetFilter extends ViewerFilter {
private ResourceWorkingSetFilter resourceWorkingSetFilter = new ResourceWorkingSetFilter();
/**
* Sets the active working set.
*
* @param workingSet
* the working set the filter should work with
*/
public void setWorkingSet(IWorkingSet workingSet) {
resourceWorkingSetFilter.setWorkingSet(workingSet);
}
@Override
public boolean select(Viewer viewer, Object parentElement,
Object element) {
return resourceWorkingSetFilter.select(viewer, parentElement,
element);
}
}
/**
* ResourceProxyVisitor to visit resource tree and get matched resources.
* During visit resources it updates progress monitor and adds matched
* resources to ContentProvider instance.
*/
private class ResourceProxyVisitor implements IResourceProxyVisitor {
private AbstractContentProvider proxyContentProvider;
private ResourceFilter resourceFilter;
private IProgressMonitor progressMonitor;
/**
* Creates new ResourceProxyVisitor instance.
*
* @param contentProvider
* @param resourceFilter
* @param progressMonitor
* @throws CoreException
*/
public ResourceProxyVisitor(AbstractContentProvider contentProvider,
ResourceFilter resourceFilter, IProgressMonitor progressMonitor)
throws CoreException {
super();
this.proxyContentProvider = contentProvider;
this.resourceFilter = resourceFilter;
this.progressMonitor = progressMonitor;
}
@Override
public boolean visit(IResourceProxy proxy) {
if (progressMonitor.isCanceled())
return false;
IResource resource = proxy.requestResource();
proxyContentProvider.add(resource, resourceFilter);
if (resource.getType() == IResource.FOLDER && resource.isDerived()
&& !resourceFilter.isShowDerived()) {
return false;
}
if (resource.getType() == IResource.FILE) {
return false;
}
return true;
}
}
/**
* Filters resources using pattern and showDerived flag. It overrides
* ItemsFilter.
*/
protected class ResourceFilter extends ItemsFilter {
private boolean showDerived = false;
private IContainer filterContainer;
/**
* Container path pattern. Is <code>null</code> when only a file name pattern is used.
* @since 3.6
*/
private SearchPattern containerPattern;
/**
* Container path pattern, relative to the current searchContainer. Is <code>null</code> if there's no search container.
* @since 3.6
*/
private SearchPattern relativeContainerPattern;
/**
* Camel case pattern for the name part of the file name (without extension). Is <code>null</code> if there's no extension.
* @since 3.6
*/
SearchPattern namePattern;
/**
* Camel case pattern for the file extension. Is <code>null</code> if there's no extension.
* @since 3.6
*/
SearchPattern extensionPattern;
private int filterTypeMask;
/**
* Creates new ResourceFilter instance
*
* @param container
* @param showDerived
* flag which determine showing derived elements
* @param typeMask
*/
public ResourceFilter(IContainer container, boolean showDerived,
int typeMask) {
super();
this.filterContainer = container;
this.showDerived = showDerived;
this.filterTypeMask = typeMask;
}
/**
* Creates new ResourceFilter instance
*
* @param container
* @param searchContainer
* IContainer to use for performing relative search
* @param showDerived
* flag which determine showing derived elements
* @param typeMask
* @since 3.6
*/
private ResourceFilter(IContainer container, IContainer searchContainer, boolean showDerived, int typeMask) {
this(container, showDerived, typeMask);
String stringPattern = getPattern();
int matchRule = getMatchRule();
String filenamePattern;
int sep = stringPattern.lastIndexOf(IPath.SEPARATOR);
if (sep != -1) {
filenamePattern = stringPattern.substring(sep + 1, stringPattern.length());
if ("*".equals(filenamePattern)) //$NON-NLS-1$
filenamePattern= "**"; //$NON-NLS-1$
if (sep > 0) {
if (filenamePattern.length() == 0) // relative patterns don't need a file name
filenamePattern= "**"; //$NON-NLS-1$
String containerPattern = stringPattern.substring(0, sep);
if (searchContainer != null) {
relativeContainerPattern = new SearchPattern(SearchPattern.RULE_EXACT_MATCH | SearchPattern.RULE_PATTERN_MATCH);
relativeContainerPattern.setPattern(searchContainer.getFullPath().append(containerPattern).toString());
}
if (!containerPattern.startsWith("" + IPath.SEPARATOR)) //$NON-NLS-1$
containerPattern = IPath.SEPARATOR + containerPattern;
this.containerPattern= new SearchPattern(SearchPattern.RULE_EXACT_MATCH | SearchPattern.RULE_PREFIX_MATCH | SearchPattern.RULE_PATTERN_MATCH);
this.containerPattern.setPattern(containerPattern);
}
boolean isPrefixPattern = matchRule == SearchPattern.RULE_PREFIX_MATCH
|| (matchRule == SearchPattern.RULE_PATTERN_MATCH && filenamePattern.endsWith("*")); //$NON-NLS-1$
if (!isPrefixPattern)
// Add '<' again as it was removed by SearchPattern
filenamePattern += '<';
else if (filenamePattern.endsWith("*") && !filenamePattern.equals("**")) //$NON-NLS-1$ //$NON-NLS-2$
// Remove added '*' as the filename pattern might be a camel case pattern
filenamePattern = filenamePattern.substring(0, filenamePattern.length() - 1);
patternMatcher.setPattern(filenamePattern);
// Update filenamePattern and matchRule as they might have changed
filenamePattern = getPattern();
matchRule = getMatchRule();
} else {
filenamePattern= stringPattern;
}
int lastPatternDot = filenamePattern.lastIndexOf('.');
if (lastPatternDot != -1) {
if (matchRule != SearchPattern.RULE_EXACT_MATCH) {
namePattern = new SearchPattern();
namePattern.setPattern(filenamePattern.substring(0, lastPatternDot));
String extensionPatternStr = filenamePattern.substring(lastPatternDot + 1);
// Add a '<' except this is a camel case pattern or a prefix pattern
if (matchRule != SearchPattern.RULE_CAMELCASE_MATCH
&& matchRule != SearchPattern.RULE_PREFIX_MATCH
&& !extensionPatternStr.endsWith("*")) //$NON-NLS-1$
extensionPatternStr += '<';
extensionPattern = new SearchPattern();
extensionPattern.setPattern(extensionPatternStr);
}
}
}
/**
* Creates new ResourceFilter instance
*/
public ResourceFilter() {
this(container, searchContainer, isDerived, typeMask);
}
/**
* @param item
* Must be instance of IResource, otherwise
* <code>false</code> will be returned.
* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter#isConsistentItem(java.lang.Object)
*/
@Override
public boolean isConsistentItem(Object item) {
if (!(item instanceof IResource)) {
return false;
}
IResource resource = (IResource) item;
if (this.filterContainer.findMember(resource.getFullPath()) != null)
return true;
return false;
}
/**
* @param item
* Must be instance of IResource, otherwise
* <code>false</code> will be returned.
* @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.ItemsFilter#matchItem(java.lang.Object)
*/
@Override
public boolean matchItem(Object item) {
if (!(item instanceof IResource)) {
return false;
}
IResource resource = (IResource) item;
return (this.filterTypeMask & resource.getType()) != 0
&& matchName(resource)
&& (this.showDerived || !resource.isDerived());
}
private boolean matchName(IResource resource) {
String name = resource.getName();
if (nameMatches(name)) {
if (containerPattern != null) {
// match full container path:
String containerPath = resource.getParent().getFullPath().toString();
if (containerPattern.matches(containerPath))
return true;
// match path relative to current selection:
if (relativeContainerPattern != null)
return relativeContainerPattern.matches(containerPath);
return false;
}
return true;
}
return false;
}
private boolean nameMatches(String name) {
if (namePattern != null) {
// fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=212565
int lastDot = name.lastIndexOf('.');
if (lastDot != -1
&& namePattern.matches(name.substring(0, lastDot))
&& extensionPattern.matches(name.substring(lastDot + 1))) {
return true;
}
}
return matches(name);
}
@Override
public boolean isSubFilter(ItemsFilter filter) {
if (!super.isSubFilter(filter))
return false;
if (filter instanceof ResourceFilter) {
ResourceFilter resourceFilter = (ResourceFilter) filter;
if (this.showDerived == resourceFilter.showDerived) {
if (containerPattern == null) {
return resourceFilter.containerPattern == null;
} else if (resourceFilter.containerPattern == null) {
return false;
} else {
return containerPattern.equals(resourceFilter.containerPattern);
}
}
}
return false;
}
@Override
public boolean equalsFilter(ItemsFilter iFilter) {
if (!super.equalsFilter(iFilter))
return false;
if (iFilter instanceof ResourceFilter) {
ResourceFilter resourceFilter = (ResourceFilter) iFilter;
if (this.showDerived == resourceFilter.showDerived) {
if (containerPattern == null) {
return resourceFilter.containerPattern == null;
} else if (resourceFilter.containerPattern == null) {
return false;
} else {
return containerPattern.equals(resourceFilter.containerPattern);
}
}
}
return false;
}
/**
* Check show derived flag for a filter
*
* @return true if filter allow derived resources false if not
*/
public boolean isShowDerived() {
return showDerived;
}
}
private class FilterResourcesByLocation extends ViewerFilter {
private boolean enabled;
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
if (!this.enabled) {
return elements;
}
Map<IPath, IResource> bestResourceForPath = new LinkedHashMap<>();
for (Object item : elements) {
if (item instanceof IResource) {
IResource currentResource = (IResource) item;
IResource otherResource = bestResourceForPath.get(currentResource.getLocation());
if (otherResource == null || otherResource.getFullPath().segmentCount() > currentResource
.getFullPath().segmentCount()) {
bestResourceForPath.put(currentResource.getLocation(), currentResource);
}
}
}
return bestResourceForPath.values().toArray(new IResource[bestResourceForPath.size()]);
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
// shouldn't be called, but err on the side of caution
return true;
}
}
/**
* <code>ResourceSelectionHistory</code> provides behavior specific to
* resources - storing and restoring <code>IResource</code>s state
* to/from XML (memento).
*/
private class ResourceSelectionHistory extends SelectionHistory {
@Override
protected Object restoreItemFromMemento(IMemento element) {
ResourceFactory resourceFactory = new ResourceFactory();
IResource resource = (IResource) resourceFactory
.createElement(element);
return resource;
}
@Override
protected void storeItemToMemento(Object item, IMemento element) {
IResource resource = (IResource) item;
ResourceFactory resourceFactory = new ResourceFactory(resource);
resourceFactory.saveState(element);
}
}
}