/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.search.internal.ui;
import com.google.dart.tools.search.internal.ui.util.ExceptionHandler;
import com.google.dart.tools.search.ui.ISearchPage;
import com.google.dart.tools.search.ui.ISearchPageContainer;
import com.google.dart.tools.search.ui.ISearchPageScoreComputer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IPluginContribution;
import org.osgi.framework.Bundle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
/**
* Proxy that represents a search page.
*/
@SuppressWarnings("rawtypes")
class SearchPageDescriptor implements IPluginContribution, Comparable {
private static class ExtensionScorePair {
public String extension;
public int score;
public ExtensionScorePair(String extension, int score) {
this.extension = extension;
this.score = score;
}
}
public final static String PAGE_TAG = "page"; //$NON-NLS-1$
private final static String ID_ATTRIBUTE = "id"; //$NON-NLS-1$
private final static String ICON_ATTRIBUTE = "icon"; //$NON-NLS-1$
private final static String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$
private final static String LABEL_ATTRIBUTE = "label"; //$NON-NLS-1$
private final static String SIZE_ATTRIBUTE = "sizeHint"; //$NON-NLS-1$
private final static String TAB_POSITION_ATTRIBUTE = "tabPosition"; //$NON-NLS-1$
private final static String EXTENSIONS_ATTRIBUTE = "extensions"; //$NON-NLS-1$
private final static String SHOW_SCOPE_SECTION_ATTRIBUTE = "showScopeSection"; //$NON-NLS-1$
private final static String CAN_SEARCH_ENCLOSING_PROJECTS = "canSearchEnclosingProjects"; //$NON-NLS-1$
private final static String ENABLED_ATTRIBUTE = "enabled"; //$NON-NLS-1$
private final static String SEARCH_VIEW_HELP_CONTEXT_ID_ATTRIBUTE = "searchViewHelpContextId"; //$NON-NLS-1$
public final static Point UNKNOWN_SIZE = new Point(SWT.DEFAULT, SWT.DEFAULT);
// dialog store id constants
private final static String SECTION_ID = "Search"; //$NON-NLS-1$
private final static String STORE_ENABLED_PAGE_IDS = SECTION_ID + ".enabledPageIds"; //$NON-NLS-1$
private final static String STORE_PROCESSED_PAGE_IDS = SECTION_ID + ".processedPageIds"; //$NON-NLS-1$
private static List<String> fgEnabledPageIds;
static void setEnabled(Object[] enabledDescriptors) {
fgEnabledPageIds = new ArrayList<String>(5);
for (int i = 0; i < enabledDescriptors.length; i++) {
if (enabledDescriptors[i] instanceof SearchPageDescriptor) {
fgEnabledPageIds.add(((SearchPageDescriptor) enabledDescriptors[i]).getId());
}
}
storeEnabledPageIds();
}
private static IDialogSettings getDialogSettings() {
IDialogSettings settings = SearchPlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(SECTION_ID);
if (section == null) {
// create new section
section = settings.addNewSection(SECTION_ID);
}
return section;
}
private static List<String> getEnabledPageIds() {
if (fgEnabledPageIds == null) {
List<SearchPageDescriptor> descriptors = SearchPlugin.getDefault().getSearchPageDescriptors();
String[] enabledPageIds = getDialogSettings().getArray(STORE_ENABLED_PAGE_IDS);
if (enabledPageIds == null) {
fgEnabledPageIds = new ArrayList<String>(descriptors.size());
} else {
fgEnabledPageIds = new ArrayList<String>(Arrays.asList(enabledPageIds));
}
List<String> processedPageIds;
String[] processedPageIdsArr = getDialogSettings().getArray(STORE_PROCESSED_PAGE_IDS);
if (processedPageIdsArr == null) {
processedPageIds = new ArrayList<String>(descriptors.size());
} else {
processedPageIds = new ArrayList<String>(Arrays.asList(processedPageIdsArr));
}
// Enable pages based on contribution
Iterator<SearchPageDescriptor> iter = descriptors.iterator();
while (iter.hasNext()) {
SearchPageDescriptor desc = iter.next();
if (processedPageIds.contains(desc.getId())) {
continue;
}
processedPageIds.add(desc.getId());
if (desc.isInitiallyEnabled()) {
fgEnabledPageIds.add(desc.getId());
}
}
getDialogSettings().put(
STORE_PROCESSED_PAGE_IDS,
processedPageIds.toArray(new String[processedPageIds.size()]));
storeEnabledPageIds();
}
return fgEnabledPageIds;
}
private static void storeEnabledPageIds() {
getDialogSettings().put(
STORE_ENABLED_PAGE_IDS,
fgEnabledPageIds.toArray(new String[fgEnabledPageIds.size()]));
}
private IConfigurationElement fElement;
private List<ExtensionScorePair> fExtensionScorePairs;
private int fWildcardScore = ISearchPageScoreComputer.UNKNOWN;
private ISearchPage fCreatedPage;
//---- XML Attribute accessors ---------------------------------------------
/**
* Creates a new search page node with the given configuration element.
*
* @param element The configuration element
*/
public SearchPageDescriptor(IConfigurationElement element) {
fElement = element;
}
/**
* Returns <code>true</code> if the page can handle searches in enclosing projects. The value
* should be ignored if <code>showScopeSection()</code> returns <code>false</code>. This attribute
* is optional and defaults to <code>false</code>.
*
* @return Returns if the page can handle searches in enclosing projects
*/
public boolean canSearchInProjects() {
return Boolean.valueOf(fElement.getAttribute(CAN_SEARCH_ENCLOSING_PROJECTS)).booleanValue();
}
/*
* Implements a method from IComparable
*/
@Override
public int compareTo(Object o) {
int myPos = getTabPosition();
int objsPos = ((SearchPageDescriptor) o).getTabPosition();
if (myPos == Integer.MAX_VALUE && objsPos == Integer.MAX_VALUE || myPos == objsPos) {
return getLabel().compareTo(((SearchPageDescriptor) o).getLabel());
}
return myPos - objsPos;
}
/**
* Returns the score for this page with the given input element.
*
* @param element The input element
* @return The scope for the page
*/
public int computeScore(Object element) {
if (element instanceof IAdaptable) {
int score = ISearchPageScoreComputer.UNKNOWN;
ISearchPageScoreComputer tester = (ISearchPageScoreComputer) ((IAdaptable) element).getAdapter(ISearchPageScoreComputer.class);
if (tester != null) {
score = tester.computeScore(getId(), element);
}
IResource resource = (IResource) ((IAdaptable) element).getAdapter(IResource.class);
if (resource != null && resource.getType() == IResource.FILE) {
String extension = ((IFile) resource).getFileExtension();
if (extension != null) {
score = Math.max(score, getScoreForFileExtension(extension));
}
}
if (score != ISearchPageScoreComputer.UNKNOWN) {
return score;
}
}
if (fWildcardScore != ISearchPageScoreComputer.UNKNOWN) {
return fWildcardScore;
}
return ISearchPageScoreComputer.LOWEST;
}
/**
* Creates a new search page from this node.
*
* @param container The parent container
* @return the created page or null if the creation failed
* @throws CoreException Page creation failed
*/
public ISearchPage createObject(ISearchPageContainer container) throws CoreException {
if (fCreatedPage == null) {
fCreatedPage = (ISearchPage) fElement.createExecutableExtension(CLASS_ATTRIBUTE);
fCreatedPage.setTitle(getLabel());
fCreatedPage.setContainer(container);
}
return fCreatedPage;
}
public void dispose() {
if (fCreatedPage != null) {
fCreatedPage.dispose();
fCreatedPage = null;
}
}
/**
* Returns the page's id.
*
* @return The id of the page
*/
public String getId() {
return fElement.getAttribute(ID_ATTRIBUTE);
}
/**
* Returns the page's image
*
* @return ImageDescriptor of the image or null if creating failed
*/
public ImageDescriptor getImage() {
String imageName = fElement.getAttribute(ICON_ATTRIBUTE);
if (imageName == null) {
return null;
}
Bundle bundle = Platform.getBundle(getPluginId());
return SearchPluginImages.createImageDescriptor(bundle, new Path(imageName), true);
}
/**
* @return Returns the page's label.
*/
public String getLabel() {
return fElement.getAttribute(LABEL_ATTRIBUTE);
}
@Override
public String getLocalId() {
return getId();
}
public ISearchPage getPage() {
return fCreatedPage;
}
@Override
public String getPluginId() {
return fElement.getContributor().getName();
}
/**
* @return Returns the page's preferred size
*/
public Point getPreferredSize() {
String sizeHint = fElement.getAttribute(SIZE_ATTRIBUTE);
if (sizeHint != null) {
int commaSep = sizeHint.indexOf(',');
if (commaSep != -1) {
try {
int xval = Integer.parseInt(sizeHint.substring(0, commaSep).trim());
int yval = Integer.parseInt(sizeHint.substring(commaSep + 1).trim());
return new Point(xval, yval);
} catch (NumberFormatException e) {
}
}
}
return UNKNOWN_SIZE;
}
/**
* Returns the help context for help shown in search view.
*
* @return the help context id or <code>null</code> if not defined
*/
public String getSearchViewHelpContextId() {
return fElement.getAttribute(SEARCH_VIEW_HELP_CONTEXT_ID_ATTRIBUTE);
}
/**
* Returns the page's tab position relative to the other tabs.
*
* @return the tab position or <code>Integer.MAX_VALUE</code> if not defined in the plugins.xml
* file
*/
public int getTabPosition() {
int position = Integer.MAX_VALUE / 2;
String str = fElement.getAttribute(TAB_POSITION_ATTRIBUTE);
if (str != null) {
try {
position = Integer.parseInt(str);
} catch (NumberFormatException ex) {
ExceptionHandler.log(ex, SearchMessages.Search_Error_createSearchPage_message);
// position is Integer.MAX_VALUE;
}
}
return position;
}
//---- Suitability tests ---------------------------------------------------
/**
* Returns <code>true</code> if the page is initially shown in the Search dialog. This attribute
* is optional and defaults to <code>true</code>.
*
* @return Returns if the page should be initially shown
*/
public boolean isInitiallyEnabled() {
String strVal = fElement.getAttribute(ENABLED_ATTRIBUTE);
return strVal == null || Boolean.valueOf(strVal).booleanValue();
}
/**
* @return Returns <code>true</code> if the scope section needs to be shown in the dialog.
*/
public boolean showScopeSection() {
return Boolean.valueOf(fElement.getAttribute(SHOW_SCOPE_SECTION_ATTRIBUTE)).booleanValue();
}
boolean isEnabled() {
return getEnabledPageIds().contains(getId());
}
private int getScoreForFileExtension(String extension) {
if (fExtensionScorePairs == null) {
readExtensionScorePairs();
}
int size = fExtensionScorePairs.size();
for (int i = 0; i < size; i++) {
ExtensionScorePair p = fExtensionScorePairs.get(i);
if (extension.equals(p.extension)) {
return p.score;
}
}
return ISearchPageScoreComputer.UNKNOWN;
}
private void readExtensionScorePairs() {
fExtensionScorePairs = new ArrayList<ExtensionScorePair>(3);
String content = fElement.getAttribute(EXTENSIONS_ATTRIBUTE);
if (content == null) {
return;
}
StringTokenizer tokenizer = new StringTokenizer(content, ","); //$NON-NLS-1$
while (tokenizer.hasMoreElements()) {
String token = tokenizer.nextToken().trim();
int pos = token.indexOf(':');
if (pos != -1) {
String extension = token.substring(0, pos);
int score = StringConverter.asInt(
token.substring(pos + 1).trim(),
ISearchPageScoreComputer.UNKNOWN);
if (extension.equals("*")) { //$NON-NLS-1$
fWildcardScore = score;
} else {
fExtensionScorePairs.add(new ExtensionScorePair(extension, score));
}
}
}
}
}