/******************************************************************************* * 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); } } }