/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.search; import static com.google.common.collect.Lists.newArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.Stylers; import org.eclipse.jface.viewers.Viewer; import org.eclipse.search.ui.text.Match; import org.robotframework.ide.eclipse.main.plugin.RedPlugin; import org.robotframework.ide.eclipse.main.plugin.model.RobotModel; import org.robotframework.ide.eclipse.main.plugin.model.RobotProject; import org.robotframework.ide.eclipse.main.plugin.project.library.KeywordSpecification; import org.robotframework.ide.eclipse.main.plugin.project.library.LibrarySpecification; import org.robotframework.red.viewers.TreeContentProvider; import com.google.common.base.Objects; /** * @author Michal Anglart */ class SearchResultContentProvider extends TreeContentProvider { private SearchResult input = null; private RobotModel model; @Override public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { input = (SearchResult) newInput; model = input == null ? null : ((SearchQuery) input.getQuery()).getModel(); } @Override public Object[] getElements(final Object inputElement) { final SearchResult result = (SearchResult) inputElement; final Set<IProject> projects = new HashSet<>(); for (final Object matchingElement : result.getElements()) { if (matchingElement instanceof IFile) { projects.add(((IFile) matchingElement).getProject()); } else if (matchingElement instanceof IProject) { projects.add((IProject) matchingElement); } else if (matchingElement instanceof MatchesGroupingElement) { final Optional<IProject> groupingProject = ((MatchesGroupingElement) matchingElement) .getGroupingObjectOf(IProject.class); if (groupingProject.isPresent()) { projects.add(groupingProject.get()); } } } return projects.toArray(); } @Override public Object[] getChildren(final Object parentElement) { if (parentElement instanceof IContainer) { try { final List<Object> children = new ArrayList<>(); if (parentElement instanceof IProject) { if (libsShouldBeShown((IProject) parentElement)) { children.add(new Libs((IProject) parentElement)); } } for (final IResource resource : ((IContainer) parentElement).members()) { if (resourceShouldBeShown(resource)) { children.add(resource); } } return children.toArray(); } catch (final CoreException e) { RedPlugin.logError("Problem when displaying search results", e); } } else if (parentElement instanceof IFile) { final List<Match> children = new ArrayList<>(); final Match[] matches = input.getMatches(parentElement); if (matches.length > 0) { children.addAll(newArrayList(matches)); } return children.toArray(); } else if (parentElement instanceof Libs) { final Set<Object> children = new LinkedHashSet<>(); final Libs parent = (Libs) parentElement; final IProject project = parent.getParent(); final RobotProject robotProject = model.createRobotProject(project); for (final LibrarySpecification libSpec : robotProject.getLibrariesSpecifications()) { final Match[] libMatches = input.getMatches(new MatchesGroupingElement(project, libSpec)); if (libMatches.length > 0) { children.add(new LibraryWithParent(parent, libSpec, newArrayList(libMatches))); } else { for (final KeywordSpecification kwSpec : libSpec.getKeywords()) { final Match[] kwMatches = input.getMatches(new MatchesGroupingElement(project, libSpec, kwSpec)); if (kwMatches.length > 0) { children.add(new LibraryWithParent(parent, libSpec, new ArrayList<Match>())); } } } } return children.toArray(); } else if (parentElement instanceof LibraryWithParent) { final Set<Object> children = new LinkedHashSet<>(); final LibraryWithParent parent = (LibraryWithParent) parentElement; final IProject project = parent.getParent().getParent(); final LibrarySpecification libSpec = parent.getSpecification(); children.addAll(parent.getMatches()); for (final KeywordSpecification kwSpec : libSpec.getKeywords()) { final Match[] kwMatches = input.getMatches(new MatchesGroupingElement(project, libSpec, kwSpec)); if (kwMatches.length > 0) { children.add(new KeywordWithParent(parent, kwSpec, newArrayList(kwMatches))); } } return children.toArray(); } else if (parentElement instanceof KeywordWithParent) { final Set<Object> children = new LinkedHashSet<>(); final KeywordWithParent parent = (KeywordWithParent) parentElement; children.addAll(parent.getMatches()); return children.toArray(); } return null; } private boolean libsShouldBeShown(final IProject project) { final RobotProject robotProject = model.createRobotProject(project); for (final LibrarySpecification libSpec : robotProject.getLibrariesSpecifications()) { if (input.containMatches(new MatchesGroupingElement(project, libSpec))) { return true; } for (final KeywordSpecification kwSpec : libSpec.getKeywords()) { if (input.containMatches(new MatchesGroupingElement(project, libSpec, kwSpec))) { return true; } } } return false; } private boolean resourceShouldBeShown(final IResource resource) throws CoreException { final AtomicBoolean shouldBeShown = new AtomicBoolean(false); resource.accept(new IResourceVisitor() { @Override public boolean visit(final IResource resource) throws CoreException { if (resource.getType() == IResource.FILE) { if (input.containMatches(resource)) { shouldBeShown.set(true); return false; } } return true; } }); return shouldBeShown.get(); } @Override public Object getParent(final Object element) { if (element instanceof IResource) { return ((IResource) element).getParent(); } else if (element instanceof Libs) { return ((Libs) element).getParent(); } else if (element instanceof LibraryWithParent) { return ((LibraryWithParent) element).getParent(); } else if (element instanceof KeywordWithParent) { return ((KeywordWithParent) element).getParent(); } return null; } @Override public boolean hasChildren(final Object element) { return !(element instanceof Match); } static class Libs { private final IProject project; private Libs(final IProject project) { this.project = project; } private IProject getParent() { return project; } } private static abstract class LibraryEntity<P, S> { private final P parent; private final S specification; private final List<Match> matches; private LibraryEntity(final P parent, final S specification, final List<Match> matches) { this.parent = parent; this.specification = specification; this.matches = matches; } P getParent() { return parent; } S getSpecification() { return specification; } List<Match> getMatches() { return matches; } @Override public boolean equals(final Object obj) { if (obj instanceof LibraryEntity) { final LibraryEntity<?, ?> that = (LibraryEntity<?, ?>) obj; return this.parent == that.parent && this.specification.equals(that.specification); } return false; } @Override public int hashCode() { return Objects.hashCode(parent, specification); } StyledString getLabel() { final StyledString label = new StyledString(getName()); if (!matches.isEmpty()) { label.append(" (" + matches.size() + ") matches", Stylers.Common.ECLIPSE_DECORATION_STYLER); } return label; } abstract String getName(); } static final class LibraryWithParent extends LibraryEntity<Libs, LibrarySpecification> { private LibraryWithParent(final Libs parent, final LibrarySpecification specification, final List<Match> matches) { super(parent, specification, matches); } @Override String getName() { return getSpecification().getName(); } } static final class KeywordWithParent extends LibraryEntity<LibraryWithParent, KeywordSpecification> { private KeywordWithParent(final LibraryWithParent parent, final KeywordSpecification specification, final List<Match> matches) { super(parent, specification, matches); } @Override String getName() { return getSpecification().getName(); } } }