/******************************************************************************* * Copyright (c) 2010-2014 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.text.xml.contentassist; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.wst.sse.ui.contentassist.CompletionProposalInvocationContext; import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal; import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceCompletionProposal; import org.eclipse.wst.sse.ui.internal.util.Sorter; import org.jboss.tools.common.text.ITextProposalProvider; import org.jboss.tools.common.text.TextProposal; /** * The utility helper class which purpose is to filter out and sort * Content Assist proposals * * @author Victor V. Rubezhny */ @SuppressWarnings("restriction") public class ProposalSorter { /** * Utility that helps to ProposalSorter object to filter out the proposals that aren't valid for the * given context */ public static interface IProposalFilter { boolean isValidProposal(CompletionProposalInvocationContext context, ICompletionProposal proposal); } /** * Filters and sorts the Content Assist proposals, using the external filter */ public static List<ICompletionProposal> filterAndSortProposals(List<ICompletionProposal> proposals, IProgressMonitor monitor, CompletionProposalInvocationContext context, IProposalFilter filter) { if (proposals == null) return null; ICompletionProposal[] resultArray = (ICompletionProposal[])proposals.toArray(new ICompletionProposal[proposals.size()]); resultArray = makeUnique(resultArray); resultArray = filterProposals(resultArray, context, filter); Object[] sorted = createSorter().sort(resultArray); System.arraycopy(sorted, 0, resultArray, 0, sorted.length); return Arrays.asList(resultArray); } /** * Filters and sorts the Content Assist proposals */ public static List<ICompletionProposal> filterAndSortProposals(List<ICompletionProposal> proposals, IProgressMonitor monitor, CompletionProposalInvocationContext context) { return filterAndSortProposals(proposals, monitor, context, null); } private static Sorter createSorter() { return new Sorter() { public boolean compare(Object proposal1, Object proposal2) { int pr1 = Integer.MIN_VALUE; int pr2 = Integer.MIN_VALUE; ICompletionProposal p1 = (ICompletionProposal)proposal1; ICompletionProposal p2 = (ICompletionProposal)proposal2; if (p1 instanceof IRelevanceCompletionProposal) pr1 = ((IRelevanceCompletionProposal)p1).getRelevance(); if (p2 instanceof IRelevanceCompletionProposal) pr2 = ((IRelevanceCompletionProposal)p2).getRelevance(); if (pr1 == pr2) { String str1 = (p1.getDisplayString() == null ? "" : p1.getDisplayString()); //$NON-NLS-1$ String str2 = (p2.getDisplayString() == null ? "" : p2.getDisplayString()); //$NON-NLS-1$ return str2.compareTo(str1) > 0; } return (pr1 > pr2); } }; } /** * Removes duplicates of completion strings * * @param suggestions a list of suggestions ({@link String}). * @return a list of unique completion suggestions. */ public static ICompletionProposal[] makeUnique(ICompletionProposal[] proposals) { if (proposals == null) return null; Map <String, ICompletionProposal> existingProposals = new HashMap<String, ICompletionProposal>(proposals.length); ArrayList<ICompletionProposal> unique = new ArrayList<ICompletionProposal>(proposals.length); for (ICompletionProposal proposal : proposals) { if (proposal == null) continue; String replString = null; String dispString = null; if (proposal instanceof CustomCompletionProposal) { replString = ((CustomCompletionProposal) proposal) .getReplacementString(); } dispString = unQuote(proposal.getDisplayString()); replString = getReplacementWord(replString == null ? dispString : replString); boolean isFilterable = true; if (proposal instanceof ITextProposalProvider) { TextProposal textProposal = ((ITextProposalProvider)proposal).getTextProposal(); isFilterable = (textProposal == null || textProposal.isFilterable()); } if (isFilterable) { ICompletionProposal existingProposal = existingProposals.get(replString); if (existingProposal == null) { existingProposals.put(replString, proposal); unique.add(proposal); } else { if (existingProposal instanceof IRelevanceCompletionProposal && proposal instanceof IRelevanceCompletionProposal) { if (((IRelevanceCompletionProposal)existingProposal).getRelevance() < ((IRelevanceCompletionProposal)proposal).getRelevance()) { existingProposals.put(replString, proposal); unique.remove(existingProposal); unique.add(proposal); } } } } else { unique.add(proposal); } } return unique.toArray(new ICompletionProposal[unique.size()]); } public static ICompletionProposal[] filterProposals(ICompletionProposal[] proposals, CompletionProposalInvocationContext context, IProposalFilter filter) { if (filter == null) return proposals; ArrayList<ICompletionProposal> filtered = new ArrayList<ICompletionProposal>(proposals.length); for (ICompletionProposal proposal : proposals) { if (filter.isValidProposal(context, proposal)) { filtered.add(proposal); } } return filtered.toArray(new ICompletionProposal[filtered.size()]); } private static String getReplacementWord(String replacement) { replacement = (replacement == null ? "" : //$NON-NLS-1$ replacement); int index = replacement.indexOf('>'); if (index != -1) { replacement = replacement.substring(0, index).trim(); if (replacement.endsWith("/")) //$NON-NLS-1$ replacement = replacement .substring(0, replacement.length() - 1).trim(); } index = replacement.indexOf("="); //$NON-NLS-1$ if (index != -1) { replacement = replacement.substring(0, index).trim(); } index = replacement.indexOf(" "); //$NON-NLS-1$ if (index != -1) { replacement = replacement.substring(0, index).trim(); } return replacement; } private static String unQuote(String str) { str = (str == null ? "" : //$NON-NLS-1$ str.toLowerCase()); if (str.startsWith("\"")) //$NON-NLS-1$ str = str.substring(1); if (str.endsWith("\"")) //$NON-NLS-1$ str = str.substring(0, str.length() - 1); str = str.trim().toLowerCase(); return str; } }