/*
* 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.ui.internal.dialogs;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.index.Index;
import com.google.dart.engine.search.SearchEngine;
import com.google.dart.engine.search.SearchEngineFactory;
import com.google.dart.engine.search.SearchListener;
import com.google.dart.engine.search.SearchMatch;
import com.google.dart.engine.search.SearchPatternFactory;
import com.google.dart.engine.search.SearchScope;
import com.google.dart.engine.search.SearchScopeFactory;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.model.DartConventions;
import com.google.dart.tools.ui.DartElementLabelProvider;
import com.google.dart.tools.ui.DartElementLabels;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.DartUIMessages;
import com.google.dart.tools.ui.Messages;
import com.google.dart.tools.ui.dialogs.ITypeInfoFilterExtension;
import com.google.dart.tools.ui.dialogs.ITypeInfoImageProvider;
import com.google.dart.tools.ui.dialogs.ITypeSelectionComponent;
import com.google.dart.tools.ui.dialogs.TypeSelectionExtension;
import com.google.dart.tools.ui.internal.text.DartHelpContextIds;
import com.google.dart.tools.ui.internal.util.Strings;
import com.google.dart.tools.ui.internal.util.TypeNameMatchLabelProvider;
import com.google.dart.tools.ui.internal.viewsupport.ColoredDartElementLabels;
import com.google.dart.tools.ui.internal.viewsupport.ColoredString;
import com.google.dart.tools.ui.internal.viewsupport.ColoredViewersManager;
import com.google.dart.tools.ui.internal.viewsupport.OwnerDrawSupport;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
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.operation.IRunnableContext;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.dialogs.SearchPattern;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* Shows a list of Dart types to the user with a text entry field for a string pattern used to
* filter the list of types.
*/
public class FilteredTypesSelectionDialog extends FilteredItemsSelectionDialog implements
ITypeSelectionComponent {
//TODO(pquitslund): display search-in-progress status
//TODO(pquitslund): improve/make incremental refresh
/**
* The <code>ShowContainerForDuplicatesAction</code> provides means to show/hide container
* information for duplicate elements.
*/
private class ShowContainerForDuplicatesAction extends Action {
/**
* Creates a new instance of the class
*/
public ShowContainerForDuplicatesAction() {
super(
DartUIMessages.FilteredTypeSelectionDialog_showContainerForDuplicatesAction,
IAction.AS_CHECK_BOX);
}
@Override
public void run() {
fTypeInfoLabelProvider.setContainerInfo(isChecked());
}
}
// TODO: enable history
// /**
// * Extends the <code>SelectionHistory</code>, providing support for
// * <code>OpenTypeHistory</code>.
// */
// protected class TypeSelectionHistory extends SelectionHistory {
//
// /**
// * Creates new instance of TypeSelectionHistory
// */
//
// public TypeSelectionHistory() {
// super();
// }
//
// /*
// * (non-Javadoc)
// * @see
// * org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#
// * accessed(java.lang.Object)
// */
// public synchronized void accessed(Object object) {
// super.accessed(object);
// }
//
// /*
// * (non-Javadoc)
// * @see
// * org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#
// * load(org.eclipse.ui.IMemento)
// */
// public void load(IMemento memento) {
// TypeNameMatch[] types = OpenTypeHistory.getInstance().getTypeInfos();
//
// for (int i = 0; i < types.length; i++) {
// TypeNameMatch type = types[i];
// accessed(type);
// }
// }
//
// /*
// * (non-Javadoc)
// * @see
// * org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#
// * remove(java.lang.Object)
// */
// public synchronized boolean remove(Object element) {
// OpenTypeHistory.getInstance().remove((TypeNameMatch) element);
// return super.remove(element);
// }
//
// /*
// * (non-Javadoc)
// * @see
// * org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#
// * save(org.eclipse.ui.IMemento)
// */
// public void save(IMemento memento) {
// persistHistory();
// }
//
// protected Object restoreItemFromMemento(IMemento element) {
// return null;
// }
//
// /*
// * (non-Javadoc)
// * @see
// * org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.SelectionHistory#
// * storeItemToMemento(java.lang.Object, org.eclipse.ui.IMemento)
// */
// protected void storeItemToMemento(Object item, IMemento element) {
//
// }
//
// /**
// * Stores contents of the local history into persistent history container.
// */
// private synchronized void persistHistory() {
// if (getReturnCode() == OK) {
// Object[] items = getHistoryItems();
// for (int i = 0; i < items.length; i++) {
// OpenTypeHistory.getInstance().accessed((TypeNameMatch) items[i]);
// }
// }
// }
//
// }
//
// /*
// * We only have to ensure history consistency here since the search engine
// * takes care of working copies.
// */
// private static class ConsistencyRunnable implements IRunnableWithProgress {
// public static boolean needsExecution() {
// OpenTypeHistory history = OpenTypeHistory.getInstance();
// return fgFirstTime || history.isEmpty() || history.needConsistencyCheck();
// }
//
// public void run(IProgressMonitor monitor) throws InvocationTargetException,
// InterruptedException {
// if (fgFirstTime) {
// // Join the initialize after load job.
// IJobManager manager = Job.getJobManager();
// manager.join(DartUI.ID_PLUGIN, monitor);
// }
// OpenTypeHistory history = OpenTypeHistory.getInstance();
// if (fgFirstTime || history.isEmpty()) {
// if (history.needConsistencyCheck()) {
// monitor.beginTask(
// DartUIMessages.TypeSelectionDialog_progress_consistency, 100);
// refreshSearchIndices(new SubProgressMonitor(monitor, 90));
// history.checkConsistency(new SubProgressMonitor(monitor, 10));
// } else {
// refreshSearchIndices(monitor);
// }
// monitor.done();
// fgFirstTime = false;
// } else {
// history.checkConsistency(monitor);
// }
// }
//
// private void refreshSearchIndices(IProgressMonitor monitor)
// throws InvocationTargetException {
// try {
// new SearchEngine().searchAllTypeNames(
// null,
// 0,
// // make sure we search a concrete name. This is faster according to
// // Kent
// "_______________".toCharArray(), //$NON-NLS-1$
// SearchPattern.RULE_EXACT_MATCH | SearchPattern.RULE_CASE_SENSITIVE,
// IJavaScriptSearchConstants.ENUM,
// SearchEngine.createWorkspaceScope(), new TypeNameRequestor() {
// }, IJavaScriptSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
// } catch (DartModelException e) {
// throw new InvocationTargetException(e);
// }
// }
// }
private static class TypeInfoUtil {
// private final ITypeInfoImageProvider fProviderExtension;
// private final SearchListener fAdapter = new SearchListener() {
// @SuppressWarnings("unused")
// private SearchMatch match;
//
// @Override
// public void matchFound(SearchMatch match) {
// this.match = match;
// }
//
// @Override
// public void searchComplete() {
// // Ignored
// }
// };
// private final Map fLib2Name = new HashMap();
// private final String[] fInstallLocations;
//
// private final String[] fVMNames;
// private boolean fFullyQualifyDuplicates;
public TypeInfoUtil(ITypeInfoImageProvider extension) {
// fProviderExtension = extension;
// List locations = new ArrayList();
// List labels = new ArrayList();
// IVMInstallType[] installs = JavaRuntime.getVMInstallTypes();
// for (int i = 0; i < installs.length; i++) {
// processVMInstallType(installs[i], locations, labels);
// }
// fInstallLocations = (String[]) locations.toArray(new String[locations.size()]);
// fVMNames = (String[]) labels.toArray(new String[labels.size()]);
}
public String getFullyQualifiedText(Element element) {
StringBuffer result = new StringBuffer();
result.append(element.getName());
// String containerName = type.getTypeContainerName();
// if (containerName.length() > 0) {
// result.append(DartElementLabels.CONCAT_STRING);
// result.append(containerName);
// }
// result.append(DartElementLabels.CONCAT_STRING);
// result.append(getContainerName(type));
return result.toString();
}
// public ImageDescriptor getImageDescriptor(Object object) {
// DartElement element = (DartElement) object;
// if (fProviderExtension != null) {
// try {
// fAdapter.matchFound(new SearchMatch(
// MatchQuality.EXACT,
// element,
// ((SourceReference) element).getSourceRange()));
// } catch (DartModelException e) {
// DartToolsPlugin.log(e);
// }
//// ImageDescriptor descriptor = fProviderExtension.getImageDescriptor(fAdapter);
//
// // TODO(brianwilkerson) This needs to return a different descriptor for function type aliases.
// ImageDescriptor descriptor = DartElementImageProvider.getTypeImageDescriptor(false, false);
//
// if (descriptor != null) {
// return descriptor;
// }
// }
// // TODO(brianwilkerson) This needs to return a different descriptor for function type aliases.
// return DartElementImageProvider.getTypeImageDescriptor(false, false);
// }
public String getQualificationText(Element element) {
StringBuffer result = new StringBuffer();
LibraryElement library = element.getLibrary();
result.append(library.getDisplayName());
IResource resource = DartCore.getProjectManager().getResource(element.getSource());
if (resource != null) {
result.append(DartElementLabels.CONCAT_STRING);
IContainer container = resource.getParent();
String path = container.getFullPath().toString();
if (path.startsWith("/")) { //$NON-NLS-1$
result.append(path.substring(1));
} else {
result.append(path);
}
}
return result.toString();
}
public String getQualifiedText(Element element) {
StringBuffer result = new StringBuffer();
result.append(element.getName());
LibraryElement library = element.getLibrary();
if (library != null) {
result.append(DartElementLabels.CONCAT_STRING);
result.append(library.getDisplayName());
}
return result.toString();
}
public String getText(Object element) {
return ((Element) element).getName();
}
// public String getText(Type last, Type current,
// Type next) {
// StringBuffer result = new StringBuffer();
// int qualifications = 0;
// String currentTN = current.getSimpleTypeName();
// result.append(currentTN);
// String currentTCN = getTypeContainerName(current);
// if (last != null) {
// String lastTN = last.getSimpleTypeName();
// String lastTCN = getTypeContainerName(last);
// if (currentTCN.equals(lastTCN)) {
// if (currentTN.equals(lastTN)) {
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(currentTCN);
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(getContainerName(current));
// return result.toString();
// }
// } else if (currentTN.equals(lastTN)) {
// qualifications = 1;
// }
// }
// if (next != null) {
// String nextTN = next.getSimpleTypeName();
// String nextTCN = getTypeContainerName(next);
// if (currentTCN.equals(nextTCN)) {
// if (currentTN.equals(nextTN)) {
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(currentTCN);
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(getContainerName(current));
// return result.toString();
// }
// } else if (currentTN.equals(nextTN)) {
// qualifications = 1;
// }
// }
// if (qualifications > 0) {
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(currentTCN);
// if (fFullyQualifyDuplicates) {
// result.append(JavaScriptElementLabels.CONCAT_STRING);
// result.append(getContainerName(current));
// }
// }
// return result.toString();
// }
// public void setFullyQualifyDuplicates(boolean value) {
// fFullyQualifyDuplicates = value;
// }
// private String getContainerName(TypeNameMatch type) {
// IPackageFragmentRoot root = type.getPackageFragmentRoot();
// if (root.isExternal()) {
// String name = root.getPath().toOSString();
// for (int i = 0; i < fInstallLocations.length; i++) {
// if (name.startsWith(fInstallLocations[i])) {
// return fVMNames[i];
// }
// }
// String lib = (String) fLib2Name.get(name);
// if (lib != null)
// return lib;
// }
// StringBuffer buf = new StringBuffer();
// JavaScriptElementLabels.getPackageFragmentRootLabel(root,
// JavaScriptElementLabels.ROOT_QUALIFIED
// | JavaScriptElementLabels.ROOT_VARIABLE, buf);
// return buf.toString();
// }
// private String getFormattedLabel(String name) {
// return Messages.format(DartUIMessages.FilteredTypesSelectionDialog_library_name_format, name);
// }
// private String getTypeContainerName(TypeNameMatch info) {
// String result = info.getTypeContainerName();
// if (result.length() > 0)
// return result;
// return DartUIMessages.FilteredTypesSelectionDialog_default_package;
// }
// private void processLibraryLocation(LibraryLocation[] libLocations,
// String label) {
// for (int l = 0; l < libLocations.length; l++) {
// LibraryLocation location = libLocations[l];
// fLib2Name.put(location.getSystemLibraryPath().toOSString(), label);
// }
// }
// private void processVMInstallType(IVMInstallType installType,
// List locations, List labels) {
// if (installType != null) {
// IVMInstall[] installs = installType.getVMInstalls();
// boolean isMac = Platform.OS_MACOSX.equals(Platform.getOS());
// final String HOME_SUFFIX = "/Home"; //$NON-NLS-1$
// for (int i = 0; i < installs.length; i++) {
// String label = getFormattedLabel(installs[i].getName());
// LibraryLocation[] libLocations = installs[i].getLibraryLocations();
// if (libLocations != null) {
// processLibraryLocation(libLocations, label);
// } else {
// String filePath = installs[i].getInstallLocation().getAbsolutePath();
// // on MacOS X install locations end in an additional
// // "/Home" segment; remove it
// if (isMac && filePath.endsWith(HOME_SUFFIX))
// filePath = filePath.substring(0,
// filePath.length() - HOME_SUFFIX.length() + 1);
// locations.add(filePath);
// labels.add(label);
// }
// }
// }
// }
}
//TODO: enable or remove type filter preferences
// private class TypeFiltersPreferencesAction extends Action {
//
// public TypeFiltersPreferencesAction() {
// super(
// DartUIMessages.FilteredTypesSelectionDialog_TypeFiltersPreferencesAction_label);
// }
//
// /*
// * (non-Javadoc)
// * @see org.eclipse.jface.action.Action#run()
// */
// public void run() {
// String typeFilterID = TypeFilterPreferencePage.TYPE_FILTER_PREF_PAGE_ID;
// PreferencesUtil.createPreferenceDialogOn(getShell(), typeFilterID,
// new String[]{typeFilterID}, null).open();
// triggerSearch();
// }
// }
/**
* A <code>LabelProvider</code> for the label showing type details.
*/
private static class TypeItemDetailsLabelProvider extends LabelProvider {
private final DartElementLabelProvider imageProvider = new DartElementLabelProvider();
private final TypeInfoUtil fTypeInfoUtil;
public TypeItemDetailsLabelProvider(TypeInfoUtil typeInfoUtil) {
fTypeInfoUtil = typeInfoUtil;
}
@Override
public Image getImage(Object object) {
if (object instanceof Element) {
Element element = (Element) object;
LibraryElement library = element.getLibrary();
if (library != null) {
return imageProvider.getImage(library);
}
}
return super.getImage(object);
}
@Override
public String getText(Object element) {
if (element instanceof Element) {
return fTypeInfoUtil.getQualificationText((Element) element);
}
return super.getText(element);
}
}
/**
* A <code>LabelProvider</code> for (the table of) types.
*/
private class TypeItemLabelProvider extends LabelProvider implements ILabelDecorator {
private final TypeNameMatchLabelProvider fLabelProvider = new TypeNameMatchLabelProvider(
TypeNameMatchLabelProvider.SHOW_TYPE_CONTAINER_ONLY
+ TypeNameMatchLabelProvider.SHOW_ROOT_POSTFIX);
private boolean fContainerInfo;
/**
* Construct a new <code>TypeItemLabelProvider</code>. F
*/
public TypeItemLabelProvider() {
}
@Override
public Image decorateImage(Image image, Object element) {
return null;
}
@Override
public String decorateText(String text, Object element) {
if (!(element instanceof Element)) {
return null;
}
if (fContainerInfo && isDuplicateElement(element)) {
return fTypeInfoUtil.getFullyQualifiedText((Element) element);
}
return fTypeInfoUtil.getQualifiedText((Element) element);
}
@Override
public Image getImage(Object element) {
if (!(element instanceof Element)) {
return super.getImage(element);
}
return fLabelProvider.getImage(element);
}
@Override
public String getText(Object element) {
if (!(element instanceof Element)) {
return super.getText(element);
}
if (fContainerInfo && isDuplicateElement(element)) {
return fTypeInfoUtil.getFullyQualifiedText((Element) element);
}
if (!fContainerInfo && isDuplicateElement(element)) {
return fTypeInfoUtil.getQualifiedText((Element) element);
}
return fTypeInfoUtil.getText(element);
}
public void setContainerInfo(boolean containerInfo) {
fContainerInfo = containerInfo;
fireLabelProviderChanged(new LabelProviderChangedEvent(this));
}
}
/**
* Compares TypeItems is used during sorting
*/
@SuppressWarnings("rawtypes")
private static class TypeItemsComparator implements Comparator {
// private final Map fLib2Name = new HashMap();
// private final String[] fInstallLocations;
//
// private final String[] fVMNames;
/**
* Creates new instance of TypeItemsComparator
*/
public TypeItemsComparator() {
// List locations = new ArrayList();
// List labels = new ArrayList();
// IVMInstallType[] installs = JavaRuntime.getVMInstallTypes();
// for (int i = 0; i < installs.length; i++) {
// processVMInstallType(installs[i], locations, labels);
// }
// fInstallLocations = (String[]) locations.toArray(new String[locations.size()]);
// fVMNames = (String[]) labels.toArray(new String[labels.size()]);
}
@Override
public int compare(Object left, Object right) {
Element leftInfo = (Element) left;
Element rightInfo = (Element) right;
return compareName(leftInfo.getName(), rightInfo.getName());
// int result = compareName(leftInfo.getSimpleTypeName(),
// rightInfo.getSimpleTypeName());
// if (result != 0)
// return result;
// result = compareTypeContainerName(leftInfo.getTypeContainerName(),
// rightInfo.getTypeContainerName());
// if (result != 0)
// return result;
//
// int leftCategory = getElementTypeCategory(leftInfo);
// int rightCategory = getElementTypeCategory(rightInfo);
// if (leftCategory < rightCategory)
// return -1;
// if (leftCategory > rightCategory)
// return +1;
// return compareContainerName(leftInfo, rightInfo);
}
// private int compareContainerName(Type leftType,
// Type rightType) {
// return getContainerName(leftType).compareTo(getContainerName(rightType));
// }
private int compareName(String leftString, String rightString) {
int result = leftString.compareToIgnoreCase(rightString);
if (result != 0 || rightString.length() == 0) {
return result;
} else if (Strings.isLowerCase(leftString.charAt(0))
&& !Strings.isLowerCase(rightString.charAt(0))) {
return +1;
} else if (Strings.isLowerCase(rightString.charAt(0))
&& !Strings.isLowerCase(leftString.charAt(0))) {
return -1;
} else {
return leftString.compareTo(rightString);
}
}
// private int compareTypeContainerName(String leftString, String rightString) {
// int leftLength = leftString.length();
// int rightLength = rightString.length();
// if (leftLength == 0 && rightLength > 0)
// return -1;
// if (leftLength == 0 && rightLength == 0)
// return 0;
// if (leftLength > 0 && rightLength == 0)
// return +1;
// return compareName(leftString, rightString);
// }
//
// private String getContainerName(TypeNameMatch type) {
// IPackageFragmentRoot root = type.getPackageFragmentRoot();
// if (root.isExternal()) {
// String name = root.getPath().toOSString();
// for (int i = 0; i < fInstallLocations.length; i++) {
// if (name.startsWith(fInstallLocations[i])) {
// return fVMNames[i];
// }
// }
// String lib = (String) fLib2Name.get(name);
// if (lib != null)
// return lib;
// }
// StringBuffer buf = new StringBuffer();
// JavaScriptElementLabels.getPackageFragmentRootLabel(root,
// JavaScriptElementLabels.ROOT_QUALIFIED
// | JavaScriptElementLabels.ROOT_VARIABLE, buf);
// return buf.toString();
// }
// private int getElementTypeCategory(TypeNameMatch type) {
// try {
// if (type.getPackageFragmentRoot().getKind() == IPackageFragmentRoot.K_SOURCE)
// return 0;
// } catch (DartModelException e) {
// DartToolsPlugin.log(e);
// }
// return 1;
// }
// private String getFormattedLabel(String name) {
// return MessageFormat.format(
// DartUIMessages.FilteredTypesSelectionDialog_library_name_format,
// new Object[] {name});
// }
// private void processLibraryLocation(LibraryLocation[] libLocations,
// String label) {
// for (int l = 0; l < libLocations.length; l++) {
// LibraryLocation location = libLocations[l];
// fLib2Name.put(location.getSystemLibraryPath().toString(), label);
// }
// }
//
// private void processVMInstallType(IVMInstallType installType,
// List locations, List labels) {
// if (installType != null) {
// IVMInstall[] installs = installType.getVMInstalls();
// boolean isMac = Platform.OS_MACOSX.equals(Platform.getOS());
// final String HOME_SUFFIX = "/Home"; //$NON-NLS-1$
// for (int i = 0; i < installs.length; i++) {
// String label = getFormattedLabel(installs[i].getName());
// LibraryLocation[] libLocations = installs[i].getLibraryLocations();
// if (libLocations != null) {
// processLibraryLocation(libLocations, label);
// } else {
// String filePath = installs[i].getInstallLocation().getAbsolutePath();
// // on MacOS X install locations end in an additional
// // "/Home" segment; remove it
// if (isMac && filePath.endsWith(HOME_SUFFIX))
// filePath = filePath.substring(0,
// filePath.length() - HOME_SUFFIX.length() + 1);
// locations.add(filePath);
// labels.add(label);
// }
// }
// }
// }
}
/**
* Filters types using pattern, scope, element kind and filter extension.
*/
@SuppressWarnings("unused")
private class TypeItemsFilter extends ItemsFilter {
private final SearchScope fScope;
private final boolean fIsWorkspaceScope;
private final int fElemKind;
private final ITypeInfoFilterExtension fFilterExt;
// private final TypeInfoRequestorAdapter fAdapter = new TypeInfoRequestorAdapter();
private SearchPattern fPackageMatcher;
private boolean fMatchEverything = false;
private final int fMyTypeFilterVersion = fTypeFilterVersion;
/**
* Creates instance of TypeItemsFilter
*
* @param scope
* @param elementKind
* @param extension
*/
public TypeItemsFilter(SearchScope scope, int elementKind, ITypeInfoFilterExtension extension) {
super(new TypeSearchPattern());
fScope = scope;
fIsWorkspaceScope = scope == null ? false
: scope.equals(SearchScopeFactory.createUniverseScope());
fElemKind = elementKind;
fFilterExt = extension;
String stringPackage = ((TypeSearchPattern) patternMatcher).getPackagePattern();
if (stringPackage != null) {
fPackageMatcher = new SearchPattern();
fPackageMatcher.setPattern(stringPackage);
} else {
fPackageMatcher = null;
}
}
@Override
public boolean equalsFilter(ItemsFilter iFilter) {
if (!super.equalsFilter(iFilter)) {
return false;
}
if (!(iFilter instanceof TypeItemsFilter)) {
return false;
}
TypeItemsFilter typeItemsFilter = (TypeItemsFilter) iFilter;
if (fScope != typeItemsFilter.getSearchScope()) {
return false;
}
if (fMyTypeFilterVersion != typeItemsFilter.getMyTypeFilterVersion()) {
return false;
}
return true;
}
public int getElementKind() {
return fElemKind;
}
public ITypeInfoFilterExtension getFilterExtension() {
return fFilterExt;
}
public int getMyTypeFilterVersion() {
return fMyTypeFilterVersion;
}
public int getPackageFlags() {
if (fPackageMatcher == null) {
return SearchPattern.RULE_PREFIX_MATCH;
}
return fPackageMatcher.getMatchRule();
}
public String getPackagePattern() {
if (fPackageMatcher == null) {
return null;
}
return fPackageMatcher.getPattern();
}
public SearchScope getSearchScope() {
return fScope;
}
@Override
public boolean isConsistentItem(Object item) {
return true;
}
@Override
public boolean isSubFilter(ItemsFilter filter) {
if (!super.isSubFilter(filter)) {
return false;
}
TypeItemsFilter typeItemsFilter = (TypeItemsFilter) filter;
if (fScope != typeItemsFilter.getSearchScope()) {
return false;
}
if (fMyTypeFilterVersion != typeItemsFilter.getMyTypeFilterVersion()) {
return false;
}
//TODO(pquitslund): this forces a full refresh which works-around filter application refresh issues
return false;
}
public boolean matchesCachedResult(Element element) {
if (!(matchesFilterExtension(element))) {
return false;
}
return matchesName(element);
}
public boolean matchesFilterExtension(Element element) {
return true;
//TODO: consider whether we need filter extensions
// if (fFilterExt == null)
// return true;
// fAdapter.setMatch(type);
// return fFilterExt.select(fAdapter);
}
public boolean matchesHistoryElement(Element element) {
if (!(matchesScope(element) && matchesFilterExtension(element))) {
return false;
}
return matchesName(element);
}
public boolean matchesRawNamePattern(Element type) {
return Strings.startsWithIgnoreCase(type.getName(), getPattern());
}
@Override
public boolean matchesRawNamePattern(Object item) {
Element element = (Element) item;
return matchesRawNamePattern(element);
}
@Override
public boolean matchItem(Object item) {
if (fMatchEverything) {
return true;
}
Element element = (Element) item;
if (!(matchesScope(element) && matchesFilterExtension(element))) {
return false;
}
return matchesName(element);
}
/**
* Set filter to "match everything" mode.
*
* @param matchEverything if <code>true</code>, {@link #matchItem(Object)} always returns true.
* If <code>false</code>, the filter is enabled.
*/
public void setMatchEverythingMode(boolean matchEverything) {
this.fMatchEverything = matchEverything;
}
private boolean matchesName(Element element) {
return matches(element.getName());
}
private boolean matchesScope(Element element) {
if (fIsWorkspaceScope) {
return true;
}
return fScope.encloses(element);
}
}
/**
* Extends functionality of SearchPatterns
*/
private static class TypeSearchPattern extends SearchPattern {
private String packagePattern;
/**
* @return the packagePattern
*/
public String getPackagePattern() {
return packagePattern;
}
@Override
public void setPattern(String stringPattern) {
String pattern = stringPattern;
String packPattern = null;
int index = stringPattern.lastIndexOf("."); //$NON-NLS-1$
if (index != -1) {
packPattern = evaluatePackagePattern(stringPattern.substring(0, index));
pattern = stringPattern.substring(index + 1);
if (pattern.length() == 0) {
pattern = "**"; //$NON-NLS-1$
}
}
super.setPattern(pattern);
packagePattern = packPattern;
}
@Override
protected boolean isNameCharAllowed(char nameChar) {
return super.isNameCharAllowed(nameChar);
}
@Override
protected boolean isPatternCharAllowed(char patternChar) {
return super.isPatternCharAllowed(patternChar);
}
@Override
protected boolean isValidCamelCaseChar(char ch) {
return super.isValidCamelCaseChar(ch);
}
/*
* Transforms o.e.j to o*.e*.j*
*/
private String evaluatePackagePattern(String s) {
StringBuffer buf = new StringBuffer();
boolean hasWildCard = false;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '.') {
if (!hasWildCard) {
buf.append('*');
}
hasWildCard = false;
} else if (ch == '*' || ch == '?') {
hasWildCard = true;
}
buf.append(ch);
}
if (!hasWildCard) {
buf.append('*');
}
return buf.toString();
}
}
/**
* A <code>TypeSearchRequestor</code> collects matches filtered using <code>TypeItemsFilter</code>
* . The attached content provider is filled on the basis of the collected entries (instances of
* <code>TypeNameMatch</code> ).
*/
@SuppressWarnings("unused")
private class TypeSearchRequestor implements SearchListener {
private volatile boolean fStop;
private final AbstractContentProvider fContentProvider;
private final TypeItemsFilter fTypeItemsFilter;
public TypeSearchRequestor(AbstractContentProvider contentProvider,
TypeItemsFilter typeItemsFilter) {
super();
fContentProvider = contentProvider;
fTypeItemsFilter = typeItemsFilter;
}
public void cancel() {
fStop = true;
}
@Override
public void matchFound(SearchMatch match) {
if (fStop) {
return;
}
Element element = match.getElement();
if (fTypeItemsFilter.matchesFilterExtension(element)) {
fContentProvider.add(element, fTypeItemsFilter);
}
//TODO(pquitslund): this shouldn't be necessary (possibly remove once history is working)
scheduleRefresh();
}
@Override
public void searchComplete() {
// Ignored
}
}
/**
* Disabled "Show Container for Duplicates because of
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=184693 .
*/
private static final boolean BUG_184693 = true;
private static final String DIALOG_SETTINGS = "com.google.dart.tools.ui.dialogs.FilteredTypesSelectionDialog"; //$NON-NLS-1$
private static final String SHOW_CONTAINER_FOR_DUPLICATES = "ShowContainerForDuplicates"; //$NON-NLS-1$
private static final String WORKINGS_SET_SETTINGS = "WorkingSet"; //$NON-NLS-1$
private WorkingSetFilterActionGroup fFilterActionGroup;
private final TypeItemLabelProvider fTypeInfoLabelProvider;
private String fTitle;
private ShowContainerForDuplicatesAction fShowContainerForDuplicatesAction;
private SearchScope fSearchScope;
private boolean fAllowScopeSwitching;
private final int fElementKinds;
private final ITypeInfoFilterExtension fFilterExtension;
private final TypeSelectionExtension fExtension;
private ISelectionStatusValidator fValidator;
private final TypeInfoUtil fTypeInfoUtil;
@SuppressWarnings("unused")
private static boolean fgFirstTime = true;
private final TypeItemsComparator fTypeItemsComparator;
private int fTypeFilterVersion = 0;
// /**
// * Creates new FilteredTypesSelectionDialog instance
// *
// * @param parent shell to parent the dialog on
// * @param multi <code>true</code> if multiple selection is allowed
// * @param context context used to execute long-running operations associated with this dialog
// * @param scope scope used when searching for types
// * @param elementKinds flags defining nature of searched elements; the only valid values are:
// * <code>IJavaScriptSearchConstants.TYPE</code>
// * <code>IJavaScriptSearchConstants.ANNOTATION_TYPE</code>
// * <code>IJavaScriptSearchConstants.INTERFACE</code>
// * <code>IJavaScriptSearchConstants.ENUM</code>
// * <code>IJavaScriptSearchConstants.CLASS_AND_INTERFACE</code>
// * <code>IJavaScriptSearchConstants.CLASS_AND_ENUM</code>. Please note that the bitwise
// * OR combination of the elementary constants is not supported.
// */
// public FilteredTypesSelectionDialog(Shell parent, boolean multi, IRunnableContext context,
// SearchScope scope, int elementKinds) {
// this(parent, multi, context, scope, elementKinds, null);
// }
/**
* Creates new FilteredTypesSelectionDialog instance.
*
* @param shell shell to parent the dialog on
* @param multi <code>true</code> if multiple selection is allowed
* @param context context used to execute long-running operations associated with this dialog
* @param scope scope used when searching for types. If the scope is <code>null</code>, then
* workspace is scope is used as default, and the user can choose a working set as scope.
* @param elementKinds flags defining nature of searched elements (<em>currently ignored</em>).
* @param extension an extension of the standard type selection dialog; See
* {@link TypeSelectionExtension}
*/
public FilteredTypesSelectionDialog(Shell shell, boolean multi, IRunnableContext context,
SearchScope scope, int elementKinds, TypeSelectionExtension extension) {
super(shell, multi);
//TODO: implement selection history
// setSelectionHistory(new TypeSelectionHistory());
if (scope == null) {
fAllowScopeSwitching = true;
scope = SearchScopeFactory.createUniverseScope();
}
PlatformUI.getWorkbench().getHelpSystem().setHelp(
shell,
DartHelpContextIds.TYPE_SELECTION_DIALOG2);
fElementKinds = elementKinds;
fExtension = extension;
fFilterExtension = (extension == null) ? null : extension.getFilterExtension();
fSearchScope = scope;
if (extension != null) {
fValidator = extension.getSelectionValidator();
}
fTypeInfoUtil = new TypeInfoUtil(extension != null ? extension.getImageProvider() : null);
fTypeInfoLabelProvider = new TypeItemLabelProvider();
setListLabelProvider(fTypeInfoLabelProvider);
setListSelectionLabelDecorator(fTypeInfoLabelProvider);
setDetailsLabelProvider(new TypeItemDetailsLabelProvider(fTypeInfoUtil));
fTypeItemsComparator = new TypeItemsComparator();
}
@Override
public void create() {
super.create();
Control patternControl = getPatternControl();
if (patternControl instanceof Text) {
TextFieldNavigationHandler.install((Text) patternControl);
}
}
@Override
public String getElementName(Object item) {
return fTypeInfoUtil.getText(item);
}
@Override
public int open() {
if (getInitialPattern() == null) {
IWorkbenchWindow window = DartToolsPlugin.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 && DartConventions.validateTypeName(text).isOK()) {
setInitialPattern(text, FULL_SELECTION);
}
}
}
}
}
return super.open();
}
@Override
public void reloadCache(boolean checkDuplicates, IProgressMonitor monitor) {
IProgressMonitor remainingMonitor = monitor;
//TODO: enable history consistency runnable
// if (ConsistencyRunnable.needsExecution()) {
// monitor.beginTask(
// DartUIMessages.TypeSelectionDialog_progress_consistency, 10);
// try {
// ConsistencyRunnable runnable = new ConsistencyRunnable();
// runnable.run(new SubProgressMonitor(monitor, 1));
// } catch (InvocationTargetException e) {
// ExceptionHandler.handle(e,
// DartUIMessages.TypeSelectionDialog_error3Title,
// DartUIMessages.TypeSelectionDialog_error3Message);
// close();
// return;
// } catch (InterruptedException e) {
// // cancelled by user
// close();
// return;
// }
// remainingMonitor = new SubProgressMonitor(monitor, 9);
// } else {
// remainingMonitor = monitor;
// }
super.reloadCache(checkDuplicates, remainingMonitor);
monitor.done();
}
@Override
public void setTitle(String title) {
super.setTitle(title);
fTitle = title;
}
/**
* Sets a new validator.
*
* @param validator the new validator
*/
public void setValidator(ISelectionStatusValidator validator) {
fValidator = validator;
}
@Override
public void triggerSearch() {
fTypeFilterVersion++;
applyFilter();
}
@Override
protected Control createContents(Composite parent) {
Control contents = super.createContents(parent);
if (ColoredViewersManager.showColoredLabels()) {
if (contents instanceof Composite) {
Table listControl = findTableControl((Composite) contents);
if (listControl != null) {
installOwnerDraw(listControl);
}
}
}
return contents;
}
@Override
protected Control createExtendedContentArea(Composite parent) {
Control addition = null;
if (fExtension != null) {
addition = fExtension.createContentArea(parent);
if (addition != null) {
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
addition.setLayoutData(gd);
}
fExtension.initialize(this);
}
return addition;
}
@Override
protected ItemsFilter createFilter() {
return new TypeItemsFilter(fSearchScope, fElementKinds, fFilterExtension);
}
@Override
protected void fillContentProvider(final AbstractContentProvider provider,
ItemsFilter itemsFilter, IProgressMonitor progressMonitor) throws CoreException {
TypeItemsFilter typeSearchFilter = (TypeItemsFilter) itemsFilter;
SearchListener requestor = new TypeSearchRequestor(provider, typeSearchFilter);
Index globalIndex = DartCore.getProjectManager().getIndex();
SearchEngine engine = SearchEngineFactory.createSearchEngine(globalIndex);
//SearchEngine engine = SearchEngineFactory.createSearchEngine((WorkingCopyOwner) null);
progressMonitor.setTaskName(DartUIMessages.FilteredTypesSelectionDialog_searchJob_taskName);
/*
* Setting the filter into match everything mode avoids filtering twice by the same pattern (the
* search engine only provides filtered matches). For the case when the pattern is a camel case
* pattern with a terminator, the filter is not set to match everything mode because jdt.core's
* SearchPattern does not support that case.
*/
String typePattern = itemsFilter.getPattern();
int matchRule = typeSearchFilter.getMatchRule();
if (matchRule == SearchPattern.RULE_CAMELCASE_MATCH) {
// If the pattern is empty, the RULE_BLANK_MATCH will be chosen, so we
// don't have to check the pattern length
char lastChar = typePattern.charAt(typePattern.length() - 1);
if (lastChar == '<' || lastChar == ' ') {
typePattern = typePattern.substring(0, typePattern.length() - 1);
} else {
typeSearchFilter.setMatchEverythingMode(true);
}
} else {
typeSearchFilter.setMatchEverythingMode(true);
}
com.google.dart.engine.search.SearchPattern searchPattern = null;
switch (matchRule) {
case SearchPattern.RULE_CAMELCASE_MATCH:
searchPattern = SearchPatternFactory.createCamelCasePattern(typePattern, false);
break;
case SearchPattern.RULE_PATTERN_MATCH:
searchPattern = SearchPatternFactory.createWildcardPattern(typePattern, false);
break;
case SearchPattern.RULE_PREFIX_MATCH:
searchPattern = SearchPatternFactory.createPrefixPattern(typePattern, false);
break;
default:
searchPattern = SearchPatternFactory.createExactPattern(typePattern, false);
break;
}
try {
engine.searchTypeDeclarations(
typeSearchFilter.getSearchScope(),
searchPattern,
null,
requestor
/* progressMonitor */);
} finally {
typeSearchFilter.setMatchEverythingMode(false);
}
}
@Override
protected void fillViewMenu(IMenuManager menuManager) {
super.fillViewMenu(menuManager);
if (!BUG_184693) {
fShowContainerForDuplicatesAction = new ShowContainerForDuplicatesAction();
menuManager.add(fShowContainerForDuplicatesAction);
}
//TODO: add workingset search scope support
// if (fAllowScopeSwitching) {
// fFilterActionGroup = new WorkingSetFilterActionGroup(getShell(),
// new IPropertyChangeListener() {
// public void propertyChange(PropertyChangeEvent event) {
// IWorkingSet ws = (IWorkingSet) event.getNewValue();
// if (ws == null || (ws.isAggregateWorkingSet() && ws.isEmpty())) {
// setSearchScope(SearchScopeFactory.createWorkspaceScope());
// setSubtitle(null);
// } else {
// setSearchScope(JavaSearchScopeFactory.getInstance().createJavaSearchScope(
// ws, true));
// setSubtitle(ws.getLabel());
// }
//
// applyFilter();
// }
// });
// fFilterActionGroup.fillViewMenu(menuManager);
// }
menuManager.add(new Separator());
//TODO: add/remove type filter preferences
// menuManager.add(new TypeFiltersPreferencesAction());
}
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = DartToolsPlugin.getDefault().getDialogSettings().getSection(
DIALOG_SETTINGS);
if (settings == null) {
settings = DartToolsPlugin.getDefault().getDialogSettings().addNewSection(DIALOG_SETTINGS);
}
return settings;
}
@SuppressWarnings("rawtypes")
@Override
protected Comparator getItemsComparator() {
return fTypeItemsComparator;
}
@Override
protected void restoreDialog(IDialogSettings settings) {
super.restoreDialog(settings);
if (!BUG_184693) {
boolean showContainer = settings.getBoolean(SHOW_CONTAINER_FOR_DUPLICATES);
fShowContainerForDuplicatesAction.setChecked(showContainer);
fTypeInfoLabelProvider.setContainerInfo(showContainer);
} else {
fTypeInfoLabelProvider.setContainerInfo(true);
}
if (fAllowScopeSwitching) {
String setting = settings.get(WORKINGS_SET_SETTINGS);
if (setting != null) {
try {
IMemento memento = XMLMemento.createReadRoot(new StringReader(setting));
fFilterActionGroup.restoreState(memento);
} catch (WorkbenchException e) {
// don't do anything. Simply don't restore the settings
DartToolsPlugin.log(e);
}
}
//TODO: adding workingset scope support
// IWorkingSet ws = fFilterActionGroup.getWorkingSet();
// if (ws == null || (ws.isAggregateWorkingSet() && ws.isEmpty())) {
setSearchScope(SearchScopeFactory.createUniverseScope());
setSubtitle(null);
// } else {
// setSearchScope(JavaSearchScopeFactory.getInstance().createJavaSearchScope(
// ws, true));
// setSubtitle(ws.getLabel());
// }
}
// TypeNameMatch[] types = OpenTypeHistory.getInstance().getTypeInfos();
//
// for (int i = 0; i < types.length; i++) {
// TypeNameMatch type = types[i];
// accessedHistoryItem(type);
// }
}
@Override
protected void setResult(@SuppressWarnings("rawtypes") List newResult) {
List<Element> resultToReturn = new ArrayList<Element>();
for (int i = 0; i < newResult.size(); i++) {
if (newResult.get(i) instanceof Element) {
Element element = (Element) newResult.get(i);
// items are added to history in the
// org.eclipse.ui.dialogs.FilteredItemsSelectionDialog#computeResult()
// method
resultToReturn.add(element);
}
}
super.setResult(resultToReturn);
}
@Override
protected void storeDialog(IDialogSettings settings) {
super.storeDialog(settings);
if (!BUG_184693) {
settings.put(SHOW_CONTAINER_FOR_DUPLICATES, fShowContainerForDuplicatesAction.isChecked());
}
if (fFilterActionGroup != null) {
XMLMemento memento = XMLMemento.createWriteRoot("workingSet"); //$NON-NLS-1$
fFilterActionGroup.saveState(memento);
fFilterActionGroup.dispose();
StringWriter writer = new StringWriter();
try {
memento.save(writer);
settings.put(WORKINGS_SET_SETTINGS, writer.getBuffer().toString());
} catch (IOException e) {
// don't do anything. Simply don't store the settings
DartToolsPlugin.log(e);
}
}
}
@Override
protected IStatus validateItem(Object item) {
if (item == null) {
return new Status(IStatus.ERROR, DartToolsPlugin.getPluginId(), IStatus.ERROR, "", null); //$NON-NLS-1$
}
if (fValidator != null) {
Object[] elements = {item};
return fValidator.validate(elements);
} else {
return new Status(IStatus.OK, DartToolsPlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
}
}
private Table findTableControl(Composite composite) {
Control[] children = composite.getChildren();
for (int i = 0; i < children.length; i++) {
Control curr = children[i];
if (curr instanceof Table) {
return (Table) curr;
} else if (curr instanceof Composite) {
Table res = findTableControl((Composite) curr);
if (res != null) {
return res;
}
}
}
return null;
}
private void installOwnerDraw(Table tableControl) {
new OwnerDrawSupport(tableControl) { // installs the owner draw listeners
@Override
public Color getColor(String foregroundColorName, Display display) {
return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(
foregroundColorName);
}
@Override
public ColoredString getColoredLabel(Item item) {
String text = item.getText();
ColoredString str = new ColoredString(text);
int index = text.indexOf('-');
if (index != -1) {
str.colorize(index, str.length() - index, ColoredDartElementLabels.QUALIFIER_STYLE);
}
return str;
}
};
}
/**
* Sets search scope used when searching for types.
*
* @param scope the new scope
*/
private void setSearchScope(SearchScope scope) {
fSearchScope = scope;
}
/**
* Adds or replaces subtitle of the dialog
*
* @param text the new subtitle for this dialog
*/
private void setSubtitle(String text) {
if (text == null || text.length() == 0) {
getShell().setText(fTitle);
} else {
getShell().setText(
Messages.format(DartUIMessages.FilteredTypeSelectionDialog_titleFormat, new String[] {
fTitle, text}));
}
}
}