blob: 1b7d1fad1871be80a9d0739bca4257c61348f001 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2014 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
* Yaroslav Nikolaiko <nikolaiko.yaroslav@gmail.com> - [webapp][base] Bugs related to Search Scope for filtering content in The Eclipse platform's help infocenter - http://bugs.eclipse.org/441407
*******************************************************************************/
package org.eclipse.help.internal.search;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.help.IToc;
import org.eclipse.help.ITopic;
import org.eclipse.help.base.AbstractHelpScope;
import org.eclipse.help.internal.HelpPlugin;
import org.eclipse.help.internal.Topic;
import org.eclipse.help.internal.base.scope.CriteriaHelpScope;
import org.eclipse.help.internal.criteria.CriterionResource;
import org.eclipse.help.internal.util.URLCoder;
import org.eclipse.help.internal.workingset.AdaptableHelpResource;
import org.eclipse.help.internal.workingset.AdaptableSelectedToc;
import org.eclipse.help.internal.workingset.AdaptableSelectedTopic;
import org.eclipse.help.internal.workingset.AdaptableToc;
import org.eclipse.help.internal.workingset.AdaptableTopic;
import org.eclipse.help.internal.workingset.WorkingSet;
/**
* Search result collector. Performs filtering and collects hits into an array
* of SearchHit
*/
public class SearchResults implements ISearchHitCollector {
// Collection of AdaptableHelpResource[]
private ArrayList<AdaptableHelpResource> scopes;
private int maxHits;
private String locale;
private AbstractHelpScope filter;
private CriteriaHelpScope criteriaScope;
protected SearchHit[] searchHits = new SearchHit[0];
private QueryTooComplexException searchException = null;
private boolean isQuickSearch;
public SearchResults(WorkingSet[] workingSets, int maxHits, String locale) {
this(workingSets, maxHits, locale, false);
}
/**
* Constructor
*
* @param workingSets
* working sets or null if no filtering
*/
public SearchResults(WorkingSet[] workingSets, int maxHits, String locale, boolean isQuickSearch) {
this.maxHits = maxHits;
this.locale = locale;
this.scopes = getScopes(workingSets);
this.criteriaScope = new CriteriaHelpScope(getCriteriaScopes(workingSets));
this.isQuickSearch = isQuickSearch;
}
public void setFilter(AbstractHelpScope filter) {
this.filter = filter;
}
/* (non-Javadoc)
* @see org.eclipse.help.internal.search.ISearchHitCollector#addHits(List, String)
*/
public void addHits(List<SearchHit> hits, String highlightTerms) {
String urlEncodedWords = URLCoder.encode(highlightTerms);
List<SearchHit> searchHitList = new ArrayList<SearchHit>();
float scoreScale = 1.0f;
boolean scoreScaleSet = false;
Iterator<SearchHit> iter = hits.iterator();
for (int filteredHits = 0; filteredHits < maxHits && iter.hasNext(); ) {
SearchHit rawHit = iter.next();
String href = rawHit.getHref();
IToc toc = null; // the TOC containing the topic
AdaptableHelpResource scope = null;
// the scope for the topic, if any
if (scopes == null) {
toc = getTocForTopic(href, locale);
if (toc == null && !rawHit.canOpen()) {
continue;
}
} else {
scope = getScopeForTopic(href);
if (scope == null) {
// topic outside of scope
continue;
} else if ((scope instanceof AdaptableToc) || (scope instanceof AdaptableSelectedToc)) {
toc = scope.getAdapter(IToc.class);
} else if((scope instanceof AdaptableTopic) || (scope instanceof AdaptableSelectedTopic)){ // scope is AdaptableTopic or AdaptableSelectedTopic
toc = scope.getParent().getAdapter(IToc.class);
}
}
// adjust score
float score = rawHit.getScore();
if (!scoreScaleSet) {
if (score > 0) {
scoreScale = 0.99f / score;
score = 1;
}
scoreScaleSet = true;
} else {
score = score * scoreScale + 0.01f;
}
// Set the document label
String label = rawHit.getLabel();
if ("".equals(label) && toc != null) { //$NON-NLS-1$
ITopic t;
if (scope != null) {
t = scope.getTopic(href);
} else {
t = toc.getTopic(href);
}
if (t != null) {
label = t.getLabel();
}
}
if (label == null || "".equals(label)) { //$NON-NLS-1$
label = href;
}
// Set document href
if (urlEncodedWords.length() > 0) {
href += "?resultof=" + urlEncodedWords; //$NON-NLS-1$
}
filteredHits ++;
searchHitList.add(new SearchHit(href, label, rawHit.getSummary(), score, toc, rawHit.getRawId(), rawHit.getParticipantId(), rawHit.isPotentialHit()));
}
searchHits = searchHitList
.toArray(new SearchHit[searchHitList.size()]);
}
public void setHits(SearchHit hits[])
{
searchHits = hits;
}
/**
* Finds a topic within a scope
*/
private AdaptableHelpResource getScopeForTopic(String href) {
boolean enabled = HelpPlugin.getCriteriaManager().isCriteriaEnabled();
for (int i = 0; i < scopes.size(); i++) {
AdaptableHelpResource scope = scopes.get(i);
ITopic inScopeTopic = scope.getTopic(href);
if (inScopeTopic != null){
if (filter == null || filter.inScope(inScopeTopic)) {
if(!enabled || (enabled && criteriaScope.inScope(inScopeTopic))){
return scope;
}
}
}
// add root toc's extradir topics to search scope
if (!isQuickSearch) {
IToc tocRoot = getTocForScope(scope, locale);
if (tocRoot != null) {
IToc toc = HelpPlugin.getTocManager().getOwningToc(href);
if (toc != null) {
String owningTocHref = toc.getHref();
if (owningTocHref == tocRoot.getHref()) {
Topic extradirTopic = new Topic();
extradirTopic.setHref(href);
if (filter == null || filter.inScope(extradirTopic)) {
if(!enabled || (enabled && criteriaScope.inScope(inScopeTopic))){
return scope;
}
}
}
}
}
}
}
return null;
}
/**
* Finds a scope in a toc
*/
private IToc getTocForScope(AdaptableHelpResource scope, String locale) {
if (scope == null) {
return null;
}
String href = scope.getHref();
IToc toc=scope.getAdapter(IToc.class);
if (toc != null){
href=toc.getTopic(null).getHref();
}
if (href != null && href.length() > 0) {
return getTocForTopic(href, locale);
} else {
AdaptableHelpResource[] childrenScopes = scope.getChildren();
if (childrenScopes != null) {
for (int i = 0; i < childrenScopes.length; i++) {
// To find the target toc recursively because scope.getHref
// may be null.
toc = getTocForScope(childrenScopes[i], locale);
if (toc != null)
return toc;
}
}
}
return null;
}
/**
* Finds a topic in a toc or within a scope if specified
*/
private IToc getTocForTopic(String href, String locale) {
IToc[] tocs = HelpPlugin.getTocManager().getTocs(locale);
boolean foundInToc = false;
for (int i = 0; i < tocs.length; i++) {
IToc nextToc = tocs[i];
ITopic topic = nextToc.getTopic(href);
if (topic != null) {
foundInToc = true;
if (filter == null || filter.inScope(topic)) {
return nextToc;
}
}
// Test for href attached to Toc element
topic = nextToc.getTopic(null);
if (topic != null && href != null && href.equals(topic.getHref())) {
if (filter == null || filter.inScope(topic)) {
return nextToc;
}
}
}
if (!foundInToc) {
// test to pick up files in extradirs
IToc toc = HelpPlugin.getTocManager().getOwningToc(href);
if (toc != null) {
foundInToc = true;
if (filter == null || filter.inScope(toc)) {
return toc;
}
}
}
return null;
}
/**
* Gets the searchHits.
*
* @return Returns a SearchHit[]
*/
public SearchHit[] getSearchHits() {
return searchHits;
}
public QueryTooComplexException getException() {
return searchException;
}
/**
* Returns a collection of adaptable help resources that are roots for
* filtering.
*
* @return Collection
*/
private ArrayList<AdaptableHelpResource> getScopes(WorkingSet[] wSets) {
if (wSets == null)
return null;
scopes = new ArrayList<AdaptableHelpResource>(wSets.length);
for (int w = 0; w < wSets.length; w++) {
AdaptableHelpResource[] elements = wSets[w].getElements();
for (int i = 0; i < elements.length; i++)
scopes.add(elements[i]);
}
return scopes;
}
private ArrayList<CriterionResource> getCriteriaScopes(WorkingSet[] wSets){
if (wSets == null)
return null;
ArrayList<CriterionResource> criteriaScopes = new ArrayList<CriterionResource>(wSets.length);
for (int w = 0; w < wSets.length; w++) {
CriterionResource[] elements = wSets[w].getCriteria();
for (int i = 0; i < elements.length; i++)
criteriaScopes.add(elements[i]);
}
return criteriaScopes;
}
public void addQTCException(QueryTooComplexException exception) throws QueryTooComplexException {
this.searchException = exception;
}
}