blob: 255738d2fb2ed33944b50ecd41720f4330d575a2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2020 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* George Suaridze <suag@1c.ru> (1C-Soft LLC) - Bug 560168
*******************************************************************************/
package org.eclipse.help.internal.base.scope;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.help.base.AbstractHelpScope;
import org.eclipse.help.base.IHelpScopeProducer;
import org.eclipse.help.base.IScopeHandle;
public class ScopeRegistry {
public static final String SCOPE_XP_NAME = "org.eclipse.help.base.scope"; //$NON-NLS-1$
public static final String ENABLEMENT_SCOPE_ID = "org.eclipse.help.enablement"; //$NON-NLS-1$
public static final String SEARCH_SCOPE_SCOPE_ID = "org.eclipse.help.searchscope"; //$NON-NLS-1$
public static final String SCOPE_AND = "^"; //$NON-NLS-1$
public static final String SCOPE_OR = "|"; //$NON-NLS-1$
private static List<IScopeHandle> scopes = null;
private static ScopeRegistry instance;
private boolean initialized = false;
private ScopeRegistry() {
}
public static ScopeRegistry getInstance() {
if (instance == null)
instance = new ScopeRegistry();
return instance;
}
public AbstractHelpScope getScope(String id) {
if (id == null) {
return new UniversalScope();
}
readScopes();
// Lookup in scope registry
for (IScopeHandle handle : scopes) {
if (id.equals(handle.getId())) {
return handle.getScope();
}
}
return null;
}
synchronized private void readScopes() {
if (initialized ) {
return;
}
scopes = new ArrayList<>();
IExtensionRegistry registry = Platform.getExtensionRegistry();
IConfigurationElement[] elements = registry
.getConfigurationElementsFor(SCOPE_XP_NAME);
for (IConfigurationElement element : elements) {
Object obj = null;
try {
obj = element.createExecutableExtension("class"); //$NON-NLS-1$
} catch (CoreException e) {
Platform.getLog(getClass()).error("Create extension failed:[" + SCOPE_XP_NAME + "].", e); //$NON-NLS-1$ //$NON-NLS-2$
}
if (obj instanceof AbstractHelpScope) {
String id = element.getAttribute("id"); //$NON-NLS-1$
IScopeHandle filter = new ScopeHandle(id, (AbstractHelpScope) obj);
scopes.add(filter);
}
else if (obj instanceof IHelpScopeProducer)
{
IScopeHandle dynamicScopes[] = ((IHelpScopeProducer)obj).getScopeHandles();
Collections.addAll(scopes, dynamicScopes);
}
}
initialized = true;
}
public IScopeHandle[] getScopes() {
readScopes();
return scopes.toArray(new IScopeHandle[scopes.size()]);
}
/**
* Parse logical sets of Scopes. All phrases in the
* array are intersected together
*
* @param phrases
* @return
*/
public AbstractHelpScope parseScopePhrases(String phrases[])
{
ArrayList<AbstractHelpScope> scopes = new ArrayList<>();
for (String phrase : phrases) {
AbstractHelpScope scope = parseScopePhrase(phrase);
if (scope!=null)
scopes.add(scope);
}
if (scopes.isEmpty())
return null;
if (scopes.size()==1)
return scopes.get(0);
return new IntersectionScope(
scopes.toArray(
new AbstractHelpScope[scopes.size()]));
}
/**
* Parse a logical phrase of scope names. i.e.:
* (A^B)|C
*
* @param phrase
* @return
*/
public AbstractHelpScope parseScopePhrase(String phrase)
{
if (!(phrase.startsWith("(") && !phrase.startsWith("("))) //$NON-NLS-1$ //$NON-NLS-2$
phrase = '('+phrase+')';
Stack<TempScope> scopeStack = new Stack<>();
ScopePhrase scopePhrase = new ScopePhrase(phrase);
String elem;
while ((elem = scopePhrase.getNextElement())!=null)
{
if (elem.equals("(")) //$NON-NLS-1$
{
TempScope scope = new TempScope();
scope.setType(TempScope.SELF);
scopeStack.push(scope);
}
else if (elem.equals(")")) //$NON-NLS-1$
{
TempScope scope = scopeStack.pop();
if (scopeStack.isEmpty())
return scope.getScope();
else{
TempScope parent = scopeStack.peek();
parent.add(scope.getScope());
}
}
else if (elem.equals(SCOPE_AND))
{
TempScope scope = scopeStack.peek();
scope.setType(TempScope.INTERSECTION);
}
else if (elem.equals(SCOPE_OR))
{
TempScope scope = scopeStack.peek();
scope.setType(TempScope.UNION);
}
else
{
TempScope scope = scopeStack.peek();
AbstractHelpScope helpScope = getScope(elem);
if (helpScope!=null)
scope.add(helpScope);
}
}
return null;
}
/**
* A class used to parse a logical scope phrase, by
* returning each part of the phrase as a separate element
*
*/
static class ScopePhrase{
private String phrase;
private int cursor;
public ScopePhrase(String phrase)
{
this.phrase = phrase;
this.cursor = 0;
}
public String getNextElement()
{
String next = ""; //$NON-NLS-1$
for (;cursor<phrase.length();cursor++)
{
char current = phrase.charAt(cursor);
if (current=='(')
return format(next,current);
if (current==')')
return format(next,current);
if ((current+"").equals(SCOPE_AND)) //$NON-NLS-1$
return format(next,current);
if ((current+"").equals(SCOPE_OR)) //$NON-NLS-1$
return format(next,current);
next+=current;
}
if (next.isEmpty())
return null;
return next;
}
private String format(String next,char current)
{
if (next.isEmpty())
{
cursor++;
return current+""; //$NON-NLS-1$
}
else
return next;
}
}
/**
* A class used to contruct a logical AbstractHelpScope based
* on one Scope, or a union/intersection of scopes.
*
*/
private static class TempScope
{
public final static int SELF=0;
public final static int UNION=1;
public final static int INTERSECTION=2;
private ArrayList<AbstractHelpScope> kids = new ArrayList<>();
private int type;
public void setType(int type)
{
this.type = type;
}
public void add(AbstractHelpScope kid)
{
kids.add(kid);
}
public AbstractHelpScope getScope()
{
switch (type){
case UNION:
return new UnionScope(
kids.toArray(
new AbstractHelpScope[kids.size()]));
case INTERSECTION:
return new IntersectionScope(
kids.toArray(
new AbstractHelpScope[kids.size()]));
default:
if (kids.size()>=1)
return kids.get(0);
else
return null;
}
}
}
}