Lines 49-54
Link Here
|
49 |
import java.beans.PropertyChangeEvent; |
49 |
import java.beans.PropertyChangeEvent; |
50 |
import java.beans.PropertyChangeListener; |
50 |
import java.beans.PropertyChangeListener; |
51 |
import java.lang.ref.WeakReference; |
51 |
import java.lang.ref.WeakReference; |
|
|
52 |
import java.lang.reflect.Array; |
52 |
import java.util.ArrayList; |
53 |
import java.util.ArrayList; |
53 |
import java.util.Collection; |
54 |
import java.util.Collection; |
54 |
import java.util.Collections; |
55 |
import java.util.Collections; |
Lines 129-134
Link Here
|
129 |
|
130 |
|
130 |
private static final int PLEASE_WAIT_TIMEOUT = 750; |
131 |
private static final int PLEASE_WAIT_TIMEOUT = 750; |
131 |
private static final int PRESCAN = 25; |
132 |
private static final int PRESCAN = 25; |
|
|
133 |
|
134 |
/** |
135 |
* A default {@link CompletionController} which is used for the "Please wait..." |
136 |
* and "No suggestions" completion results. |
137 |
*/ |
138 |
private final CompletionController FALLBACK_COMPLETION_CONTROLLER = |
139 |
new CompletionController() { |
140 |
@Override |
141 |
public void sortItems(List<? extends CompletionItem> items, int sortType) { |
142 |
assert items.size() == 1; |
143 |
} |
144 |
|
145 |
@Override |
146 |
public Selection getSelection(List<? extends CompletionItem> items) { |
147 |
assert items.size() == 1; |
148 |
return Selection.DEFAULT; |
149 |
} |
150 |
|
151 |
@Override |
152 |
public void defaultAction(CompletionItem bestMatch, boolean isSelected) { |
153 |
if (isSelected) { |
154 |
bestMatch.defaultAction(getActiveComponent()); |
155 |
} |
156 |
} |
157 |
|
158 |
@Override |
159 |
public void processKeyEvent(KeyEvent evt, CompletionItem bestMatch, |
160 |
boolean isSelected) { |
161 |
bestMatch.processKeyEvent(evt); |
162 |
} |
163 |
|
164 |
@Override |
165 |
public void render(Graphics g, Font defaultFont, Color foregroundColor, |
166 |
Color backgroundColor, Color selectedForegroundColor, |
167 |
Color selectedBackgroundColor, int width, int height, CompletionItem item, |
168 |
boolean isBestMatch, boolean isSelected) { |
169 |
if (isBestMatch) { |
170 |
// Clear the background |
171 |
g.setColor(selectedBackgroundColor); |
172 |
g.fillRect(0, 0, width, height); |
173 |
g.setColor(selectedForegroundColor); |
174 |
item.render(g, defaultFont, selectedForegroundColor, |
175 |
selectedBackgroundColor, width, height, isBestMatch); |
176 |
} else { |
177 |
// Clear the background |
178 |
g.setColor(backgroundColor); |
179 |
g.fillRect(0, 0, width, height); |
180 |
g.setColor(foregroundColor); |
181 |
item.render(g, defaultFont, foregroundColor, backgroundColor, |
182 |
width, height, isBestMatch); |
183 |
} |
184 |
} |
185 |
|
186 |
@Override |
187 |
public boolean instantSubstitution(CompletionItem uniqueMatch) { |
188 |
return uniqueMatch.instantSubstitution(getActiveComponent()); |
189 |
} |
190 |
}; |
132 |
|
191 |
|
133 |
public static CompletionImpl get() { |
192 |
public static CompletionImpl get() { |
134 |
if (singleton == null) |
193 |
if (singleton == null) |
Lines 166-173
Link Here
|
166 |
/* Completion providers registered for the active component (its mime-type). Changed in AWT only. */ |
225 |
/* Completion providers registered for the active component (its mime-type). Changed in AWT only. */ |
167 |
private CompletionProvider[] activeProviders = null; |
226 |
private CompletionProvider[] activeProviders = null; |
168 |
|
227 |
|
169 |
/** Mapping of mime-type to array of providers. Changed in AWT only. */ |
228 |
/** Completion providers registered for the active component (its mime-type). Changed in AWT only. */ |
170 |
private HashMap<String, CompletionProvider[]> providersCache = new HashMap<String, CompletionProvider[]>(); |
229 |
private CompletionControllerProvider[] activeControllerProviders = null; |
|
|
230 |
|
231 |
/** Mapping of mime-type to service provider type to array of providers. Changed in AWT only. */ |
232 |
private HashMap<String, HashMap<Class<?>, Object[]>> providersCache = |
233 |
new HashMap<String, HashMap<Class<?>, Object[]>>(); |
171 |
|
234 |
|
172 |
/** |
235 |
/** |
173 |
* Result of the completion query. |
236 |
* Result of the completion query. |
Lines 253-259
Link Here
|
253 |
|
316 |
|
254 |
docAutoPopupTimer = new Timer(0, new ActionListener() { |
317 |
docAutoPopupTimer = new Timer(0, new ActionListener() { |
255 |
public void actionPerformed(ActionEvent e) { |
318 |
public void actionPerformed(ActionEvent e) { |
256 |
if (lastSelectedItem == null || lastSelectedItem.get() != layout.getSelectedCompletionItem()) |
319 |
SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem(); |
|
|
320 |
CompletionItem currentSelectedItem = selectedItem != null ? selectedItem.getItem() : null; |
321 |
if (lastSelectedItem == null || lastSelectedItem.get() != currentSelectedItem) |
257 |
showDocumentation(); |
322 |
showDocumentation(); |
258 |
} |
323 |
} |
259 |
}); |
324 |
}); |
Lines 278-284
Link Here
|
278 |
} |
343 |
} |
279 |
} |
344 |
} |
280 |
layout.showCompletion(Collections.singletonList(waitText), |
345 |
layout.showCompletion(Collections.singletonList(waitText), |
281 |
null, -1, CompletionImpl.this, null, null, 0); |
346 |
null, -1, CompletionImpl.this, null, null, |
|
|
347 |
FALLBACK_COMPLETION_CONTROLLER, |
348 |
CompletionController.Selection.DEFAULT); |
282 |
pleaseWaitDisplayed = true; |
349 |
pleaseWaitDisplayed = true; |
283 |
if (!politeWaitText) { |
350 |
if (!politeWaitText) { |
284 |
long when = System.currentTimeMillis() - PLEASE_WAIT_TIMEOUT; |
351 |
long when = System.currentTimeMillis() - PLEASE_WAIT_TIMEOUT; |
Lines 328-334
Link Here
|
328 |
CompletionSettings.getInstance(getActiveComponent()).completionAutoPopup()) { |
395 |
CompletionSettings.getInstance(getActiveComponent()).completionAutoPopup()) { |
329 |
autoModEndOffset = modEndOffset; |
396 |
autoModEndOffset = modEndOffset; |
330 |
if (completionResultNull) |
397 |
if (completionResultNull) |
331 |
showCompletion(false, false, true, CompletionProvider.COMPLETION_QUERY_TYPE); |
398 |
showCompletion(false, false, true, type & (CompletionProvider.COMPLETION_QUERY_MASK | CompletionProvider.USER_QUERY_MASK)); |
332 |
} |
399 |
} |
333 |
|
400 |
|
334 |
boolean tooltipResultNull; |
401 |
boolean tooltipResultNull; |
Lines 497-541
Link Here
|
497 |
} |
564 |
} |
498 |
|
565 |
|
499 |
private void initActiveProviders(JTextComponent component) { |
566 |
private void initActiveProviders(JTextComponent component) { |
500 |
activeProviders = (component != null) |
567 |
activeProviders = initActiveProviders(CompletionProvider.class, component); |
501 |
? getCompletionProvidersForComponent(component, true) |
568 |
// currently only one async warm up task is allowed at once |
|
|
569 |
activeControllerProviders = null; |
570 |
} |
571 |
|
572 |
private <T> T[] initActiveProviders(Class<T> clazz, JTextComponent component) { |
573 |
T[] providers = (component != null) |
574 |
? getProvidersForComponent(clazz, component, true) |
502 |
: null; |
575 |
: null; |
|
|
576 |
|
503 |
if (LOG.isLoggable(Level.FINE)) { |
577 |
if (LOG.isLoggable(Level.FINE)) { |
504 |
StringBuffer sb = new StringBuffer("Completion PROVIDERS:\n"); // NOI18N |
578 |
StringBuilder sb = new StringBuilder(clazz.getName() + " PROVIDERS:\n"); // NOI18N |
505 |
if (activeProviders != null) { |
579 |
if (providers != null) { |
506 |
for (int i = 0; i < activeProviders.length; i++) { |
580 |
for (int i = 0; i < providers.length; i++) { |
507 |
sb.append("providers["); // NOI18N |
581 |
sb.append("providers["); // NOI18N |
508 |
sb.append(i); |
582 |
sb.append(i); |
509 |
sb.append("]: "); // NOI18N |
583 |
sb.append("]: "); // NOI18N |
510 |
sb.append(activeProviders[i].getClass()); |
584 |
sb.append(providers[i].getClass()); |
511 |
sb.append('\n'); |
585 |
sb.append('\n'); |
512 |
} |
586 |
} |
513 |
} |
587 |
} |
514 |
LOG.fine(sb.toString()); |
588 |
LOG.fine(sb.toString()); |
515 |
} |
589 |
} |
|
|
590 |
|
591 |
return providers; |
516 |
} |
592 |
} |
517 |
|
593 |
|
518 |
private boolean ensureActiveProviders() { |
594 |
private boolean ensureActiveProviders() { |
519 |
if (activeProviders != null) |
595 |
activeProviders = ensureActiveProviders(CompletionProvider.class, activeProviders); |
520 |
return true; |
596 |
activeControllerProviders = ensureActiveProviders(CompletionControllerProvider.class, activeControllerProviders); |
|
|
597 |
// allow activeControllerProviders to be null since we have a |
598 |
// DefaultCompletionControllerProvider to fall back on. |
599 |
return activeProviders != null; |
600 |
} |
601 |
|
602 |
private <T> T[] ensureActiveProviders(Class<T> clazz, T[] providers) { |
603 |
if (providers != null) |
604 |
return providers; |
521 |
JTextComponent component = getActiveComponent(); |
605 |
JTextComponent component = getActiveComponent(); |
522 |
activeProviders = (component != null) |
606 |
providers = (component != null) |
523 |
? getCompletionProvidersForComponent(component, false) |
607 |
? getProvidersForComponent(clazz, component, false) |
524 |
: null; |
608 |
: null; |
525 |
if (LOG.isLoggable(Level.FINE)) { |
609 |
if (LOG.isLoggable(Level.FINE)) { |
526 |
StringBuffer sb = new StringBuffer("Completion PROVIDERS:\n"); // NOI18N |
610 |
StringBuilder sb = new StringBuilder(clazz.getName() + " PROVIDERS:\n"); // NOI18N |
527 |
if (activeProviders != null) { |
611 |
if (providers != null) { |
528 |
for (int i = 0; i < activeProviders.length; i++) { |
612 |
for (int i = 0; i < providers.length; i++) { |
529 |
sb.append("providers["); // NOI18N |
613 |
sb.append("providers["); // NOI18N |
530 |
sb.append(i); |
614 |
sb.append(i); |
531 |
sb.append("]: "); // NOI18N |
615 |
sb.append("]: "); // NOI18N |
532 |
sb.append(activeProviders[i].getClass()); |
616 |
sb.append(providers[i].getClass()); |
533 |
sb.append('\n'); |
617 |
sb.append('\n'); |
534 |
} |
618 |
} |
535 |
} |
619 |
} |
536 |
LOG.fine(sb.toString()); |
620 |
LOG.fine(sb.toString()); |
537 |
} |
621 |
} |
538 |
return activeProviders != null; |
622 |
return providers; |
539 |
} |
623 |
} |
540 |
|
624 |
|
541 |
private void restartCompletionAutoPopupTimer() { |
625 |
private void restartCompletionAutoPopupTimer() { |
Lines 553-560
Link Here
|
553 |
docAutoPopupTimer.setInitialDelay(docDelay); |
637 |
docAutoPopupTimer.setInitialDelay(docDelay); |
554 |
docAutoPopupTimer.restart(); |
638 |
docAutoPopupTimer.restart(); |
555 |
} |
639 |
} |
556 |
|
640 |
|
557 |
private CompletionProvider[] getCompletionProvidersForComponent(JTextComponent component, boolean asyncWarmUp) { |
641 |
private <T> T[] getProvidersForComponent(final Class<T> clazz, JTextComponent component, boolean asyncWarmUp) { |
558 |
assert (SwingUtilities.isEventDispatchThread()); |
642 |
assert (SwingUtilities.isEventDispatchThread()); |
559 |
|
643 |
|
560 |
if (component == null) |
644 |
if (component == null) |
Lines 569-583
Link Here
|
569 |
BaseKit kit = Utilities.getKit(component); |
653 |
BaseKit kit = Utilities.getKit(component); |
570 |
|
654 |
|
571 |
if (kit == null) { |
655 |
if (kit == null) { |
572 |
return new CompletionProvider[0]; |
656 |
@SuppressWarnings("unchecked") |
|
|
657 |
T[] result = (T[])Array.newInstance(clazz, 0); |
658 |
return result; |
573 |
} |
659 |
} |
574 |
|
660 |
|
575 |
mimeType = kit.getContentType(); |
661 |
mimeType = kit.getContentType(); |
576 |
} |
662 |
} |
577 |
|
663 |
|
578 |
if (providersCache.containsKey(mimeType)) |
664 |
HashMap<Class<?>, Object[]> providers = providersCache.get(mimeType); |
579 |
return providersCache.get(mimeType); |
665 |
if (providers == null) { |
|
|
666 |
providers = new HashMap<Class<?>, Object[]>(); |
667 |
providersCache.put(mimeType, providers); |
668 |
} |
580 |
|
669 |
|
|
|
670 |
if (providers.containsKey(clazz)) { |
671 |
@SuppressWarnings("unchecked") |
672 |
T[] result = (T[])providers.get(clazz); |
673 |
return result; |
674 |
} |
675 |
|
581 |
if (asyncWarmUpTask != null) { |
676 |
if (asyncWarmUpTask != null) { |
582 |
if (asyncWarmUp && mimeType != null && mimeType.equals(asyncWarmUpMimeType)) |
677 |
if (asyncWarmUp && mimeType != null && mimeType.equals(asyncWarmUpMimeType)) |
583 |
return null; |
678 |
return null; |
Lines 587-610
Link Here
|
587 |
asyncWarmUpTask = null; |
682 |
asyncWarmUpTask = null; |
588 |
asyncWarmUpMimeType = null; |
683 |
asyncWarmUpMimeType = null; |
589 |
} |
684 |
} |
|
|
685 |
|
590 |
final Lookup lookup = MimeLookup.getLookup(MimePath.get(mimeType)); |
686 |
final Lookup lookup = MimeLookup.getLookup(MimePath.get(mimeType)); |
591 |
if (asyncWarmUp) { |
687 |
if (asyncWarmUp) { |
592 |
asyncWarmUpMimeType = mimeType; |
688 |
asyncWarmUpMimeType = mimeType; |
593 |
asyncWarmUpTask = RequestProcessor.getDefault().post(new Runnable() { |
689 |
asyncWarmUpTask = RequestProcessor.getDefault().post(new Runnable() { |
594 |
@Override |
690 |
@Override |
595 |
public void run() { |
691 |
public void run() { |
596 |
lookup.lookupAll(CompletionProvider.class); |
692 |
lookup.lookupAll(clazz); |
597 |
} |
693 |
} |
598 |
}); |
694 |
}); |
599 |
return null; |
695 |
return null; |
600 |
} |
696 |
} |
601 |
Collection<? extends CompletionProvider> col = lookup.lookupAll(CompletionProvider.class); |
697 |
|
|
|
698 |
Collection<? extends T> col = lookup.lookupAll(clazz); |
602 |
int size = col.size(); |
699 |
int size = col.size(); |
603 |
CompletionProvider[] ret = size == 0 ? null : col.toArray(new CompletionProvider[size]); |
700 |
@SuppressWarnings("unchecked") |
604 |
providersCache.put(mimeType, ret); |
701 |
T[] ret = size == 0 ? null : col.toArray((T[])Array.newInstance(clazz, size)); |
|
|
702 |
providers.put(clazz, ret); |
605 |
return ret; |
703 |
return ret; |
606 |
} |
704 |
} |
607 |
|
705 |
|
608 |
private void dispatchKeyEvent(KeyEvent e) { |
706 |
private void dispatchKeyEvent(KeyEvent e) { |
609 |
if (e == null) |
707 |
if (e == null) |
610 |
return; |
708 |
return; |
Lines 624-644
Link Here
|
624 |
} |
722 |
} |
625 |
} |
723 |
} |
626 |
if (layout.isCompletionVisible()) { |
724 |
if (layout.isCompletionVisible()) { |
627 |
CompletionItem item = layout.getSelectedCompletionItem(); |
725 |
SelectedCompletionItem item = layout.getSelectedCompletionItem(); |
628 |
if (item != null) { |
726 |
if (item != null && completionResult != null) { |
629 |
sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP); |
727 |
sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP); |
630 |
try { |
728 |
try { |
631 |
if (compEditable && !guardedPos) { |
729 |
if (compEditable && !guardedPos) { |
632 |
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT"); // NOI18N |
730 |
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT"); // NOI18N |
633 |
r.setParameters(new Object[] {e.getKeyChar(), layout.getSelectedIndex(), item.getClass().getSimpleName()}); |
731 |
r.setParameters(new Object[] {e.getKeyChar(), layout.getSelectedIndex(), item.getItem().getClass().getSimpleName()}); |
634 |
item.processKeyEvent(e); |
732 |
completionResult.getController().processKeyEvent(e, item.getItem(), item.isSelected()); |
635 |
if (e.isConsumed()) { |
733 |
if (e.isConsumed()) { |
636 |
uilog(r); |
734 |
uilog(r); |
637 |
return; |
735 |
return; |
638 |
} |
736 |
} |
639 |
} |
737 |
} |
640 |
// Call default action if ENTER was pressed |
738 |
// Call default action if ENTER was pressed and the item is selected |
641 |
if (e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED) { |
739 |
// TODO: move this functionality to the CompletionController |
|
|
740 |
if (item.isSelected() && e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED) { |
642 |
e.consume(); |
741 |
e.consume(); |
643 |
if (guardedPos) { |
742 |
if (guardedPos) { |
644 |
Toolkit.getDefaultToolkit().beep(); |
743 |
Toolkit.getDefaultToolkit().beep(); |
Lines 648-655
Link Here
|
648 |
consumeIdentifier(); |
747 |
consumeIdentifier(); |
649 |
} |
748 |
} |
650 |
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT_DEFAULT"); // NOI18N |
749 |
LogRecord r = new LogRecord(Level.FINE, "COMPL_KEY_SELECT_DEFAULT"); // NOI18N |
651 |
r.setParameters(new Object[]{'\n', layout.getSelectedIndex(), item.getClass().getSimpleName()}); |
750 |
r.setParameters(new Object[]{'\n', layout.getSelectedIndex(), item.getItem().getClass().getSimpleName()}); |
652 |
item.defaultAction(getActiveComponent()); |
751 |
completionResult.getController().defaultAction(item.getItem(), item.isSelected()); |
653 |
uilog(r); |
752 |
uilog(r); |
654 |
} |
753 |
} |
655 |
return; |
754 |
return; |
Lines 662-667
Link Here
|
662 |
|| e.getKeyCode() == KeyEvent.VK_HOME || e.getKeyCode() == KeyEvent.VK_END) { |
761 |
|| e.getKeyCode() == KeyEvent.VK_HOME || e.getKeyCode() == KeyEvent.VK_END) { |
663 |
hideCompletion(false); |
762 |
hideCompletion(false); |
664 |
} |
763 |
} |
|
|
764 |
// TODO: move this functionality to the CompletionController |
665 |
if (e.getKeyCode() == KeyEvent.VK_TAB && doc.getProperty(CT_HANDLER_DOC_PROPERTY) == null) { |
765 |
if (e.getKeyCode() == KeyEvent.VK_TAB && doc.getProperty(CT_HANDLER_DOC_PROPERTY) == null) { |
666 |
e.consume(); |
766 |
e.consume(); |
667 |
if (guardedPos) { |
767 |
if (guardedPos) { |
Lines 716-723
Link Here
|
716 |
} |
816 |
} |
717 |
} else { |
817 |
} else { |
718 |
completionCancel(); |
818 |
completionCancel(); |
719 |
if (explicitQuery) |
819 |
if (explicitQuery) { |
720 |
layout.showCompletion(Collections.singletonList(NO_SUGGESTIONS), null, -1, CompletionImpl.this, null, null, 0); |
820 |
layout.showCompletion(Collections.singletonList(NO_SUGGESTIONS), |
|
|
821 |
null, -1, CompletionImpl.this, null, null, |
822 |
FALLBACK_COMPLETION_CONTROLLER, |
823 |
CompletionController.Selection.DEFAULT); |
824 |
} |
721 |
pleaseWaitDisplayed = false; |
825 |
pleaseWaitDisplayed = false; |
722 |
stopProfiling(); |
826 |
stopProfiling(); |
723 |
} |
827 |
} |
Lines 945-951
Link Here
|
945 |
|
1049 |
|
946 |
final ArrayList<CompletionItem> sortedResultItems = new ArrayList<CompletionItem>(size = resultItems.size()); |
1050 |
final ArrayList<CompletionItem> sortedResultItems = new ArrayList<CompletionItem>(size = resultItems.size()); |
947 |
if (size > 0) { |
1051 |
if (size > 0) { |
948 |
Collections.sort(resultItems, CompletionItemComparator.get(getSortType())); |
1052 |
result.getController().sortItems(resultItems, getSortType()); |
949 |
int cnt = 0; |
1053 |
int cnt = 0; |
950 |
for(int i = 0; i < size; i++) { |
1054 |
for(int i = 0; i < size; i++) { |
951 |
CompletionItem item = resultItems.get(i); |
1055 |
CompletionItem item = resultItems.get(i); |
Lines 964-974
Link Here
|
964 |
|
1068 |
|
965 |
final boolean noSuggestions = sortedResultItems.size() == 0; |
1069 |
final boolean noSuggestions = sortedResultItems.size() == 0; |
966 |
if (noSuggestions) { |
1070 |
if (noSuggestions) { |
967 |
if (hasAdditionalItems && qType == CompletionProvider.COMPLETION_QUERY_TYPE) { |
1071 |
if (hasAdditionalItems && (qType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) != CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { |
968 |
showCompletion(this.explicitQuery, this.refreshedQuery, false, CompletionProvider.COMPLETION_ALL_QUERY_TYPE); |
1072 |
showCompletion(this.explicitQuery, this.refreshedQuery, false, CompletionProvider.COMPLETION_ALL_QUERY_TYPE); |
969 |
return; |
1073 |
return; |
970 |
} |
1074 |
} |
971 |
if (!explicitQuery) { |
1075 |
if (!explicitQuery) { |
972 |
hideCompletion(false); |
1076 |
hideCompletion(false); |
973 |
return; |
1077 |
return; |
974 |
} |
1078 |
} |
Lines 988-1016
Link Here
|
988 |
Document doc = c.getDocument(); |
1092 |
Document doc = c.getDocument(); |
989 |
CompletionSettings cs = CompletionSettings.getInstance(c); |
1093 |
CompletionSettings cs = CompletionSettings.getInstance(c); |
990 |
int caretOffset = c.getSelectionStart(); |
1094 |
int caretOffset = c.getSelectionStart(); |
991 |
// completionResults = null; |
1095 |
|
992 |
if (sortedResultItems.size() == 1 && !refreshedQuery && explicitQuery |
1096 |
CompletionController.Selection selection = result.getController().getSelection(sortedResultItems); |
|
|
1097 |
// the CompletionController should be returning a valid selection |
1098 |
assert selection != null |
1099 |
&& (sortedResultItems.isEmpty() |
1100 |
|| selection.getIndex() >= 0 && selection.getIndex() < sortedResultItems.size()); |
1101 |
if (selection == null || selection.getIndex() < 0 || selection.getIndex() > sortedResultItems.size()) { |
1102 |
selection = CompletionController.Selection.DEFAULT; |
1103 |
} |
1104 |
|
1105 |
if (selection.isUnique() && !refreshedQuery && explicitQuery |
993 |
&& cs.completionInstantSubstitution() |
1106 |
&& cs.completionInstantSubstitution() |
994 |
&& c.isEditable() && !(doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(caretOffset))) { |
1107 |
&& c.isEditable() && !(doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(caretOffset))) { |
|
|
1108 |
|
1109 |
sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP); |
995 |
try { |
1110 |
try { |
996 |
int[] block = Utilities.getIdentifierBlock(c, caretOffset); |
1111 |
if (result.getController().instantSubstitution(sortedResultItems.get(selection.getIndex()))) |
997 |
if (block == null || block[1] == caretOffset) { // NOI18N |
1112 |
return; |
998 |
CompletionItem item = sortedResultItems.get(0); |
1113 |
} finally { |
999 |
sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP); |
1114 |
sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP); |
1000 |
try { |
|
|
1001 |
if (item.instantSubstitution(c)) |
1002 |
return; |
1003 |
} finally { |
1004 |
sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP); |
1005 |
} |
1006 |
} |
1007 |
} catch (BadLocationException ex) { |
1008 |
} |
1115 |
} |
1009 |
} |
1116 |
} |
1010 |
|
1117 |
|
1011 |
int selectedIndex = getCompletionPreSelectionIndex(sortedResultItems); |
|
|
1012 |
c.putClientProperty("completion-visible", Boolean.TRUE); |
1118 |
c.putClientProperty("completion-visible", Boolean.TRUE); |
1013 |
layout.showCompletion(noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems, displayTitle, displayAnchorOffset, CompletionImpl.this, displayAdditionalItems ? hasAdditionalItemsText.toString() : null, displayAdditionalItems ? completionShortcut : null, selectedIndex); |
1119 |
layout.showCompletion( |
|
|
1120 |
noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems, |
1121 |
displayTitle, displayAnchorOffset, CompletionImpl.this, |
1122 |
displayAdditionalItems ? hasAdditionalItemsText.toString() : null, |
1123 |
displayAdditionalItems ? completionShortcut : null, |
1124 |
result.getController(), |
1125 |
selection); |
1014 |
pleaseWaitDisplayed = false; |
1126 |
pleaseWaitDisplayed = false; |
1015 |
stopProfiling(); |
1127 |
stopProfiling(); |
1016 |
|
1128 |
|
Lines 1028-1059
Link Here
|
1028 |
}; |
1140 |
}; |
1029 |
runInAWT(requestShowRunnable); |
1141 |
runInAWT(requestShowRunnable); |
1030 |
} |
1142 |
} |
1031 |
|
|
|
1032 |
private int getCompletionPreSelectionIndex(List<CompletionItem> items) { |
1033 |
String prefix = null; |
1034 |
if(getActiveDocument() instanceof BaseDocument) { |
1035 |
BaseDocument doc = (BaseDocument)getActiveDocument(); |
1036 |
int caretOffset = getActiveComponent().getSelectionStart(); |
1037 |
try { |
1038 |
int[] block = Utilities.getIdentifierBlock(doc, caretOffset); |
1039 |
if (block != null) { |
1040 |
block[1] = caretOffset; |
1041 |
prefix = doc.getText(block); |
1042 |
} |
1043 |
} catch (BadLocationException ble) { |
1044 |
} |
1045 |
} |
1046 |
if (prefix != null && prefix.length() > 0) { |
1047 |
int idx = 0; |
1048 |
for (CompletionItem item : items) { |
1049 |
CharSequence text = item.getInsertPrefix(); |
1050 |
if (text != null && text.toString().startsWith(prefix)) |
1051 |
return idx; |
1052 |
idx++; |
1053 |
} |
1054 |
} |
1055 |
return 0; |
1056 |
} |
1057 |
|
1143 |
|
1058 |
/** |
1144 |
/** |
1059 |
* May be called from any thread. The UI changes will be rescheduled into AWT. |
1145 |
* May be called from any thread. The UI changes will be rescheduled into AWT. |
Lines 1144-1153
Link Here
|
1144 |
List<CompletionResultSetImpl> documentationResultSets = docResult.getResultSets(); |
1230 |
List<CompletionResultSetImpl> documentationResultSets = docResult.getResultSets(); |
1145 |
|
1231 |
|
1146 |
CompletionTask docTask; |
1232 |
CompletionTask docTask; |
1147 |
CompletionItem selectedItem = layout.getSelectedCompletionItem(); |
1233 |
SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem(); |
1148 |
if (selectedItem != null) { |
1234 |
if (selectedItem != null) { |
1149 |
lastSelectedItem = new WeakReference<CompletionItem>(selectedItem); |
1235 |
lastSelectedItem = new WeakReference<CompletionItem>(selectedItem.getItem()); |
1150 |
docTask = selectedItem.createDocumentationTask(); |
1236 |
docTask = selectedItem.getItem().createDocumentationTask(); |
1151 |
if (docTask != null) { // attempt the documentation for selected item |
1237 |
if (docTask != null) { // attempt the documentation for selected item |
1152 |
CompletionResultSetImpl resultSet = new CompletionResultSetImpl( |
1238 |
CompletionResultSetImpl resultSet = new CompletionResultSetImpl( |
1153 |
this, newDocumentationResult, docTask, CompletionProvider.DOCUMENTATION_QUERY_TYPE); |
1239 |
this, newDocumentationResult, docTask, CompletionProvider.DOCUMENTATION_QUERY_TYPE); |
Lines 1266-1273
Link Here
|
1266 |
List<CompletionResultSetImpl> toolTipResultSets = newToolTipResult.getResultSets(); |
1352 |
List<CompletionResultSetImpl> toolTipResultSets = newToolTipResult.getResultSets(); |
1267 |
|
1353 |
|
1268 |
CompletionTask toolTipTask; |
1354 |
CompletionTask toolTipTask; |
1269 |
CompletionItem selectedItem = layout.getSelectedCompletionItem(); |
1355 |
SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem(); |
1270 |
if (selectedItem != null && (toolTipTask = selectedItem.createToolTipTask()) != null) { |
1356 |
if (selectedItem != null && (toolTipTask = selectedItem.getItem().createToolTipTask()) != null) { |
1271 |
CompletionResultSetImpl resultSet = new CompletionResultSetImpl( |
1357 |
CompletionResultSetImpl resultSet = new CompletionResultSetImpl( |
1272 |
this, newToolTipResult, toolTipTask, CompletionProvider.TOOLTIP_QUERY_TYPE); |
1358 |
this, newToolTipResult, toolTipTask, CompletionProvider.TOOLTIP_QUERY_TYPE); |
1273 |
toolTipResultSets.add(resultSet); |
1359 |
toolTipResultSets.add(resultSet); |
Lines 1437-1443
Link Here
|
1437 |
void finishNotify(CompletionResultSetImpl finishedResult) { |
1523 |
void finishNotify(CompletionResultSetImpl finishedResult) { |
1438 |
Result localResult; |
1524 |
Result localResult; |
1439 |
boolean finished = false; |
1525 |
boolean finished = false; |
1440 |
switch (finishedResult.getQueryType()) { |
1526 |
switch (finishedResult.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) { |
1441 |
case CompletionProvider.COMPLETION_QUERY_TYPE: |
1527 |
case CompletionProvider.COMPLETION_QUERY_TYPE: |
1442 |
case CompletionProvider.COMPLETION_ALL_QUERY_TYPE: |
1528 |
case CompletionProvider.COMPLETION_ALL_QUERY_TYPE: |
1443 |
synchronized (this) { |
1529 |
synchronized (this) { |
Lines 1503-1509
Link Here
|
1503 |
private static CompletionResultSetImpl findFirstValidResult(List<CompletionResultSetImpl> resultSets) { |
1589 |
private static CompletionResultSetImpl findFirstValidResult(List<CompletionResultSetImpl> resultSets) { |
1504 |
for (int i = 0; i < resultSets.size(); i++) { |
1590 |
for (int i = 0; i < resultSets.size(); i++) { |
1505 |
CompletionResultSetImpl result = resultSets.get(i); |
1591 |
CompletionResultSetImpl result = resultSets.get(i); |
1506 |
switch (result.getQueryType()) { |
1592 |
switch (result.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) { |
1507 |
case CompletionProvider.DOCUMENTATION_QUERY_TYPE: |
1593 |
case CompletionProvider.DOCUMENTATION_QUERY_TYPE: |
1508 |
if (result.getDocumentation() != null) { |
1594 |
if (result.getDocumentation() != null) { |
1509 |
return result; |
1595 |
return result; |
Lines 1688-1693
Link Here
|
1688 |
private boolean invoked; |
1774 |
private boolean invoked; |
1689 |
private boolean cancelled; |
1775 |
private boolean cancelled; |
1690 |
private boolean beforeQuery = true; |
1776 |
private boolean beforeQuery = true; |
|
|
1777 |
|
1778 |
private CompletionController controller; |
1691 |
|
1779 |
|
1692 |
Result(int resultSetsSize) { |
1780 |
Result(int resultSetsSize) { |
1693 |
resultSets = new ArrayList<CompletionResultSetImpl>(resultSetsSize); |
1781 |
resultSets = new ArrayList<CompletionResultSetImpl>(resultSetsSize); |
Lines 1702-1707
Link Here
|
1702 |
return resultSets; |
1790 |
return resultSets; |
1703 |
} |
1791 |
} |
1704 |
|
1792 |
|
|
|
1793 |
CompletionController getController() { |
1794 |
synchronized (resultSets) { |
1795 |
if (controller == null) { |
1796 |
if (resultSets.isEmpty()) { |
1797 |
return FALLBACK_COMPLETION_CONTROLLER; |
1798 |
} |
1799 |
|
1800 |
JTextComponent component = getActiveComponent(); |
1801 |
CompletionTask task = resultSets.get(0).getTask(); |
1802 |
int queryType = resultSets.get(0).getQueryType(); |
1803 |
CompletionControllerProvider[] providers = activeControllerProviders; |
1804 |
if (providers != null) { |
1805 |
for (CompletionControllerProvider provider : providers) { |
1806 |
controller = provider.createController(component, task, queryType); |
1807 |
if (controller != null) { |
1808 |
break; |
1809 |
} |
1810 |
} |
1811 |
} |
1812 |
|
1813 |
if (controller == null) { |
1814 |
CompletionControllerProvider provider = |
1815 |
DefaultCompletionControllerProvider.INSTANCE; |
1816 |
controller = provider.createController(component, task, queryType); |
1817 |
} |
1818 |
} |
1819 |
|
1820 |
return controller; |
1821 |
} |
1822 |
} |
1823 |
|
1705 |
/** |
1824 |
/** |
1706 |
* Cancel the resultSets. |
1825 |
* Cancel the resultSets. |
1707 |
* <br> |
1826 |
* <br> |