From e0a9f12895ca4fb5717e1dcf469382300fb8db32 Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Wed, 18 Jan 2006 15:34:05 +0000 Subject: [PATCH] Bug 104792 - Content proposal filtering feature. --- core/org.eclipse.cdt.ui.tests/plugin.xml | 7 + .../ProposalFilterPreferencesTest.java | 50 ++++ .../contentassist/TestProposalFilter.java | 19 ++ core/org.eclipse.cdt.ui/plugin.xml | 1 + .../schema/ProposalFilter.exsd | 122 +++++++++ .../preferences/AbstractPreferencePage.java | 42 +++- .../preferences/CodeAssistPreferencePage.java | 8 +- .../PreferencesMessages.properties | 2 + .../ProposalFilterPreferencesUtil.java | 232 ++++++++++++++++++ .../contentassist/CCompletionProcessor2.java | 75 +++--- .../ContentAssistPreference.java | 4 +- .../contentassist/DefaultProposalFilter.java | 58 +++++ .../text/contentassist/IProposalFilter.java | 18 ++ 13 files changed, 594 insertions(+), 44 deletions(-) create mode 100644 core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/ProposalFilterPreferencesTest.java create mode 100644 core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/TestProposalFilter.java create mode 100644 core/org.eclipse.cdt.ui/schema/ProposalFilter.exsd create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/ProposalFilterPreferencesUtil.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DefaultProposalFilter.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/contentassist/IProposalFilter.java diff --git a/core/org.eclipse.cdt.ui.tests/plugin.xml b/core/org.eclipse.cdt.ui.tests/plugin.xml index 5d346cd499e..6e420b224ba 100644 --- a/core/org.eclipse.cdt.ui.tests/plugin.xml +++ b/core/org.eclipse.cdt.ui.tests/plugin.xml @@ -121,5 +121,12 @@ id="org.eclipse.cdt.ui.tests.DOMAST.DOMAST.IncludeStatementFilter"> + + + diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/ProposalFilterPreferencesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/ProposalFilterPreferencesTest.java new file mode 100644 index 00000000000..55d83482672 --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/ProposalFilterPreferencesTest.java @@ -0,0 +1,50 @@ +package org.eclipse.cdt.ui.tests.text.contentassist; + +import org.eclipse.cdt.internal.ui.preferences.ProposalFilterPreferencesUtil; +import org.eclipse.cdt.internal.ui.preferences.ProposalFilterPreferencesUtil.ComboState; +import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.jface.preference.IPreferenceStore; + +import junit.framework.TestCase; + +/** + * This test covers the convenience methods + * in org.eclipse.cdt.internal.ui.preferences.ProposalFilterPreferencesUtil + */ +public class ProposalFilterPreferencesTest extends TestCase { + + public void testPreferences() { + // Check that the test filter is among the filternames + String[] filterNames = ProposalFilterPreferencesUtil.getProposalFilterNames(); + int index = -1 ; + for (int i = 0; i < filterNames.length; i++) { + String name = filterNames[i]; + if (name.equals("Testing Completion Filter")) { + index = i ; + break ; + } + } + assertTrue("Did not find expected filter!", index>=0); + + // Set the preference to the tested filter + IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore(); + String filterComboStateString = store.getString(ContentAssistPreference.PROPOSALS_FILTER); + ProposalFilterPreferencesUtil.ComboState state = ProposalFilterPreferencesUtil.getComboState(filterComboStateString); + StringBuffer newStateText = new StringBuffer(); + newStateText.append(index+1); // First entry is always the , index+1 must be selected + for (int i = 0; i < state.items.length; i++) { + String item = state.items[i]; + newStateText.append(";"); + newStateText.append(item); + } + store.setValue(ContentAssistPreference.PROPOSALS_FILTER, newStateText.toString()); + + // Now we can test preferred filter retrieval: + IConfigurationElement preferredElement = ProposalFilterPreferencesUtil.getPreferredFilterElement(); + String extensionId = preferredElement.getAttribute("id"); + assertNotNull("Configuration element was not found!", extensionId); + assertEquals("Unexpected element id", "org.eclipse.cdt.ui.tests.TestProposalFilter", extensionId); + } +} diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/TestProposalFilter.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/TestProposalFilter.java new file mode 100644 index 00000000000..e7b65212f7e --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist/TestProposalFilter.java @@ -0,0 +1,19 @@ +package org.eclipse.cdt.ui.tests.text.contentassist; + +import org.eclipse.cdt.ui.text.ICCompletionProposal; +import org.eclipse.cdt.ui.text.contentassist.IProposalFilter; + +/** + * Dummy filter implementation for testing purposes + */ +public class TestProposalFilter implements IProposalFilter { + + /** + * This dummy filter method will return the original proposals unmodified. + */ + public ICCompletionProposal[] filterProposals( + ICCompletionProposal[] proposals) { + return proposals ; + } + +} diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index d41ba1f5c0f..da6bf1930f4 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -17,6 +17,7 @@ + diff --git a/core/org.eclipse.cdt.ui/schema/ProposalFilter.exsd b/core/org.eclipse.cdt.ui/schema/ProposalFilter.exsd new file mode 100644 index 00000000000..6b898119bca --- /dev/null +++ b/core/org.eclipse.cdt.ui/schema/ProposalFilter.exsd @@ -0,0 +1,122 @@ + + + + + + + + + This extension point allows contributors to make their implementation of ICompletionFilter known to the platform. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CDT 3.1 + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + + + + + diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractPreferencePage.java index a3c130c0b93..949ed5989c3 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/AbstractPreferencePage.java @@ -33,6 +33,7 @@ import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; @@ -63,6 +64,16 @@ public abstract class AbstractPreferencePage extends PreferencePage implements I fOverlayStore.setValue((String) fTextFields.get(text), text.getText()); } }; + + protected Map fComboBoxes = new HashMap(); + private ModifyListener fComboBoxListener = new ModifyListener() { + public void modifyText(ModifyEvent e) { + Combo combo = (Combo) e.widget; + String state = ProposalFilterPreferencesUtil.comboStateAsString(combo); + fOverlayStore.setValue((String) fComboBoxes.get(combo), state); + } + }; + protected Map fCheckBoxes = new HashMap(); private SelectionListener fCheckBoxListener = new SelectionListener() { @@ -157,6 +168,24 @@ public abstract class AbstractPreferencePage extends PreferencePage implements I return textControl; } + protected void addComboBox(Composite composite, String label, String key, int textLimit, int indentation) { + + Label labelControl = new Label(composite, SWT.NONE); + labelControl.setText(label); + GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + gd.horizontalIndent = indentation; + labelControl.setLayoutData(gd); + + Combo comboControl = new Combo(composite, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY); // TODO: When will the combo be disposed? + gd = new GridData(GridData.HORIZONTAL_ALIGN_END); + gd.widthHint = convertWidthInCharsToPixels(textLimit + 1); + comboControl.setLayoutData(gd); + comboControl.setTextLimit(textLimit); + fComboBoxes.put(comboControl, key); + comboControl.addModifyListener(fComboBoxListener); // TODO: When will the listener be removed? + + } + protected void addFiller(Composite composite) { PixelConverter pixelConverter= new PixelConverter(composite); Label filler= new Label(composite, SWT.LEFT ); @@ -292,11 +321,22 @@ public abstract class AbstractPreferencePage extends PreferencePage implements I String key = (String) fTextFields.get(t); t.setText(fOverlayStore.getString(key)); } + + e = fComboBoxes.keySet().iterator(); + while (e.hasNext()) { + Combo c = (Combo) e.next(); + String key = (String) fComboBoxes.get(c); + String state = fOverlayStore.getString(key); + // Interpret the state string as a Combo state description + ProposalFilterPreferencesUtil.restoreComboFromString(c, state); + } } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) */ public void init(IWorkbench workbench) { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CodeAssistPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CodeAssistPreferencePage.java index e147b045a4c..1a38dd84082 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CodeAssistPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CodeAssistPreferencePage.java @@ -58,6 +58,7 @@ public class CodeAssistPreferencePage extends AbstractPreferencePage { overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, ContentAssistPreference.ADD_INCLUDE)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, ContentAssistPreference.CURRENT_FILE_SEARCH_SCOPE)); overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, ContentAssistPreference.PROJECT_SEARCH_SCOPE)); + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, ContentAssistPreference.PROPOSALS_FILTER)); OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys.size()]; overlayKeys.toArray(keys); @@ -135,7 +136,10 @@ public class CodeAssistPreferencePage extends AbstractPreferencePage { // label= PreferencesMessages.getString("CEditorPreferencePage.ContentAssistPage.parameterForegroundColor"); // addColorButton(contentAssistComposite, label, ContentAssistPreference.PARAMETERS_FOREGROUND, 0); - initializeFields(); + label = PreferencesMessages.getString("CEditorPreferencePage.ContentAssistPage.proposalFilterSelect") ; //$NON-NLS-1$ + addComboBox(contentAssistComposite, label, ContentAssistPreference.PROPOSALS_FILTER, 20, 0); + + initializeFields(); PlatformUI.getWorkbench().getHelpSystem().setHelp(contentAssistComposite, ICHelpContextIds.C_EDITOR_CONTENT_ASSIST_PREF_PAGE); @@ -168,6 +172,8 @@ public class CodeAssistPreferencePage extends AbstractPreferencePage { PreferenceConverter.setDefault(store, ContentAssistPreference.PARAMETERS_FOREGROUND, new RGB(0, 0, 0)); store.setDefault(ContentAssistPreference.ORDER_PROPOSALS, false); store.setDefault(ContentAssistPreference.ADD_INCLUDE, true); + store.setDefault(ContentAssistPreference.PROPOSALS_FILTER, ProposalFilterPreferencesUtil.getProposalFilternamesAsString()); // $NON_NLS 1$ } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index 40c7598a71b..382cd386e80 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -85,6 +85,7 @@ CEditorPreferencePage.ContentAssistPage.autoActivationGroupTitle=Auto activation CEditorPreferencePage.ContentAssistPage.autoActivationEnableDot=Enable "." as trigger CEditorPreferencePage.ContentAssistPage.autoActivationEnableArrow=Enable "->" as trigger CEditorPreferencePage.ContentAssistPage.autoActivationDelay=dela&y (ms) +CEditorPreferencePage.ContentAssistPage.proposalFilterSelect=Completion Proposal Filter: CEditorPreferencePage.ContentAssistPage.completionProposalBackgroundColor=&Background for completion proposals: CEditorPreferencePage.ContentAssistPage.completionProposalForegroundColor=&Foreground for completion proposals: CEditorPreferencePage.ContentAssistPage.parameterBackgroundColor=Bac&kground for method parameters: @@ -260,3 +261,4 @@ PathEntryVariableSelectionDialog.ExtensionDialog.description = Choose extension #Indexer IndexerPrefs.description=Sets default Indexer Options for new Projects +ProposalFilterPreferencesUtil.defaultFilterName= diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/ProposalFilterPreferencesUtil.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/ProposalFilterPreferencesUtil.java new file mode 100644 index 00000000000..1fa50504efd --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/ProposalFilterPreferencesUtil.java @@ -0,0 +1,232 @@ +package org.eclipse.cdt.internal.ui.preferences; + +import java.util.ArrayList; + +import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.InvalidRegistryObjectException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.widgets.Combo; + +/** + * A class which encapsulates several utility functions + * related to code completion preference settings. + */ +public class ProposalFilterPreferencesUtil { + + /** + * Private default constructor prevents instantiation + */ + private ProposalFilterPreferencesUtil() { + } + + /** + * Get an array of proposal filter names + * (i.e. the human-readable text for display + * to fill into the Combo) + */ + public static String[] getProposalFilterNames() { + ArrayList names = new ArrayList(); + try { + IExtensionPoint point = Platform.getExtensionRegistry() + .getExtensionPoint(CUIPlugin.PLUGIN_ID, "ProposalFilter"); //$NON-NLS-1$ + if (point != null) { + IExtension[] extensions = point.getExtensions(); + for (int i = 0; i < extensions.length; i++) { + IExtension extension = extensions[i]; + IConfigurationElement[] elements = extension + .getConfigurationElements(); + for (int j = 0; j < elements.length; ++j) { + IConfigurationElement element = elements[j]; + if ("ProposalFilter".equals(element.getName())) { //$NON-NLS-1$ + String filterName = element.getAttribute("name"); + if (null != filterName) { + names.add(filterName); + } + } + } + } + } + } catch (InvalidRegistryObjectException e) { + // No action required since we will at least be using the fail-safe default filter + CUIPlugin.getDefault().log(e); + } + String[] filterNames = (String[]) names + .toArray(new String[names.size()]); + return filterNames; + } + + /** + * Look up all contributed completion proposal filters + * and return their names as a semicolon-separated list + * plus a leading entry for the selected index 0, + * plus a leading entry.
+ * A Combo may be initialized from this string. + * @return The list of filter names + */ + public static String getProposalFilternamesAsString() { + StringBuffer filterNames = new StringBuffer("0;"); + filterNames.append(""); // TODO: NP externalize this! + String[] names = getProposalFilterNames(); + for (int i = 0; i < names.length; i++) { + String name = names[i]; + filterNames.append(";"); + filterNames.append(name); + } + return filterNames.toString(); + } + + /** + * Return the configuration element which corresponds + * to the human-readable filter name + * @param filterName The human-readable filter name + * @return The configuration element, or null if there is none + */ + public static IConfigurationElement getElementForName(String filterName) { + IConfigurationElement element = null; + IExtensionPoint point = Platform.getExtensionRegistry() + .getExtensionPoint(CUIPlugin.PLUGIN_ID, "ProposalFilter"); //$NON-NLS-1$ + if (point != null) { + try { + IExtension[] extensions = point.getExtensions(); + if (extensions.length >= 1) { + for (int i = 0; i < extensions.length; i++) { + IExtension extension = extensions[i]; + + IConfigurationElement[] elements = extension + .getConfigurationElements(); + + for (int j = 0; j < elements.length; ++j) { + IConfigurationElement testElement = elements[j]; + if ("ProposalFilter".equals(testElement.getName())) { //$NON-NLS-1$ + String testName = testElement + .getAttribute("name"); + if ((null != testName) + && (filterName.equals(testName))) { + element = testElement; + break; + } + } + } + // Did we find the corresponding element? + if (null != element) + break; + } + } + } catch (InvalidRegistryObjectException e) { + // In case of failure we'll just return null + } + } + + return element; + } + + /** + * The state of a Combo consists of the list of entries + * and the index of the selected entry. + * This method converts the state of the given Combo + * to a string representation for storage in a preference store.
+ * The string contains a semicolon-separated list of entries. + * The first entry is the index of the selected entry. + * The following entries are the texts of the individual fields.
+ * Since the semicolon is the separator, the entries cannot contain semicolons. + * This method will replace semicolons with commas if any are found. + * @param combo The Combo whose state shall be converted + * @return A string representation of the Combo state + */ + public static String comboStateAsString(Combo combo) { + StringBuffer text = new StringBuffer(); + int selectionIndex = combo.getSelectionIndex(); + text.append(selectionIndex); + String[] entries = combo.getItems(); + for (int i = 0; i < entries.length; i++) { + text.append(";"); + String entry = entries[i].replaceAll(";", ","); + text.append(entry); + } + return text.toString(); + } + + /** + * The state of a Combo consists of the list of entries + * and the index of the selected entry. + * This method takes a string representation of the state (e.g. from a preference store) + * and restores it into the Combo.
+ * For a description of the text format see method comboStateAsString(). + * @param combo The combo to be restored. + * @param text The text representation of the state. + */ + public static void restoreComboFromString(Combo combo, String text) { + try { + int endFirstEntry = text.indexOf(";"); + if (endFirstEntry > 0) { // First entry must contain at least one character + String selectedString = text.substring(0, endFirstEntry); + int selectedIndex = Integer.parseInt(selectedString); + String[] entryList = text.substring(endFirstEntry + 1, + text.length()).split(";"); + combo.setItems(entryList); + combo.select(selectedIndex); + } + } catch (NumberFormatException e) { + // If this fails we just return the unmodified Combo + } + } + + /** + * Convenience class wraps the data to initialize a Combo + */ + public static class ComboState { + public int selectedIndex; + + public String[] items; + } + + /** + * Convenience method to extract the state of a Combo + * from the state string stored e.g. in a preference store + * @param comboPreference The state string + * @return A ComboState instance. + */ + public static ComboState getComboState(String comboPreference) { + ComboState state = new ComboState(); + try { + int endFirstEntry = comboPreference.indexOf(";"); + if (endFirstEntry > 0) { // First entry must contain at least one character + String selectedString = comboPreference.substring(0, + endFirstEntry); + state.selectedIndex = Integer.parseInt(selectedString); + state.items = comboPreference.substring(endFirstEntry + 1, + comboPreference.length()).split(";"); + } + } catch (NumberFormatException e) { + // If this fails we return an empty ComboState + state.items = new String[0]; + } + return state; + } + + /** + * Look up the setting for the preferred proposal filter + * and return it's configuration element. + * @return The configuration element, or null if none is found. + */ + public static IConfigurationElement getPreferredFilterElement() { + IConfigurationElement preferredElement = null; + try { + IPreferenceStore store = CUIPlugin.getDefault() + .getPreferenceStore(); + String filterComboStateString = store + .getString(ContentAssistPreference.PROPOSALS_FILTER); + ComboState state = getComboState(filterComboStateString); + preferredElement = getElementForName(state.items[state.selectedIndex]); + } catch (Exception e) { + // If anything goes wrong we'll just return null + } + return preferredElement; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProcessor2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProcessor2.java index 747115d15f4..c1332b24e4e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProcessor2.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CCompletionProcessor2.java @@ -11,7 +11,6 @@ package org.eclipse.cdt.internal.ui.text.contentassist; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.eclipse.cdt.core.dom.CDOM; @@ -22,17 +21,21 @@ import org.eclipse.cdt.core.dom.IASTServiceProvider.UnsupportedDialectException; import org.eclipse.cdt.core.dom.ast.ASTCompletionNode; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.internal.ui.CUIMessages; +import org.eclipse.cdt.internal.ui.preferences.ProposalFilterPreferencesUtil; import org.eclipse.cdt.internal.ui.text.CParameterListValidator; import org.eclipse.cdt.internal.ui.util.ExternalEditorInput; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.text.ICCompletionProposal; import org.eclipse.cdt.ui.text.contentassist.ICompletionContributor; +import org.eclipse.cdt.ui.text.contentassist.IProposalFilter; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IStorage; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.InvalidRegistryObjectException; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; @@ -128,48 +131,12 @@ public class CCompletionProcessor2 implements IContentAssistProcessor { } } - ICCompletionProposal[] propsArray = null; + IProposalFilter filter = getCompletionFilter(); + ICCompletionProposal[] proposalsInput = (ICCompletionProposal[]) proposals.toArray(new ICCompletionProposal[proposals.size()]) ; - if (!proposals.isEmpty()) { - errorMessage = null; - propsArray = (ICCompletionProposal[])proposals.toArray(new ICCompletionProposal[proposals.size()]); - CCompletionProposalComparator propsComp = new CCompletionProposalComparator(); - propsComp.setOrderAlphabetically(true); - Arrays.sort(propsArray, propsComp); - - // remove duplicates but leave the ones with return types - - int last = 0; - int removed = 0; - for (int i = 1; i < propsArray.length; ++i) { - if (propsComp.compare(propsArray[last], propsArray[i]) == 0) { - // We want to leave the one that has the return string if any - boolean lastReturn = propsArray[last].getIdString() != propsArray[last].getDisplayString(); - boolean iReturn = propsArray[i].getIdString() != propsArray[i].getDisplayString(); - - if (!lastReturn && iReturn) - // flip i down to last - propsArray[last] = propsArray[i]; - - // Remove the duplicate - propsArray[i] = null; - ++removed; - } else - // update last - last = i; - } - if (removed > 0) { - // Strip out the null entries - ICCompletionProposal[] newArray = new ICCompletionProposal[propsArray.length - removed]; - int j = 0; - for (int i = 0; i < propsArray.length; ++i) - if (propsArray[i] != null) - newArray[j++] = propsArray[i]; - propsArray = newArray; - } - } + ICCompletionProposal[] proposalsFiltered = filter.filterProposals(proposalsInput); - return propsArray; + return proposalsFiltered; } catch (UnsupportedDialectException e) { errorMessage = CUIMessages.getString(dialectError); @@ -179,6 +146,32 @@ public class CCompletionProcessor2 implements IContentAssistProcessor { return null; } + + private IProposalFilter getCompletionFilter() { + IProposalFilter filter = null; + try { + IConfigurationElement filterElement = ProposalFilterPreferencesUtil.getPreferredFilterElement(); + if (null != filterElement) { + Object contribObject = filterElement + .createExecutableExtension("class"); //$NON-NLS-1$ + if ((contribObject instanceof IProposalFilter)) { + filter = (IProposalFilter) contribObject; + } + } + } catch (InvalidRegistryObjectException e) { + // No action required since we will be using the fail-safe default filter + CUIPlugin.getDefault().log(e); + } catch (CoreException e) { + // No action required since we will be using the fail-safe default filter + CUIPlugin.getDefault().log(e); + } + + if (null == filter) { + // fail-safe default implementation + filter = new DefaultProposalFilter(); + } + return filter; + } private String scanPrefix(IDocument document, int end) { try { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ContentAssistPreference.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ContentAssistPreference.java index c82ec2677eb..9f351ebead4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ContentAssistPreference.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/ContentAssistPreference.java @@ -63,7 +63,9 @@ public class ContentAssistPreference { public final static String CURRENT_FILE_SEARCH_SCOPE= "content_assist_current_file_search_scope"; //$NON-NLS-1$ /** Preference key for completion search scope */ public final static String PROJECT_SEARCH_SCOPE= "content_assist_project_search_scope"; //$NON-NLS-1$ - + /** Preference key for completion filtering */ + public final static String PROPOSALS_FILTER= "content_assist_proposal_filter"; //$NON_NLS 1$ + private static Color getColor(IPreferenceStore store, String key, IColorManager manager) { RGB rgb= PreferenceConverter.getColor(store, key); return manager.getColor(rgb); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DefaultProposalFilter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DefaultProposalFilter.java new file mode 100644 index 00000000000..bd6d6efdbb1 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DefaultProposalFilter.java @@ -0,0 +1,58 @@ +package org.eclipse.cdt.internal.ui.text.contentassist; + +import java.util.Arrays; + +import org.eclipse.cdt.ui.text.ICCompletionProposal; +import org.eclipse.cdt.ui.text.contentassist.IProposalFilter; + +/** + * The default code completion filter: Remove duplicate entries on the basis of + * their id string. Use CCompletionProposalComparator for sorting. + */ +public class DefaultProposalFilter implements IProposalFilter { + + public ICCompletionProposal[] filterProposals( + ICCompletionProposal[] proposals) { + + CCompletionProposalComparator propsComp = new CCompletionProposalComparator(); + propsComp.setOrderAlphabetically(true); + Arrays.sort(proposals, propsComp); + + // remove duplicates but leave the ones with return types + + int last = 0; + int removed = 0; + for (int i = 1; i < proposals.length; ++i) { + if (propsComp.compare(proposals[last], proposals[i]) == 0) { + // We want to leave the one that has the return string if any + boolean lastReturn = proposals[last].getIdString() != proposals[last] + .getDisplayString(); + boolean iReturn = proposals[i].getIdString() != proposals[i] + .getDisplayString(); + + if (!lastReturn && iReturn) + // flip i down to last + proposals[last] = proposals[i]; + + // Remove the duplicate + proposals[i] = null; + ++removed; + } else + // update last + last = i; + } + if (removed > 0) { + // Strip out the null entries + ICCompletionProposal[] newArray = new ICCompletionProposal[proposals.length + - removed]; + int j = 0; + for (int i = 0; i < proposals.length; ++i) + if (proposals[i] != null) + newArray[j++] = proposals[i]; + proposals = newArray; + } + + return proposals; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/contentassist/IProposalFilter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/contentassist/IProposalFilter.java new file mode 100644 index 00000000000..b07a9bcc218 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/contentassist/IProposalFilter.java @@ -0,0 +1,18 @@ +package org.eclipse.cdt.ui.text.contentassist; + +import org.eclipse.cdt.ui.text.ICCompletionProposal; + + +public interface IProposalFilter { + + /** + * Filter a list of ICCompletionProposals
+ * - Change the order of entries
+ * - Remove undesired (duplicate) entries
+ * - Supplement existing entries with additional information + * @param proposals The List of proposals + * @return The filtered list of proposals as array + */ + ICCompletionProposal[] filterProposals(ICCompletionProposal[] proposals) ; + +}