--- a/editor.completion/nbproject/project.xml Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/nbproject/project.xml Sat Feb 25 13:00:55 2012 -0600
@@ -50,6 +50,15 @@
org.netbeans.modules.editor.completion
+ org.netbeans.api.annotations.common
+
+
+
+ 1
+ 1.11
+
+
+
org.netbeans.modules.editor
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java Sat Feb 25 13:00:55 2012 -0600
@@ -49,6 +49,7 @@
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -129,6 +130,64 @@
private static final int PLEASE_WAIT_TIMEOUT = 750;
private static final int PRESCAN = 25;
+
+ /**
+ * A default {@link CompletionController} which is used for the "Please wait..."
+ * and "No suggestions" completion results.
+ */
+ private final CompletionController FALLBACK_COMPLETION_CONTROLLER =
+ new CompletionController() {
+ @Override
+ public void sortItems(List extends CompletionItem> items, int sortType) {
+ assert items.size() == 1;
+ }
+
+ @Override
+ public Selection getSelection(List extends CompletionItem> items) {
+ assert items.size() == 1;
+ return Selection.DEFAULT;
+ }
+
+ @Override
+ public void defaultAction(CompletionItem bestMatch, boolean isSelected) {
+ if (isSelected) {
+ bestMatch.defaultAction(getActiveComponent());
+ }
+ }
+
+ @Override
+ public void processKeyEvent(KeyEvent evt, CompletionItem bestMatch,
+ boolean isSelected) {
+ bestMatch.processKeyEvent(evt);
+ }
+
+ @Override
+ public void render(Graphics g, Font defaultFont, Color foregroundColor,
+ Color backgroundColor, Color selectedForegroundColor,
+ Color selectedBackgroundColor, int width, int height, CompletionItem item,
+ boolean isBestMatch, boolean isSelected) {
+ if (isBestMatch) {
+ // Clear the background
+ g.setColor(selectedBackgroundColor);
+ g.fillRect(0, 0, width, height);
+ g.setColor(selectedForegroundColor);
+ item.render(g, defaultFont, selectedForegroundColor,
+ selectedBackgroundColor, width, height, isBestMatch);
+ } else {
+ // Clear the background
+ g.setColor(backgroundColor);
+ g.fillRect(0, 0, width, height);
+ g.setColor(foregroundColor);
+ item.render(g, defaultFont, foregroundColor, backgroundColor,
+ width, height, isBestMatch);
+ }
+ }
+
+ @Override
+ public boolean instantSubstitution(CompletionItem uniqueMatch) {
+ return uniqueMatch.instantSubstitution(getActiveComponent());
+ }
+ };
public static CompletionImpl get() {
if (singleton == null)
@@ -166,8 +225,12 @@
/* Completion providers registered for the active component (its mime-type). Changed in AWT only. */
private CompletionProvider[] activeProviders = null;
- /** Mapping of mime-type to array of providers. Changed in AWT only. */
- private HashMap providersCache = new HashMap();
+ /** Completion providers registered for the active component (its mime-type). Changed in AWT only. */
+ private CompletionControllerProvider[] activeControllerProviders = null;
+
+ /** Mapping of mime-type to service provider type to array of providers. Changed in AWT only. */
+ private HashMap, Object[]>> providersCache =
+ new HashMap, Object[]>>();
/**
* Result of the completion query.
@@ -253,7 +316,9 @@
docAutoPopupTimer = new Timer(0, new ActionListener() {
public void actionPerformed(ActionEvent e) {
- if (lastSelectedItem == null || lastSelectedItem.get() != layout.getSelectedCompletionItem())
+ SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem();
+ CompletionItem currentSelectedItem = selectedItem != null ? selectedItem.getItem() : null;
+ if (lastSelectedItem == null || lastSelectedItem.get() != currentSelectedItem)
showDocumentation();
}
});
@@ -278,7 +343,9 @@
}
}
layout.showCompletion(Collections.singletonList(waitText),
- null, -1, CompletionImpl.this, null, null, 0);
+ null, -1, CompletionImpl.this, null, null,
+ FALLBACK_COMPLETION_CONTROLLER,
+ CompletionController.Selection.DEFAULT);
pleaseWaitDisplayed = true;
if (!politeWaitText) {
long when = System.currentTimeMillis() - PLEASE_WAIT_TIMEOUT;
@@ -328,7 +395,7 @@
CompletionSettings.getInstance(getActiveComponent()).completionAutoPopup()) {
autoModEndOffset = modEndOffset;
if (completionResultNull)
- showCompletion(false, false, true, CompletionProvider.COMPLETION_QUERY_TYPE);
+ showCompletion(false, false, true, type & (CompletionProvider.COMPLETION_QUERY_MASK | CompletionProvider.USER_QUERY_MASK));
}
boolean tooltipResultNull;
@@ -497,45 +564,62 @@
}
private void initActiveProviders(JTextComponent component) {
- activeProviders = (component != null)
- ? getCompletionProvidersForComponent(component, true)
+ activeProviders = initActiveProviders(CompletionProvider.class, component);
+ // currently only one async warm up task is allowed at once
+ activeControllerProviders = null;
+ }
+
+ private T[] initActiveProviders(Class clazz, JTextComponent component) {
+ T[] providers = (component != null)
+ ? getProvidersForComponent(clazz, component, true)
: null;
+
if (LOG.isLoggable(Level.FINE)) {
- StringBuffer sb = new StringBuffer("Completion PROVIDERS:\n"); // NOI18N
- if (activeProviders != null) {
- for (int i = 0; i < activeProviders.length; i++) {
+ StringBuilder sb = new StringBuilder(clazz.getName() + " PROVIDERS:\n"); // NOI18N
+ if (providers != null) {
+ for (int i = 0; i < providers.length; i++) {
sb.append("providers["); // NOI18N
sb.append(i);
sb.append("]: "); // NOI18N
- sb.append(activeProviders[i].getClass());
+ sb.append(providers[i].getClass());
sb.append('\n');
}
}
LOG.fine(sb.toString());
}
+
+ return providers;
}
private boolean ensureActiveProviders() {
- if (activeProviders != null)
- return true;
+ activeProviders = ensureActiveProviders(CompletionProvider.class, activeProviders);
+ activeControllerProviders = ensureActiveProviders(CompletionControllerProvider.class, activeControllerProviders);
+ // allow activeControllerProviders to be null since we have a
+ // DefaultCompletionControllerProvider to fall back on.
+ return activeProviders != null;
+ }
+
+ private T[] ensureActiveProviders(Class clazz, T[] providers) {
+ if (providers != null)
+ return providers;
JTextComponent component = getActiveComponent();
- activeProviders = (component != null)
- ? getCompletionProvidersForComponent(component, false)
+ providers = (component != null)
+ ? getProvidersForComponent(clazz, component, false)
: null;
if (LOG.isLoggable(Level.FINE)) {
- StringBuffer sb = new StringBuffer("Completion PROVIDERS:\n"); // NOI18N
- if (activeProviders != null) {
- for (int i = 0; i < activeProviders.length; i++) {
+ StringBuilder sb = new StringBuilder(clazz.getName() + " PROVIDERS:\n"); // NOI18N
+ if (providers != null) {
+ for (int i = 0; i < providers.length; i++) {
sb.append("providers["); // NOI18N
sb.append(i);
sb.append("]: "); // NOI18N
- sb.append(activeProviders[i].getClass());
+ sb.append(providers[i].getClass());
sb.append('\n');
}
}
LOG.fine(sb.toString());
}
- return activeProviders != null;
+ return providers;
}
private void restartCompletionAutoPopupTimer() {
@@ -553,8 +637,8 @@
docAutoPopupTimer.setInitialDelay(docDelay);
docAutoPopupTimer.restart();
}
-
- private CompletionProvider[] getCompletionProvidersForComponent(JTextComponent component, boolean asyncWarmUp) {
+
+ private T[] getProvidersForComponent(final Class clazz, JTextComponent component, boolean asyncWarmUp) {
assert (SwingUtilities.isEventDispatchThread());
if (component == null)
@@ -569,15 +653,26 @@
BaseKit kit = Utilities.getKit(component);
if (kit == null) {
- return new CompletionProvider[0];
+ @SuppressWarnings("unchecked")
+ T[] result = (T[])Array.newInstance(clazz, 0);
+ return result;
}
mimeType = kit.getContentType();
}
- if (providersCache.containsKey(mimeType))
- return providersCache.get(mimeType);
+ HashMap, Object[]> providers = providersCache.get(mimeType);
+ if (providers == null) {
+ providers = new HashMap, Object[]>();
+ providersCache.put(mimeType, providers);
+ }
+ if (providers.containsKey(clazz)) {
+ @SuppressWarnings("unchecked")
+ T[] result = (T[])providers.get(clazz);
+ return result;
+ }
+
if (asyncWarmUpTask != null) {
if (asyncWarmUp && mimeType != null && mimeType.equals(asyncWarmUpMimeType))
return null;
@@ -587,24 +682,27 @@
asyncWarmUpTask = null;
asyncWarmUpMimeType = null;
}
+
final Lookup lookup = MimeLookup.getLookup(MimePath.get(mimeType));
if (asyncWarmUp) {
asyncWarmUpMimeType = mimeType;
asyncWarmUpTask = RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
- lookup.lookupAll(CompletionProvider.class);
+ lookup.lookupAll(clazz);
}
});
return null;
}
- Collection extends CompletionProvider> col = lookup.lookupAll(CompletionProvider.class);
+
+ Collection extends T> col = lookup.lookupAll(clazz);
int size = col.size();
- CompletionProvider[] ret = size == 0 ? null : col.toArray(new CompletionProvider[size]);
- providersCache.put(mimeType, ret);
+ @SuppressWarnings("unchecked")
+ T[] ret = size == 0 ? null : col.toArray((T[])Array.newInstance(clazz, size));
+ providers.put(clazz, ret);
return ret;
}
-
+
private void dispatchKeyEvent(KeyEvent e) {
if (e == null)
return;
@@ -624,21 +722,22 @@
}
}
if (layout.isCompletionVisible()) {
- CompletionItem item = layout.getSelectedCompletionItem();
- if (item != null) {
+ SelectedCompletionItem item = layout.getSelectedCompletionItem();
+ if (item != null && completionResult != null) {
sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
try {
if (compEditable && !guardedPos) {
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT"); // NOI18N
- r.setParameters(new Object[] {e.getKeyChar(), layout.getSelectedIndex(), item.getClass().getSimpleName()});
- item.processKeyEvent(e);
+ r.setParameters(new Object[] {e.getKeyChar(), layout.getSelectedIndex(), item.getItem().getClass().getSimpleName()});
+ completionResult.getController().processKeyEvent(e, item.getItem(), item.isSelected());
if (e.isConsumed()) {
uilog(r);
return;
}
}
- // Call default action if ENTER was pressed
- if (e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED) {
+ // Call default action if ENTER was pressed and the item is selected
+ // TODO: move this functionality to the CompletionController
+ if (item.isSelected() && e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED) {
e.consume();
if (guardedPos) {
Toolkit.getDefaultToolkit().beep();
@@ -648,8 +747,8 @@
consumeIdentifier();
}
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT_DEFAULT"); // NOI18N
- r.setParameters(new Object[]{'\n', layout.getSelectedIndex(), item.getClass().getSimpleName()});
- item.defaultAction(getActiveComponent());
+ r.setParameters(new Object[]{'\n', layout.getSelectedIndex(), item.getItem().getClass().getSimpleName()});
+ completionResult.getController().defaultAction(item.getItem(), item.isSelected());
uilog(r);
}
return;
@@ -662,6 +761,7 @@
|| e.getKeyCode() == KeyEvent.VK_HOME || e.getKeyCode() == KeyEvent.VK_END) {
hideCompletion(false);
}
+ // TODO: move this functionality to the CompletionController
if (e.getKeyCode() == KeyEvent.VK_TAB && doc.getProperty(CT_HANDLER_DOC_PROPERTY) == null) {
e.consume();
if (guardedPos) {
@@ -716,8 +816,12 @@
}
} else {
completionCancel();
- if (explicitQuery)
- layout.showCompletion(Collections.singletonList(NO_SUGGESTIONS), null, -1, CompletionImpl.this, null, null, 0);
+ if (explicitQuery) {
+ layout.showCompletion(Collections.singletonList(NO_SUGGESTIONS),
+ null, -1, CompletionImpl.this, null, null,
+ FALLBACK_COMPLETION_CONTROLLER,
+ CompletionController.Selection.DEFAULT);
+ }
pleaseWaitDisplayed = false;
stopProfiling();
}
@@ -858,9 +962,9 @@
return;
}
}
- CompletionItem item = layout.getSelectedCompletionItem();
+ SelectedCompletionItem item = layout.getSelectedCompletionItem();
if (item != null)
- item.defaultAction(c);
+ localCompletionResult.getController().defaultAction(item.getItem(), item.isSelected());
}
}
@@ -949,7 +1053,7 @@
final ArrayList sortedResultItems = new ArrayList(size = resultItems.size());
if (size > 0) {
- Collections.sort(resultItems, CompletionItemComparator.get(getSortType()));
+ result.getController().sortItems(resultItems, getSortType());
int cnt = 0;
for(int i = 0; i < size; i++) {
CompletionItem item = resultItems.get(i);
@@ -968,11 +1072,11 @@
final boolean noSuggestions = sortedResultItems.size() == 0;
if (noSuggestions) {
- if (hasAdditionalItems && qType == CompletionProvider.COMPLETION_QUERY_TYPE) {
+ if (hasAdditionalItems && (qType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) != CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
showCompletion(this.explicitQuery, this.refreshedQuery, false, CompletionProvider.COMPLETION_ALL_QUERY_TYPE);
return;
}
- if (!explicitQuery) {
+ if (!explicitQuery) {
hideCompletion(false);
return;
}
@@ -992,29 +1096,37 @@
Document doc = c.getDocument();
CompletionSettings cs = CompletionSettings.getInstance(c);
int caretOffset = c.getSelectionStart();
- // completionResults = null;
- if (sortedResultItems.size() == 1 && !refreshedQuery && explicitQuery
+
+ CompletionController.Selection selection = result.getController().getSelection(sortedResultItems);
+ // the CompletionController should be returning a valid selection
+ assert selection != null
+ && (sortedResultItems.isEmpty()
+ || selection.getIndex() >= 0 && selection.getIndex() < sortedResultItems.size());
+ if (selection == null || selection.getIndex() < 0 || selection.getIndex() > sortedResultItems.size()) {
+ selection = CompletionController.Selection.DEFAULT;
+ }
+
+ if (selection.isUnique() && !refreshedQuery && explicitQuery
&& cs.completionInstantSubstitution()
&& c.isEditable() && !(doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(caretOffset))) {
+
+ sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
try {
- int[] block = Utilities.getIdentifierBlock(c, caretOffset);
- if (block == null || block[1] == caretOffset) { // NOI18N
- CompletionItem item = sortedResultItems.get(0);
- sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
- try {
- if (item.instantSubstitution(c))
- return;
- } finally {
- sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
- }
- }
- } catch (BadLocationException ex) {
+ if (result.getController().instantSubstitution(sortedResultItems.get(selection.getIndex())))
+ return;
+ } finally {
+ sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
}
}
- int selectedIndex = getCompletionPreSelectionIndex(sortedResultItems);
c.putClientProperty("completion-visible", Boolean.TRUE);
- layout.showCompletion(noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems, displayTitle, displayAnchorOffset, CompletionImpl.this, displayAdditionalItems ? hasAdditionalItemsText.toString() : null, displayAdditionalItems ? completionShortcut : null, selectedIndex);
+ layout.showCompletion(
+ noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems,
+ displayTitle, displayAnchorOffset, CompletionImpl.this,
+ displayAdditionalItems ? hasAdditionalItemsText.toString() : null,
+ displayAdditionalItems ? completionShortcut : null,
+ result.getController(),
+ selection);
pleaseWaitDisplayed = false;
stopProfiling();
@@ -1032,32 +1144,6 @@
};
runInAWT(requestShowRunnable);
}
-
- private int getCompletionPreSelectionIndex(List items) {
- String prefix = null;
- if(getActiveDocument() instanceof BaseDocument) {
- BaseDocument doc = (BaseDocument)getActiveDocument();
- int caretOffset = getActiveComponent().getSelectionStart();
- try {
- int[] block = Utilities.getIdentifierBlock(doc, caretOffset);
- if (block != null) {
- block[1] = caretOffset;
- prefix = doc.getText(block);
- }
- } catch (BadLocationException ble) {
- }
- }
- if (prefix != null && prefix.length() > 0) {
- int idx = 0;
- for (CompletionItem item : items) {
- CharSequence text = item.getInsertPrefix();
- if (text != null && text.toString().startsWith(prefix))
- return idx;
- idx++;
- }
- }
- return 0;
- }
/**
* May be called from any thread. The UI changes will be rescheduled into AWT.
@@ -1148,10 +1234,10 @@
List documentationResultSets = docResult.getResultSets();
CompletionTask docTask;
- CompletionItem selectedItem = layout.getSelectedCompletionItem();
+ SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem();
if (selectedItem != null) {
- lastSelectedItem = new WeakReference(selectedItem);
- docTask = selectedItem.createDocumentationTask();
+ lastSelectedItem = new WeakReference(selectedItem.getItem());
+ docTask = selectedItem.getItem().createDocumentationTask();
if (docTask != null) { // attempt the documentation for selected item
CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
this, newDocumentationResult, docTask, CompletionProvider.DOCUMENTATION_QUERY_TYPE);
@@ -1270,8 +1356,8 @@
List toolTipResultSets = newToolTipResult.getResultSets();
CompletionTask toolTipTask;
- CompletionItem selectedItem = layout.getSelectedCompletionItem();
- if (selectedItem != null && (toolTipTask = selectedItem.createToolTipTask()) != null) {
+ SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem();
+ if (selectedItem != null && (toolTipTask = selectedItem.getItem().createToolTipTask()) != null) {
CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
this, newToolTipResult, toolTipTask, CompletionProvider.TOOLTIP_QUERY_TYPE);
toolTipResultSets.add(resultSet);
@@ -1441,7 +1527,7 @@
void finishNotify(CompletionResultSetImpl finishedResult) {
Result localResult;
boolean finished = false;
- switch (finishedResult.getQueryType()) {
+ switch (finishedResult.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) {
case CompletionProvider.COMPLETION_QUERY_TYPE:
case CompletionProvider.COMPLETION_ALL_QUERY_TYPE:
synchronized (this) {
@@ -1507,7 +1593,7 @@
private static CompletionResultSetImpl findFirstValidResult(List resultSets) {
for (int i = 0; i < resultSets.size(); i++) {
CompletionResultSetImpl result = resultSets.get(i);
- switch (result.getQueryType()) {
+ switch (result.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) {
case CompletionProvider.DOCUMENTATION_QUERY_TYPE:
if (result.getDocumentation() != null) {
return result;
@@ -1692,6 +1778,8 @@
private boolean invoked;
private boolean cancelled;
private boolean beforeQuery = true;
+
+ private CompletionController controller;
Result(int resultSetsSize) {
resultSets = new ArrayList(resultSetsSize);
@@ -1706,6 +1794,37 @@
return resultSets;
}
+ CompletionController getController() {
+ synchronized (resultSets) {
+ if (controller == null) {
+ if (resultSets.isEmpty()) {
+ return FALLBACK_COMPLETION_CONTROLLER;
+ }
+
+ JTextComponent component = getActiveComponent();
+ CompletionTask task = resultSets.get(0).getTask();
+ int queryType = resultSets.get(0).getQueryType();
+ CompletionControllerProvider[] providers = activeControllerProviders;
+ if (providers != null) {
+ for (CompletionControllerProvider provider : providers) {
+ controller = provider.createController(component, task, queryType);
+ if (controller != null) {
+ break;
+ }
+ }
+ }
+
+ if (controller == null) {
+ CompletionControllerProvider provider =
+ DefaultCompletionControllerProvider.INSTANCE;
+ controller = provider.createController(component, task, queryType);
+ }
+ }
+
+ return controller;
+ }
+ }
+
/**
* Cancel the resultSets.
*
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionItemComparator.java Sat Feb 25 17:26:54 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
- * Microsystems, Inc. All Rights Reserved.
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- */
-
-package org.netbeans.modules.editor.completion;
-
-import java.util.Comparator;
-import org.netbeans.spi.editor.completion.CompletionItem;
-import org.netbeans.spi.editor.completion.CompletionResultSet;
-
-/**
- * Comparator for completion items either by sort priority or by sort text.
- *
- * @author Dusan Balek, Miloslav Metelka
- */
-
-public class CompletionItemComparator implements Comparator {
-
- public static final Comparator BY_PRIORITY = new CompletionItemComparator(true);
-
- public static final Comparator ALPHABETICAL = new CompletionItemComparator(false);
-
- private final boolean byPriority;
-
- private CompletionItemComparator(boolean byPriority) {
- this.byPriority = byPriority;
- }
-
- public static final Comparator get(int sortType) {
- if (sortType == CompletionResultSet.PRIORITY_SORT_TYPE)
- return BY_PRIORITY;
- if (sortType == CompletionResultSet.TEXT_SORT_TYPE)
- return ALPHABETICAL;
- throw new IllegalArgumentException();
- }
-
- public int compare(CompletionItem i1, CompletionItem i2) {
- if (i1 == i2)
- return 0;
- if (byPriority) {
- int importanceDiff = i1.getSortPriority() - i2.getSortPriority();
- if (importanceDiff != 0)
- return importanceDiff;
- int alphabeticalDiff = compareText(i1.getSortText(), i2.getSortText());
- return alphabeticalDiff;
- } else {
- int alphabeticalDiff = compareText(i1.getSortText(), i2.getSortText());
- if (alphabeticalDiff != 0)
- return alphabeticalDiff;
- int importanceDiff = i1.getSortPriority() - i2.getSortPriority();
- return importanceDiff;
- }
- }
-
- private static int compareText(CharSequence text1, CharSequence text2) {
- if (text1 == null)
- text1 = ""; //NOI18N
- if (text2 == null)
- text2 = ""; //NOI18N
- int len = Math.min(text1.length(), text2.length());
- for (int i = 0; i < len; i++) {
- char ch1 = text1.charAt(i);
- char ch2 = text2.charAt(i);
- if (ch1 != ch2) {
- return ch1 - ch2;
- }
- }
- return text1.length() - text2.length();
- }
-
-}
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionJList.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionJList.java Sat Feb 25 13:00:55 2012 -0600
@@ -53,8 +53,10 @@
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.text.JTextComponent;
+import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.editor.LocaleSupport;
+import org.netbeans.spi.editor.completion.CompletionController;
import org.netbeans.spi.editor.completion.CompletionItem;
import org.netbeans.spi.editor.completion.LazyCompletionItem;
@@ -75,6 +77,10 @@
private int maxVisibleRowCount;
private JTextComponent editorComponent;
private int smartIndex;
+ /** The current completion controller. */
+ private CompletionController controller;
+ /** true
if the best match is selected, otherwise false
. */
+ private boolean isSelected;
public CompletionJList(int maxVisibleRowCount, MouseListener mouseListener, JTextComponent editorComponent) {
this.maxVisibleRowCount = maxVisibleRowCount;
@@ -91,28 +97,26 @@
setCellRenderer(new ListCellRenderer() {
private ListCellRenderer defaultRenderer = new DefaultListCellRenderer();
- public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ @Override
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isBestMatch, boolean cellHasFocus) {
if( value instanceof CompletionItem ) {
CompletionItem item = (CompletionItem)value;
renderComponent.setItem(item);
- renderComponent.setSelected(isSelected);
+ renderComponent.setSelected(isBestMatch, isBestMatch && CompletionJList.this.isSelected);
renderComponent.setSeparator(smartIndex > 0 && smartIndex == index);
- Color bgColor;
- Color fgColor;
- if (isSelected) {
- bgColor = list.getSelectionBackground();
- fgColor = list.getSelectionForeground();
- } else { // not selected
- bgColor = list.getBackground();
- if ((index % 2) == 0) { // every second item slightly different
- bgColor = new Color(
- Math.abs(bgColor.getRed() - DARKER_COLOR_COMPONENT),
- Math.abs(bgColor.getGreen() - DARKER_COLOR_COMPONENT),
- Math.abs(bgColor.getBlue() - DARKER_COLOR_COMPONENT)
- );
- }
- fgColor = list.getForeground();
+ Color bgColor = list.getBackground();
+ Color bgSelectedColor = list.getSelectionBackground();
+ Color fgColor = list.getForeground();
+ Color fgSelectedColor = list.getSelectionForeground();
+ if ((index % 2) == 0) { // every second item slightly different
+ bgColor = new Color(
+ Math.abs(bgColor.getRed() - DARKER_COLOR_COMPONENT),
+ Math.abs(bgColor.getGreen() - DARKER_COLOR_COMPONENT),
+ Math.abs(bgColor.getBlue() - DARKER_COLOR_COMPONENT)
+ );
}
+
+ renderComponent.setColors(fgColor, bgColor, fgSelectedColor, bgSelectedColor);
// quick check Component.setBackground() always fires change
if (renderComponent.getBackground() != bgColor) {
renderComponent.setBackground(bgColor);
@@ -123,7 +127,7 @@
return renderComponent;
} else {
- return defaultRenderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus);
+ return defaultRenderer.getListCellRendererComponent( list, value, index, isBestMatch, cellHasFocus);
}
}
});
@@ -148,8 +152,9 @@
}
}
- void setData(List data) {
+ void setData(List data, @NonNull CompletionController controller) {
smartIndex = -1;
+ this.controller = controller;
if (data != null) {
int itemCount = data.size();
ListCellRenderer renderer = getCellRenderer();
@@ -179,7 +184,7 @@
setModel(lm);
if (itemCount > 0) {
- setSelectedIndex(0);
+ setSelection(0, false);
}
int visibleRowCount = Math.min(itemCount, maxVisibleRowCount);
setVisibleRowCount(visibleRowCount);
@@ -214,6 +219,19 @@
updateAccessible();
}
}
+
+ public @NonNull CompletionController.Selection getSelection() {
+ return new CompletionController.Selection(getSelectedIndex(), isSelected);
+ }
+
+ public void setSelection(@NonNull CompletionController.Selection selection) {
+ setSelection(selection.getIndex(), selection.isSelected());
+ }
+
+ public void setSelection(int index, boolean isSelected) {
+ this.isSelected = isSelected;
+ setSelectedIndex(index);
+ }
private JLabel accessibleLabel;
private JLabel accessibleFakeLabel;
@@ -241,7 +259,7 @@
int idx = (getSelectedIndex() - 1 + size) % size;
while(idx > 0 && getModel().getElementAt(idx) == null)
idx--;
- setSelectedIndex(idx);
+ setSelection(idx, true);
ensureIndexIsVisible(idx);
}
}
@@ -254,7 +272,7 @@
idx++;
if (idx == size)
idx = 0;
- setSelectedIndex(idx);
+ setSelection(idx, true);
ensureIndexIsVisible(idx);
}
}
@@ -265,7 +283,7 @@
int idx = Math.max(getSelectedIndex() - pageSize, 0);
while(idx > 0 && getModel().getElementAt(idx) == null)
idx--;
- setSelectedIndex(idx);
+ setSelection(idx, true);
ensureIndexIsVisible(idx);
}
}
@@ -282,14 +300,14 @@
while(idx > 0 && getModel().getElementAt(idx) == null)
idx--;
}
- setSelectedIndex(idx);
+ setSelection(idx, true);
ensureIndexIsVisible(idx);
}
}
public void begin() {
if (getModel().getSize() > 0) {
- setSelectedIndex(0);
+ setSelection(0, true);
ensureIndexIsVisible(0);
}
}
@@ -300,7 +318,7 @@
int idx = size - 1;
while(idx > 0 && getModel().getElementAt(idx) == null)
idx--;
- setSelectedIndex(idx);
+ setSelection(idx, true);
ensureIndexIsVisible(idx);
}
}
@@ -323,18 +341,25 @@
}
private final class RenderComponent extends JComponent {
-
+
private CompletionItem item;
- private boolean selected;
+ private boolean isBestMatch;
+ private boolean isSelected;
private boolean separator;
+
+ private Color fgColor;
+ private Color bgColor;
+ private Color fgSelectedColor;
+ private Color bgSelectedColor;
void setItem(CompletionItem item) {
this.item = item;
}
- void setSelected(boolean selected) {
- this.selected = selected;
+ void setSelected(boolean isBestMatch, boolean isSelected) {
+ this.isBestMatch = isBestMatch;
+ this.isSelected = isSelected;
}
void setSeparator(boolean separator) {
@@ -349,18 +374,12 @@
// of the widest item).
// Therefore the item's render width is taken from the viewport's width.
int itemRenderWidth = ((JViewport)CompletionJList.this.getParent()).getWidth();
- Color bgColor = getBackground();
- Color fgColor = getForeground();
int height = getHeight();
- // Clear the background
- g.setColor(bgColor);
- g.fillRect(0, 0, itemRenderWidth, height);
- g.setColor(fgColor);
-
// Render the item
- item.render(g, CompletionJList.this.getFont(), getForeground(), bgColor,
- itemRenderWidth, getHeight(), selected);
+ controller.render(g, CompletionJList.this.getFont(), fgColor, bgColor,
+ fgSelectedColor, bgSelectedColor, itemRenderWidth, getHeight(),
+ item, isBestMatch, isSelected);
if (separator) {
g.setColor(Color.gray);
@@ -368,7 +387,7 @@
g.setColor(fgColor);
}
}
-
+
public @Override Dimension getPreferredSize() {
if (cellPreferredSizeGraphics == null) {
// CompletionJList.this.getGraphics() is null
@@ -381,6 +400,13 @@
fixedItemHeight);
}
+ private void setColors(Color fgColor, Color bgColor, Color fgSelectedColor, Color bgSelectedColor) {
+ this.fgColor = fgColor;
+ this.bgColor = bgColor;
+ this.fgSelectedColor = fgSelectedColor;
+ this.bgSelectedColor = bgSelectedColor;
+ }
+
}
}
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java Sat Feb 25 13:00:55 2012 -0600
@@ -71,9 +71,10 @@
import javax.swing.event.ListSelectionListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.editor.GuardedDocument;
+import org.netbeans.spi.editor.completion.CompletionController;
import org.netbeans.spi.editor.completion.CompletionDocumentation;
-import org.netbeans.spi.editor.completion.CompletionItem;
import org.openide.text.CloneableEditorSupport;
import org.openide.util.NbBundle;
@@ -138,8 +139,10 @@
}
public void showCompletion(List data, String title, int anchorOffset,
- ListSelectionListener listSelectionListener, String additionalItemsText, String shortcutHint, int selectedIndex) {
- completionPopup.show(data, title, anchorOffset, listSelectionListener, additionalItemsText, shortcutHint, selectedIndex);
+ ListSelectionListener listSelectionListener, String additionalItemsText,
+ String shortcutHint, CompletionController controller,
+ CompletionController.Selection selection) {
+ completionPopup.show(data, title, anchorOffset, listSelectionListener, additionalItemsText, shortcutHint, controller, selection);
if (!visiblePopups.contains(completionPopup))
visiblePopups.push(completionPopup);
}
@@ -159,7 +162,7 @@
return completionPopup.isVisible();
}
- public CompletionItem getSelectedCompletionItem() {
+ public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
return completionPopup.getSelectedCompletionItem();
}
@@ -305,7 +308,9 @@
private CompletionScrollPane completionScrollPane;
public void show(List data, String title, int anchorOffset,
- ListSelectionListener listSelectionListener, String additionalItemsText, String shortcutHint, int selectedIndex) {
+ ListSelectionListener listSelectionListener, String additionalItemsText,
+ String shortcutHint, final CompletionController controller,
+ CompletionController.Selection selection) {
JTextComponent editorComponent = getEditorComponent();
if (editorComponent == null) {
@@ -330,7 +335,7 @@
JTextComponent c = getEditorComponent();
if (SwingUtilities.isLeftMouseButton(evt)) {
if (c != null && evt.getClickCount() == 2 ) {
- CompletionItem selectedItem
+ SelectedCompletionItem selectedItem
= completionScrollPane.getSelectedCompletionItem();
if (selectedItem != null) {
Document doc = c.getDocument();
@@ -342,7 +347,7 @@
CompletionImpl.uilog(r);
CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
try {
- selectedItem.defaultAction(c);
+ controller.defaultAction(selectedItem.getItem(), selectedItem.isSelected());
} finally {
CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
}
@@ -372,7 +377,7 @@
}
// Set the new data
getPreferredSize();
- completionScrollPane.setData(data, title, selectedIndex);
+ completionScrollPane.setData(data, title, controller, selection);
setAnchorOffset(anchorOffset);
Dimension prefSize = getPreferredSize();
@@ -395,7 +400,7 @@
} // otherwise present popup size will be retained
}
- public CompletionItem getSelectedCompletionItem() {
+ public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
return isVisible() ? completionScrollPane.getSelectedCompletionItem() : null;
}
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionResultSetImpl.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionResultSetImpl.java Sat Feb 25 13:00:55 2012 -0600
@@ -213,7 +213,7 @@
public synchronized void setHasAdditionalItems(boolean value) {
checkNotFinished();
- if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
+ if ((queryType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
return;
}
this.hasAdditionalItems = value;
@@ -225,7 +225,7 @@
public synchronized void setHasAdditionalItemsText(String text) {
checkNotFinished();
- if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
+ if ((queryType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
return;
}
this.hasAdditionalItemsText = text;
@@ -237,7 +237,7 @@
public synchronized void setDocumentation(CompletionDocumentation documentation) {
checkNotFinished();
- if (!active || queryType != CompletionProvider.DOCUMENTATION_QUERY_TYPE) {
+ if (!active || (queryType & CompletionProvider.DOCUMENTATION_QUERY_TYPE) != CompletionProvider.DOCUMENTATION_QUERY_TYPE) {
return;
}
this.documentation = documentation;
@@ -253,7 +253,7 @@
public synchronized void setToolTip(JToolTip toolTip) {
checkNotFinished();
- if (!active || queryType != CompletionProvider.TOOLTIP_QUERY_TYPE) {
+ if (!active || (queryType & CompletionProvider.TOOLTIP_QUERY_TYPE) != CompletionProvider.TOOLTIP_QUERY_TYPE) {
return;
}
this.toolTip = toolTip;
--- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionScrollPane.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionScrollPane.java Sat Feb 25 13:00:55 2012 -0600
@@ -65,8 +65,10 @@
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.EditorKit;
+import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.editor.BaseKit;
import org.netbeans.editor.ext.ExtKit;
+import org.netbeans.spi.editor.completion.CompletionController;
import org.netbeans.spi.editor.completion.CompletionItem;
/**
@@ -122,11 +124,14 @@
installKeybindings(editorComponent);
}
- public void setData(List data, String title, int selectedIndex) {
+ public void setData(List data,
+ String title,
+ CompletionController controller,
+ CompletionController.Selection selection) {
dataObj = data;
- view.setData(data);
- view.setSelectedIndex(selectedIndex);
- Rectangle r = view.getCellBounds(selectedIndex, selectedIndex);
+ view.setData(data, controller);
+ view.setSelection(selection);
+ Rectangle r = view.getCellBounds(selection.getIndex(), selection.getIndex());
if (r != null)
view.scrollRectToVisible(r);
setTitle(title);
@@ -139,9 +144,14 @@
setViewportView(getViewport().getView());
}
- public CompletionItem getSelectedCompletionItem() {
+ public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
Object ret = view.getSelectedValue();
- return ret instanceof CompletionItem ? (CompletionItem) ret : null;
+ if (ret instanceof CompletionItem) {
+ boolean isSelected = view.getSelection().isSelected();
+ return new SelectedCompletionItem((CompletionItem)ret, isSelected);
+ }
+
+ return null;
}
public int getSelectedIndex() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.editor.completion;
+
+import javax.swing.text.JTextComponent;
+import org.netbeans.spi.editor.completion.BaseCompletionController;
+import org.netbeans.spi.editor.completion.CompletionController;
+import org.netbeans.spi.editor.completion.CompletionControllerProvider;
+import org.netbeans.spi.editor.completion.CompletionTask;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public class DefaultCompletionControllerProvider implements CompletionControllerProvider {
+ public static final DefaultCompletionControllerProvider INSTANCE = new DefaultCompletionControllerProvider();
+
+ @Override
+ public CompletionController createController(JTextComponent component, CompletionTask task, int queryType) {
+ return new BaseCompletionController(component, queryType);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.editor.completion;
+
+import org.netbeans.spi.editor.completion.CompletionItem;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public final class SelectedCompletionItem {
+ private final CompletionItem item;
+ private final boolean selected;
+
+ public SelectedCompletionItem(CompletionItem item, boolean selected) {
+ this.item = item;
+ this.selected = selected;
+ }
+
+ public CompletionItem getItem() {
+ return item;
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,225 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.editor.completion;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.KeyEvent;
+import java.util.Collections;
+import java.util.List;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.editor.Utilities;
+import org.openide.util.Parameters;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public class BaseCompletionController implements CompletionController {
+ private final JTextComponent component;
+ private final int queryType;
+
+ /**
+ *
+ * @param component The active component.
+ * @param queryType The query type.
+ *
+ * @throws NullPointerException if the parameter value is null
.
+ */
+ public BaseCompletionController(@NonNull JTextComponent component,
+ int queryType) {
+ Parameters.notNull("component", component);
+ this.component = component;
+ this.queryType = queryType;
+ }
+
+
+ /**
+ * Gets the active {@link JTextComponent}.
+ *
+ * @return The active component.
+ */
+ public @NonNull JTextComponent getComponent() {
+ return component;
+ }
+
+ /**
+ * Gets the active {@link Document}.
+ *
+ * @return The active document.
+ */
+ public Document getDocument() {
+ return getComponent().getDocument();
+ }
+
+ @Override
+ public void sortItems(List extends CompletionItem> items, int sortType) {
+ Collections.sort(items, CompletionItemComparator.get(sortType));
+ }
+
+ @Override
+ public Selection getSelection(List extends CompletionItem> items) {
+ String prefix = getCompletionPrefix();
+ if (prefix != null && prefix.length() > 0) {
+ for (int idx = 0; idx < items.size(); idx++) {
+ CompletionItem item = items.get(idx);
+ CharSequence text = item.getInsertPrefix();
+ if (text != null && text.toString().startsWith(prefix)) {
+ boolean selected = isSelected(items, prefix, idx);
+ boolean unique = isUnique(items, prefix, idx);
+ return new Selection(idx, selected, unique);
+ }
+ }
+ }
+
+ /* This follows existing behavior, which is slightly different from
+ * Selection.DEFAULT because this method marks the item as selected.
+ */
+ return new Selection(0);
+ }
+
+ @Override
+ public void defaultAction(CompletionItem bestMatch, boolean isSelected) {
+ if (isSelected) {
+ bestMatch.defaultAction(component);
+ }
+ }
+
+ @Override
+ public void processKeyEvent(KeyEvent evt, CompletionItem bestMatch, boolean isSelected) {
+ bestMatch.processKeyEvent(evt);
+ }
+
+ @Override
+ public void render(Graphics g, Font defaultFont, Color foregroundColor,
+ Color backgroundColor, Color selectedForegroundColor,
+ Color selectedBackgroundColor, int width, int height, CompletionItem item, boolean isBestMatch, boolean isSelected) {
+ if (isBestMatch) {
+ // Clear the background
+ g.setColor(selectedBackgroundColor);
+ g.fillRect(0, 0, width, height);
+ g.setColor(selectedForegroundColor);
+ item.render(g, defaultFont, selectedForegroundColor, selectedBackgroundColor, width, height, isBestMatch);
+ } else {
+ // Clear the background
+ g.setColor(backgroundColor);
+ g.fillRect(0, 0, width, height);
+ g.setColor(foregroundColor);
+ item.render(g, defaultFont, foregroundColor, backgroundColor, width, height, isBestMatch);
+ }
+ }
+
+ @Override
+ public boolean instantSubstitution(CompletionItem uniqueMatch) {
+ return uniqueMatch.instantSubstitution(component);
+ }
+
+ /**
+ * Gets the current completion prefix. The default implementation returns the
+ * text of the current identifier (per {@link Utilities#getIdentifierBlock})
+ * up to the location of the caret.
+ *
+ * @return The completion prefix.
+ */
+ protected @CheckForNull String getCompletionPrefix() {
+ if(getDocument() instanceof BaseDocument) {
+ BaseDocument doc = (BaseDocument)getDocument();
+ int caretOffset = getComponent().getSelectionStart();
+ try {
+ int[] block = Utilities.getIdentifierBlock(doc, caretOffset);
+ if (block != null) {
+ block[1] = caretOffset;
+ return doc.getText(block);
+ }
+ } catch (BadLocationException ble) {
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ *
+ * @param items
+ * @param prefix
+ * @param index
+ *
+ * @return true
if the item is selected, otherwise false
.
+ */
+ protected boolean isSelected(@NonNull List extends CompletionItem> items,
+ @NullAllowed String prefix,
+ int index) {
+ return true;
+ }
+
+ /**
+ *
+ * @param items
+ * @param prefix
+ * @param index
+ *
+ * @return true
if the selection is unique, otherwise false
.
+ */
+ protected boolean isUnique(@NonNull List extends CompletionItem> items,
+ @NullAllowed String prefix,
+ int index) {
+ if (items.size() != 1) {
+ return false;
+ }
+
+ try {
+ int caretOffset = getComponent().getSelectionStart();
+ int[] block = Utilities.getIdentifierBlock(getComponent(),
+ getComponent().getSelectionStart());
+ return block == null || block[1] == caretOffset;
+ } catch (BadLocationException ble) {
+ return false;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,236 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.editor.completion;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.KeyEvent;
+import java.util.List;
+import org.netbeans.api.annotations.common.NonNull;
+
+/**
+ * This interface controls the sorting and selection behavior of the Code
+ * Completion drop down.
+ *
+ * @author Sam Harwell
+ */
+public interface CompletionController {
+
+ /**
+ * Sorts the specified list of CompletionItem items.
+ *
+ * @param items The list of items to sort.
+ * @param sortType The desired sort type, one of
+ * {@link CompletionResultSet#PRIORITY_SORT_TYPE} or
+ * {@link CompletionResultSet#TEXT_SORT_TYPE}.
+ */
+ void sortItems(@NonNull List extends CompletionItem> items, int sortType);
+
+ /**
+ * Gets the initial selected item from a list of CompletionItem items shown
+ * in a code completion drop down. The initial selection represents a "best
+ * match" among the available items.
+ *
+ * @param items A list of all CompletionItem items shown in the code
+ * completion drop down.
+ *
+ * @return A {@link Selection} object containing information about the
+ * initial selection.
+ */
+ @NonNull Selection getSelection(@NonNull List extends CompletionItem> items);
+
+ /**
+ * Gets invoked when user presses VK_ENTER
key
+ * or when she double-clicks on this item with the mouse cursor.
+ *
+ * This method gets invoked from AWT thread.
+ *
+ * @param bestMatch non-null completion item for which the action is invoked
+ * @param isSelected whether or not the best match is currently selected
+ */
+ void defaultAction(@NonNull CompletionItem bestMatch, boolean isSelected);
+
+ /**
+ * Process the key pressed when this completion item was selected
+ * in the completion popup window.
+ *
+ * This method gets invoked from AWT thread.
+ *
+ * @param evt non-null key event of the pressed key. It should be consumed
+ * in case the item is sensitive to the given key. The source of this
+ * event is the text component to which the corresponding action should
+ * be performed.
+ * @param bestMatch non-null completion item which is the current best match
+ * @param isSelected whether or not the best match is currently selected
+ */
+ void processKeyEvent(@NonNull KeyEvent evt, @NonNull CompletionItem bestMatch, boolean isSelected);
+
+ /**
+ * Render this item into the given graphics.
+ *
+ * @param g graphics to render the item into.
+ * @param defaultFont default font used for rendering.
+ * @param foregroundColor foreground color used for rendering.
+ * @param backgroundColor color used for background.
+ * @param selectedForegroundColor foreground color used for rendering selected items.
+ * @param selectedBackgroundColor color used for background selected items.
+ * @param width width of the area to render into.
+ * @param height height of the are to render into.
+ * @param item non-null completion item to render.
+ * @param isBestMatch true if this item is the best match.
+ * @param isSelected true if this item is selected.
+ */
+ void render(@NonNull Graphics g, @NonNull Font defaultFont, @NonNull Color foregroundColor,
+ @NonNull Color backgroundColor, @NonNull Color selectedForegroundColor,
+ @NonNull Color selectedBackgroundColor, int width, int height, @NonNull CompletionItem item,
+ boolean isBestMatch, boolean isSelected);
+
+ /**
+ * When enabled for the item the instant substitution should process the item
+ * in the same way like when the item is displayed and Enter key gets pressed
+ * by the user.
+ *
+ * Instant substitution is invoked when there would be just a single item
+ * displayed in the completion popup window.
+ *
+ * The implementation can invoke the {@link #defaultAction(JTextComponent)}
+ * if necessary.
+ *
+ * This method gets invoked from AWT thread.
+ *
+ * @param uniqueMatch non-null unique completion item to perform the instant
+ * substitution.
+ * @return true
if the instant substitution was successfully done.
+ * false
means that the instant substitution should not be done
+ * for this item and the completion item should normally be displayed.
+ */
+ boolean instantSubstitution(@NonNull CompletionItem uniqueMatch);
+
+ /**
+ * Represents an initial selected CompletionItem for code completion. This
+ * item can be seen as the best match for a given input.
+ */
+ public static final class Selection {
+ /**
+ * The default selected item. The item has index 0 and is not selected
+ * or unique.
+ */
+ public static final Selection DEFAULT = new Selection(0, false, false);
+
+ private final int index;
+ private final boolean selected;
+ private final boolean unique;
+
+ /**
+ * Initializes a Selection with the specified index. The item is selected
+ * but not unique.
+ *
+ * @param index The index of the selected CompletionItem.
+ *
+ * @throws IllegalArgumentException when the index argument is less than zero.
+ */
+ public Selection(int index) {
+ this(index, true, false);
+ }
+
+ /**
+ * Initializes a Selection with the specified index and selected state.
+ * The item is not unique.
+ *
+ * @param index The index of the selected CompletionItem.
+ * @param selected true
if the match is selected, otherwise
+ * false
.
+ *
+ * @throws IllegalArgumentException when the index argument is less than zero.
+ */
+ public Selection(int index, boolean selected) {
+ this(index, selected, false);
+ }
+
+ /**
+ * Initializes a Selection with the specified index, selected state, and
+ * uniqueness.
+ *
+ * @param index The index of the selected CompletionItem.
+ * @param selected true
if the match is selected, otherwise
+ * false
.
+ * @param unique true
if the match is unique, otherwise
+ * false
.
+ *
+ * @throws IllegalArgumentException when the index argument is less than zero.
+ */
+ public Selection(int index, boolean selected, boolean unique) {
+ if (index < 0) {
+ throw new IllegalArgumentException("The index cannot be negative."); // NOI18N
+ }
+
+ this.index = index;
+ this.selected = selected;
+ this.unique = unique;
+ }
+
+ /**
+ *
+ * @return The index of the selected CompletionItem.
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ *
+ * @return true
if the match is selected, otherwise false
.
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ *
+ * @return true
if the match is unique, otherwise false
.
+ */
+ public boolean isUnique() {
+ return unique;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+package org.netbeans.spi.editor.completion;
+
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.spi.editor.mimelookup.MimeLocation;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+@MimeLocation(subfolderName="CompletionProviders")
+public interface CompletionControllerProvider {
+
+ /**
+ * Creates a {@link CompletionController} which provides behavior for the
+ * code completion drop down.
+ *
+ * @param component The active component.
+ * @param task The completion task.
+ * @param queryType The completion query type.
+ *
+ * @return A {@link CompletionController} to provide behavior for the completion drop
+ * down, or null
if this provider does not support the specified
+ * component, task, or query type.
+ */
+ public @CheckForNull CompletionController createController(
+ @NonNull JTextComponent component,
+ @NonNull CompletionTask task,
+ int queryType);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ 81cafa2674cb Sat Feb 25 13:00:55 2012 -0600
@@ -0,0 +1,195 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.netbeans.spi.editor.completion;
+
+import java.util.Comparator;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.util.Parameters;
+
+/**
+ * Comparator for completion items either by sort priority or by sort text.
+ *
+ * @author Dusan Balek, Miloslav Metelka
+ */
+
+public class CompletionItemComparator implements Comparator {
+
+ /**
+ * A Comparator which sorts CompletionItem items by priority, then alphabetically.
+ */
+ public static final Comparator BY_PRIORITY =
+ new CompletionItemComparator(new PriorityComparator(), new TextComparator());
+
+ /**
+ * A Comparator which sorts CompletionItem items alphabetically, then by priority.
+ */
+ public static final Comparator ALPHABETICAL =
+ new CompletionItemComparator(new TextComparator(), new PriorityComparator());
+
+ private final Comparator primaryComparator;
+ private final Comparator secondaryComparator;
+
+ /**
+ * Constructs a CompletionItemComparator from the specified primary and secondary
+ * comparators.
+ *
+ * @param primaryComparator non-null primary comparator.
+ * @param secondaryComparator non-null secondary comparator.
+ */
+ public CompletionItemComparator(@NonNull Comparator primaryComparator,
+ @NonNull Comparator secondaryComparator) {
+ Parameters.notNull("primaryComparator", primaryComparator);
+ Parameters.notNull("secondaryComparator", secondaryComparator);
+ this.primaryComparator = primaryComparator;
+ this.secondaryComparator = secondaryComparator;
+ }
+
+ /**
+ * Gets a default comparator that can be used for sorting CompletionItem lists
+ * for the specified sort type.
+ *
+ * @param sortType The sort type, one of {@link CompletionResultSet#PRIORITY_SORT_TYPE}
+ * or {@link CompletionResultSet#TEXT_SORT_TYPE}.
+ *
+ * @return The Comparator to use when sorting CompletionItem items.
+ *
+ * @throws IllegalArgumentException the sortType argument is not a supported type.
+ */
+ public static Comparator get(int sortType) {
+ if (sortType == CompletionResultSet.PRIORITY_SORT_TYPE)
+ return BY_PRIORITY;
+
+ if (sortType == CompletionResultSet.TEXT_SORT_TYPE)
+ return ALPHABETICAL;
+
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public int compare(CompletionItem i1, CompletionItem i2) {
+ if (i1 == i2)
+ return 0;
+
+ int primaryDiff = primaryComparator.compare(i1, i2);
+ if (primaryDiff != 0) {
+ return primaryDiff;
+ }
+
+ return secondaryComparator.compare(i1, i2);
+ }
+
+ /**
+ * A comparator which compares CompletionItem items by priority.
+ *
+ * @see CompletionItem#getSortPriority()
+ */
+ protected static class PriorityComparator implements Comparator {
+
+ /**
+ * Initializes a PriorityComparator.
+ */
+ public PriorityComparator() {
+ }
+
+ @Override
+ public int compare(CompletionItem o1, CompletionItem o2) {
+ if (o1 == o2) {
+ return 0;
+ }
+
+ return o1.getSortPriority() - o2.getSortPriority();
+ }
+
+ }
+
+ /**
+ * A Comparator which compares CompletionItem items by text.
+ *
+ * @see CompletionItem#getSortText()
+ */
+ protected static class TextComparator implements Comparator {
+
+ /**
+ * Initializes a TextComparator.
+ */
+ public TextComparator() {
+ }
+
+ @Override
+ public int compare(CompletionItem o1, CompletionItem o2) {
+ return compareText(o1.getSortText(), o2.getSortText());
+ }
+
+ /**
+ * Compares two CharSequence objects for order.
+ *
+ * @param text1 the first text to be compared
+ * @param text2 the second text to be compared
+ * @return a negative integer, zero, or a positive integer as the
+ * first argument is less than, equal to, or greater than the
+ * second.
+ */
+ protected int compareText(CharSequence text1, CharSequence text2) {
+ if (text1 == null)
+ text1 = ""; //NOI18N
+
+ if (text2 == null)
+ text2 = ""; //NOI18N
+
+ int len = Math.min(text1.length(), text2.length());
+ for (int i = 0; i < len; i++) {
+ char ch1 = text1.charAt(i);
+ char ch2 = text2.charAt(i);
+ if (ch1 != ch2) {
+ return ch1 - ch2;
+ }
+ }
+
+ return text1.length() - text2.length();
+ }
+
+ }
+
+}
--- a/editor.completion/src/org/netbeans/spi/editor/completion/CompletionProvider.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/spi/editor/completion/CompletionProvider.java Sat Feb 25 13:00:55 2012 -0600
@@ -67,22 +67,37 @@
/**
* The int
value representing the query for a code completion.
*/
- public static final int COMPLETION_QUERY_TYPE = 1;
+ public static final int COMPLETION_QUERY_TYPE = 0x01;
/**
* The int
value representing the query for a documentation.
*/
- public static final int DOCUMENTATION_QUERY_TYPE = 2;
+ public static final int DOCUMENTATION_QUERY_TYPE = 0x02;
/**
* The int
value representing the query for a tooltip hint.
*/
- public static final int TOOLTIP_QUERY_TYPE = 4;
+ public static final int TOOLTIP_QUERY_TYPE = 0x04;
/**
* The int
value representing the query for an all code completion.
*/
- public static final int COMPLETION_ALL_QUERY_TYPE = 9;
+ public static final int COMPLETION_ALL_QUERY_TYPE = 0x11;
+
+ /**
+ * The int
mask representing the bits used for a completion query type.
+ */
+ public static final int COMPLETION_QUERY_MASK = COMPLETION_QUERY_TYPE | COMPLETION_ALL_QUERY_TYPE;
+
+ /**
+ * The int
mask of bits a user can specify to customize the query type.
+ */
+ public static final int USER_QUERY_MASK = 0xFFFF0000;
+
+ /**
+ * The int
mask of bits used by the API to specify the query type.
+ */
+ public static final int RESERVED_QUERY_MASK = ~USER_QUERY_MASK;
/**
* Creates a task that performs a query of the given type on the given component.
--- a/editor.completion/src/org/netbeans/spi/editor/completion/CompletionResultSet.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/spi/editor/completion/CompletionResultSet.java Sat Feb 25 13:00:55 2012 -0600
@@ -45,6 +45,8 @@
package org.netbeans.spi.editor.completion;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import javax.swing.JToolTip;
import org.netbeans.modules.editor.completion.CompletionResultSetImpl;
import org.netbeans.modules.editor.completion.CompletionSpiPackageAccessor;
@@ -101,19 +103,38 @@
}
/**
- * Set the document offset to which the returned completion items
- * or documentation or tooltip should be anchored.
+ * Get the document offset to which the returned completion items,
+ * documentation, or tool tip should be anchored.
*
* If there will be multiple completion providers setting this property
* for the given mime-type then only the first one
* (according to the xml-layer registration order)
* will be taken into account.
+ * @return
+ */
+ public int getAnchorOffset() {
+ return impl.getAnchorOffset();
+ }
+
+ /**
+ * Set the document offset to which the returned completion items
+ * or documentation or tooltip should be anchored.
+ *
+ * @see #getAnchorOffset()
*/
public void setAnchorOffset(int anchorOffset) {
impl.setAnchorOffset(anchorOffset);
}
/**
+ * Gets an unmodifiable list of completion items in this result set.
+ * @return
+ */
+ public List extends CompletionItem> getItems() {
+ return Collections.unmodifiableList(impl.getItems());
+ }
+
+ /**
* Add the completion item to this result set.
*
* This method can be called multiple times until
--- a/editor.completion/src/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.java Sat Feb 25 13:00:55 2012 -0600
@@ -47,6 +47,9 @@
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.spi.editor.completion.CompletionResultSet;
import org.netbeans.spi.editor.completion.CompletionTask;
import org.openide.util.RequestProcessor;
@@ -97,7 +100,7 @@
*
* It may be null to indicate that no component was provided.
*/
- public AsyncCompletionTask(AsyncCompletionQuery query, JTextComponent component) {
+ public AsyncCompletionTask(@NonNull AsyncCompletionQuery query, @NullAllowed JTextComponent component) {
assert (query != null) : "Query must be non-null";
this.query = query;
this.component = component;
@@ -110,11 +113,29 @@
*
* @param query non-null query implementation.
*/
- public AsyncCompletionTask(AsyncCompletionQuery query) {
+ public AsyncCompletionTask(@NonNull AsyncCompletionQuery query) {
this(query, null);
}
/**
+ * Gets the {@link AsyncCompletionQuery} wrapped by this task.
+ *
+ * @return The {@link AsyncCompletionQuery}.
+ */
+ public @NonNull AsyncCompletionQuery getQuery() {
+ return query;
+ }
+
+ /**
+ * Gets the active component used by this task.
+ *
+ * @return The component.
+ */
+ public @CheckForNull JTextComponent getComponent() {
+ return component;
+ }
+
+ /**
* Called by completion infrastructure in AWT thread to populate
* the given result set with data.
*/
--- a/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java Sat Feb 25 17:26:54 2012 +0100
+++ a/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java Sat Feb 25 13:00:55 2012 -0600
@@ -49,6 +49,8 @@
import java.awt.FontMetrics;
import java.awt.Graphics;
import javax.swing.ImageIcon;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.modules.editor.completion.PatchedHtmlRenderer;
/**
@@ -119,7 +121,7 @@
}
return width;
}
-
+
/**
* Render a completion item using the provided icon and left and right
* html texts.
@@ -160,30 +162,98 @@
public static void renderHtml(ImageIcon icon, String leftHtmlText, String rightHtmlText,
Graphics g, Font defaultFont, Color defaultColor,
int width, int height, boolean selected) {
+ renderHtml(icon, leftHtmlText, rightHtmlText, g, defaultFont, defaultColor, defaultColor, width, height, selected, true);
+ }
+
+ /**
+ * Render a completion item using the provided icon and left and right
+ * html texts.
+ *
+ * @param icon icon 16x16 that will be displayed on the left. It may be null
+ * which means that no icon will be displayed but the space for the icon
+ * will still be reserved (to properly align with other items
+ * that will provide an icon).
+ *
+ * @param leftHtmlText html text that will be displayed on the left side
+ * of the item's rendering area next to the icon.
+ *
+ * It may be null which indicates that no left text will be displayed.
+ *
+ * If there's not enough horizontal space in the rendering area
+ * the text will be shrinked and "..." will be displayed at the end.
+ *
+ * @param rightHtmlText html text that will be aligned to the right edge
+ * of the item's rendering area.
+ *
+ * It may be null which means that no right text will be displayed.
+ *
+ * The right text is always attempted to be fully displayed unlike
+ * the left text that may be shrinked if there's not enough rendering space
+ * in the horizontal direction.
+ *
+ * If there's not enough space even for the right text it will be shrinked
+ * and "..." will be displayed at the end of the rendered string.
+ * @param g non-null graphics through which the rendering happens.
+ * @param defaultFont non-null default font to be used for rendering.
+ * @param foregroundColor non-null default color to be used for rendering.
+ * @param selectedBackgroundColor non-null color to be used a the background
+ * for rendering selected items.
+ * @param width >=0 available width for rendering.
+ * @param height >=0 available height for rendering.
+ * @param isBestMatch whether the item being rendered is currently the best
+ * match in the completion's JList. If selected the foreground color is forced
+ * to be black for all parts of the rendered strings.
+ * @param isSelected whether the item being rendered is currently selected in
+ * the completion's JList. If true
, the foreground color is
+ * forced to the value of the foregroundColor argument for all parts of the
+ * rendered strings.
+ */
+ public static void renderHtml(@NullAllowed ImageIcon icon,
+ @NullAllowed String leftHtmlText,
+ @NullAllowed String rightHtmlText,
+ @NonNull Graphics g,
+ @NonNull Font defaultFont,
+ @NonNull Color foregroundColor,
+ @NonNull Color selectedBackgroundColor,
+ int width,
+ int height,
+ boolean isBestMatch,
+ boolean isSelected) {
if (icon != null) {
// The image of the ImageIcon should already be loaded
// so no ImageObserver should be necessary
boolean done = g.drawImage(icon.getImage(), BEFORE_ICON_GAP, (height - icon.getIconHeight()) /2, null);
assert (done);
}
+
+ if (isBestMatch && isSelected) {
+ g.setColor(foregroundColor);
+ }
+
int iconWidth = BEFORE_ICON_GAP + ICON_WIDTH + AFTER_ICON_GAP;
int rightTextX = width - AFTER_RIGHT_TEXT_GAP;
FontMetrics fm = g.getFontMetrics(defaultFont);
int textY = (height - fm.getHeight())/2 + fm.getHeight() - fm.getDescent();
if (rightHtmlText != null && rightHtmlText.length() > 0) {
int rightTextWidth = (int)PatchedHtmlRenderer.renderHTML(rightHtmlText, g, 0, 0, Integer.MAX_VALUE, 0,
- defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_CLIP, false, true);
+ defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_CLIP, false, true);
rightTextX = Math.max(iconWidth, rightTextX - rightTextWidth);
// Render right text
PatchedHtmlRenderer.renderHTML(rightHtmlText, g, rightTextX, textY, rightTextWidth, textY,
- defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_CLIP, true, selected);
+ defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_CLIP, true, isBestMatch && isSelected);
rightTextX = Math.max(iconWidth, rightTextX - BEFORE_RIGHT_TEXT_GAP);
}
// Render left text
if (leftHtmlText != null && leftHtmlText.length() > 0 && rightTextX > iconWidth) { // any space for left text?
PatchedHtmlRenderer.renderHTML(leftHtmlText, g, iconWidth, textY, rightTextX - iconWidth, textY,
- defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_TRUNCATE, true, selected);
+ defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_TRUNCATE, true, isBestMatch && isSelected);
+ }
+
+ // Render border for best match items that are not selected
+ if (isBestMatch && !isSelected) {
+ g.setColor(selectedBackgroundColor);
+ g.drawRect(0, 0, width - 1, height - 1);
}
}
--- a/java.editor/test/unit/src/org/netbeans/modules/java/editor/completion/CompletionTestBase.java Sat Feb 25 17:26:54 2012 +0100
+++ a/java.editor/test/unit/src/org/netbeans/modules/java/editor/completion/CompletionTestBase.java Sat Feb 25 13:00:55 2012 -0600
@@ -74,7 +74,7 @@
import org.netbeans.api.java.source.gen.WhitespaceIgnoringDiff;
import org.netbeans.api.lexer.Language;
import org.netbeans.junit.NbTestCase;
-import org.netbeans.modules.editor.completion.CompletionItemComparator;
+import org.netbeans.spi.editor.completion.CompletionItemComparator;
import org.netbeans.modules.editor.java.JavaCompletionProvider;
import org.netbeans.modules.editor.java.JavaKit;
import org.netbeans.modules.editor.java.Utilities;