This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 204867
Collapse All | Expand All

(-)a/editor.completion/nbproject/project.xml (+9 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.modules.editor.completion</code-name-base>
50
            <code-name-base>org.netbeans.modules.editor.completion</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <release-version>1</release-version>
58
                        <specification-version>1.11</specification-version>
59
                    </run-dependency>
60
                </dependency>
61
                <dependency>
53
                    <code-name-base>org.netbeans.modules.editor</code-name-base>
62
                    <code-name-base>org.netbeans.modules.editor</code-name-base>
54
                    <build-prerequisite/>
63
                    <build-prerequisite/>
55
                    <compile-dependency/>
64
                    <compile-dependency/>
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java (-94 / +213 lines)
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 858-866 Link Here
858
                    return;
962
                    return;
859
                }
963
                }
860
            }
964
            }
861
            CompletionItem item = layout.getSelectedCompletionItem();
965
            SelectedCompletionItem item = layout.getSelectedCompletionItem();
862
            if (item != null)
966
            if (item != null)
863
                item.defaultAction(c);
967
                localCompletionResult.getController().defaultAction(item.getItem(), item.isSelected());
864
        }
968
        }
865
    }
969
    }
866
    
970
    
Lines 949-955 Link Here
949
        
1053
        
950
        final ArrayList<CompletionItem> sortedResultItems = new ArrayList<CompletionItem>(size = resultItems.size());
1054
        final ArrayList<CompletionItem> sortedResultItems = new ArrayList<CompletionItem>(size = resultItems.size());
951
        if (size > 0) {
1055
        if (size > 0) {
952
            Collections.sort(resultItems, CompletionItemComparator.get(getSortType()));
1056
            result.getController().sortItems(resultItems, getSortType());
953
            int cnt = 0;
1057
            int cnt = 0;
954
            for(int i = 0; i < size; i++) {
1058
            for(int i = 0; i < size; i++) {
955
                CompletionItem item = resultItems.get(i);                
1059
                CompletionItem item = resultItems.get(i);                
Lines 968-978 Link Here
968
1072
969
        final boolean noSuggestions = sortedResultItems.size() == 0;
1073
        final boolean noSuggestions = sortedResultItems.size() == 0;
970
        if (noSuggestions) {
1074
        if (noSuggestions) {
971
            if (hasAdditionalItems && qType == CompletionProvider.COMPLETION_QUERY_TYPE) {
1075
            if (hasAdditionalItems && (qType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) != CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
972
                showCompletion(this.explicitQuery, this.refreshedQuery, false, CompletionProvider.COMPLETION_ALL_QUERY_TYPE);
1076
                showCompletion(this.explicitQuery, this.refreshedQuery, false, CompletionProvider.COMPLETION_ALL_QUERY_TYPE);
973
                return;
1077
                return;
974
            }
1078
            }
975
            if (!explicitQuery) {                
1079
            if (!explicitQuery) {
976
                hideCompletion(false);
1080
                hideCompletion(false);
977
                return;
1081
                return;
978
            }
1082
            }
Lines 992-1020 Link Here
992
                Document doc = c.getDocument();
1096
                Document doc = c.getDocument();
993
                CompletionSettings cs = CompletionSettings.getInstance(c);
1097
                CompletionSettings cs = CompletionSettings.getInstance(c);
994
                int caretOffset = c.getSelectionStart();
1098
                int caretOffset = c.getSelectionStart();
995
                // completionResults = null;
1099
996
                if (sortedResultItems.size() == 1 && !refreshedQuery && explicitQuery
1100
                CompletionController.Selection selection = result.getController().getSelection(sortedResultItems);
1101
                // the CompletionController should be returning a valid selection
1102
                assert selection != null
1103
                    && (sortedResultItems.isEmpty()
1104
                        || selection.getIndex() >= 0 && selection.getIndex() < sortedResultItems.size());
1105
                if (selection == null || selection.getIndex() < 0 || selection.getIndex() > sortedResultItems.size()) {
1106
                    selection = CompletionController.Selection.DEFAULT;
1107
                }
1108
1109
                if (selection.isUnique() && !refreshedQuery && explicitQuery
997
                        && cs.completionInstantSubstitution()
1110
                        && cs.completionInstantSubstitution()
998
                        && c.isEditable() && !(doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(caretOffset))) {
1111
                        && c.isEditable() && !(doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(caretOffset))) {
1112
1113
                    sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
999
                    try {
1114
                    try {
1000
                        int[] block = Utilities.getIdentifierBlock(c, caretOffset);
1115
                        if (result.getController().instantSubstitution(sortedResultItems.get(selection.getIndex())))
1001
                        if (block == null || block[1] == caretOffset) { // NOI18N
1116
                            return;
1002
                            CompletionItem item = sortedResultItems.get(0);
1117
                    } finally {
1003
                            sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
1118
                        sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
1004
                            try {
1005
                                if (item.instantSubstitution(c))
1006
                                    return;
1007
                            } finally {
1008
                                sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
1009
                            }
1010
                        }
1011
                    } catch (BadLocationException ex) {
1012
                    }
1119
                    }
1013
                }
1120
                }
1014
                
1121
                
1015
                int selectedIndex = getCompletionPreSelectionIndex(sortedResultItems);
1016
                c.putClientProperty("completion-visible", Boolean.TRUE);
1122
                c.putClientProperty("completion-visible", Boolean.TRUE);
1017
                layout.showCompletion(noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems, displayTitle, displayAnchorOffset, CompletionImpl.this, displayAdditionalItems ? hasAdditionalItemsText.toString() : null, displayAdditionalItems ? completionShortcut : null, selectedIndex);
1123
                layout.showCompletion(
1124
                        noSuggestions ? Collections.singletonList(NO_SUGGESTIONS) : sortedResultItems,
1125
                        displayTitle, displayAnchorOffset, CompletionImpl.this,
1126
                        displayAdditionalItems ? hasAdditionalItemsText.toString() : null,
1127
                        displayAdditionalItems ? completionShortcut : null,
1128
                        result.getController(),
1129
                        selection);
1018
                pleaseWaitDisplayed = false;
1130
                pleaseWaitDisplayed = false;
1019
                stopProfiling();
1131
                stopProfiling();
1020
1132
Lines 1032-1063 Link Here
1032
        };
1144
        };
1033
        runInAWT(requestShowRunnable);
1145
        runInAWT(requestShowRunnable);
1034
    }
1146
    }
1035
    
1036
    private int getCompletionPreSelectionIndex(List<CompletionItem> items) {
1037
        String prefix = null;
1038
        if(getActiveDocument() instanceof BaseDocument) {
1039
            BaseDocument doc = (BaseDocument)getActiveDocument();
1040
            int caretOffset = getActiveComponent().getSelectionStart();
1041
            try {
1042
                int[] block = Utilities.getIdentifierBlock(doc, caretOffset);
1043
                if (block != null) {
1044
                    block[1] = caretOffset;
1045
                    prefix = doc.getText(block);
1046
                }
1047
            } catch (BadLocationException ble) {
1048
            }
1049
        }
1050
        if (prefix != null && prefix.length() > 0) {
1051
            int idx = 0;
1052
            for (CompletionItem item : items) {
1053
                CharSequence text = item.getInsertPrefix();
1054
                if (text != null && text.toString().startsWith(prefix))
1055
                    return idx;
1056
                idx++;
1057
            }
1058
        }
1059
        return 0;
1060
    }
1061
1147
1062
    /**
1148
    /**
1063
     * May be called from any thread. The UI changes will be rescheduled into AWT.
1149
     * May be called from any thread. The UI changes will be rescheduled into AWT.
Lines 1148-1157 Link Here
1148
        List<CompletionResultSetImpl> documentationResultSets = docResult.getResultSets();
1234
        List<CompletionResultSetImpl> documentationResultSets = docResult.getResultSets();
1149
1235
1150
        CompletionTask docTask;
1236
        CompletionTask docTask;
1151
        CompletionItem selectedItem = layout.getSelectedCompletionItem();
1237
        SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem();
1152
        if (selectedItem != null) {
1238
        if (selectedItem != null) {
1153
            lastSelectedItem = new WeakReference<CompletionItem>(selectedItem);
1239
            lastSelectedItem = new WeakReference<CompletionItem>(selectedItem.getItem());
1154
            docTask = selectedItem.createDocumentationTask();
1240
            docTask = selectedItem.getItem().createDocumentationTask();
1155
            if (docTask != null) { // attempt the documentation for selected item
1241
            if (docTask != null) { // attempt the documentation for selected item
1156
                CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
1242
                CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
1157
                        this, newDocumentationResult, docTask, CompletionProvider.DOCUMENTATION_QUERY_TYPE);
1243
                        this, newDocumentationResult, docTask, CompletionProvider.DOCUMENTATION_QUERY_TYPE);
Lines 1270-1277 Link Here
1270
        List<CompletionResultSetImpl> toolTipResultSets = newToolTipResult.getResultSets();
1356
        List<CompletionResultSetImpl> toolTipResultSets = newToolTipResult.getResultSets();
1271
1357
1272
        CompletionTask toolTipTask;
1358
        CompletionTask toolTipTask;
1273
        CompletionItem selectedItem = layout.getSelectedCompletionItem();
1359
        SelectedCompletionItem selectedItem = layout.getSelectedCompletionItem();
1274
        if (selectedItem != null && (toolTipTask = selectedItem.createToolTipTask()) != null) {
1360
        if (selectedItem != null && (toolTipTask = selectedItem.getItem().createToolTipTask()) != null) {
1275
            CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
1361
            CompletionResultSetImpl resultSet = new CompletionResultSetImpl(
1276
                    this, newToolTipResult, toolTipTask, CompletionProvider.TOOLTIP_QUERY_TYPE);
1362
                    this, newToolTipResult, toolTipTask, CompletionProvider.TOOLTIP_QUERY_TYPE);
1277
            toolTipResultSets.add(resultSet);
1363
            toolTipResultSets.add(resultSet);
Lines 1441-1447 Link Here
1441
    void finishNotify(CompletionResultSetImpl finishedResult) {
1527
    void finishNotify(CompletionResultSetImpl finishedResult) {
1442
        Result localResult;
1528
        Result localResult;
1443
        boolean finished = false;
1529
        boolean finished = false;
1444
        switch (finishedResult.getQueryType()) {
1530
        switch (finishedResult.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) {
1445
            case CompletionProvider.COMPLETION_QUERY_TYPE:
1531
            case CompletionProvider.COMPLETION_QUERY_TYPE:
1446
            case CompletionProvider.COMPLETION_ALL_QUERY_TYPE:
1532
            case CompletionProvider.COMPLETION_ALL_QUERY_TYPE:
1447
                synchronized (this) {
1533
                synchronized (this) {
Lines 1507-1513 Link Here
1507
    private static CompletionResultSetImpl findFirstValidResult(List<CompletionResultSetImpl> resultSets) {
1593
    private static CompletionResultSetImpl findFirstValidResult(List<CompletionResultSetImpl> resultSets) {
1508
        for (int i = 0; i < resultSets.size(); i++) {
1594
        for (int i = 0; i < resultSets.size(); i++) {
1509
            CompletionResultSetImpl result = resultSets.get(i);
1595
            CompletionResultSetImpl result = resultSets.get(i);
1510
            switch (result.getQueryType()) {
1596
            switch (result.getQueryType() & CompletionProvider.RESERVED_QUERY_MASK) {
1511
                case CompletionProvider.DOCUMENTATION_QUERY_TYPE:
1597
                case CompletionProvider.DOCUMENTATION_QUERY_TYPE:
1512
                    if (result.getDocumentation() != null) {
1598
                    if (result.getDocumentation() != null) {
1513
                        return result;
1599
                        return result;
Lines 1692-1697 Link Here
1692
        private boolean invoked;                
1778
        private boolean invoked;                
1693
        private boolean cancelled;
1779
        private boolean cancelled;
1694
        private boolean beforeQuery = true;
1780
        private boolean beforeQuery = true;
1781
1782
        private CompletionController controller;
1695
        
1783
        
1696
        Result(int resultSetsSize) {
1784
        Result(int resultSetsSize) {
1697
            resultSets = new ArrayList<CompletionResultSetImpl>(resultSetsSize);
1785
            resultSets = new ArrayList<CompletionResultSetImpl>(resultSetsSize);
Lines 1706-1711 Link Here
1706
            return resultSets;
1794
            return resultSets;
1707
        }
1795
        }
1708
1796
1797
        CompletionController getController() {
1798
            synchronized (resultSets) {
1799
                if (controller == null) {
1800
                    if (resultSets.isEmpty()) {
1801
                        return FALLBACK_COMPLETION_CONTROLLER;
1802
                    }
1803
1804
                    JTextComponent component = getActiveComponent();
1805
                    CompletionTask task = resultSets.get(0).getTask();
1806
                    int queryType = resultSets.get(0).getQueryType();
1807
                    CompletionControllerProvider[] providers = activeControllerProviders;
1808
                    if (providers != null) {
1809
                        for (CompletionControllerProvider provider : providers) {
1810
                            controller = provider.createController(component, task, queryType);
1811
                            if (controller != null) {
1812
                                break;
1813
                            }
1814
                        }
1815
                    }
1816
1817
                    if (controller == null) {
1818
                        CompletionControllerProvider provider =
1819
                            DefaultCompletionControllerProvider.INSTANCE;
1820
                        controller = provider.createController(component, task, queryType);
1821
                    }
1822
                }
1823
1824
                return controller;
1825
            }
1826
        }
1827
1709
        /**
1828
        /**
1710
         * Cancel the resultSets.
1829
         * Cancel the resultSets.
1711
         * <br>
1830
         * <br>
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionItemComparator.java (-111 lines)
Removed Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
31
 * Microsystems, Inc. All Rights Reserved.
32
 *
33
 * If you wish your version of this file to be governed by only the CDDL
34
 * or only the GPL Version 2, indicate your decision by adding
35
 * "[Contributor] elects to include this software in this distribution
36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
37
 * single choice of license, a recipient has the option to distribute
38
 * your version of this file under either the CDDL, the GPL Version 2 or
39
 * to extend the choice of license to its licensees as provided above.
40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
43
 */
44
45
package org.netbeans.modules.editor.completion;
46
47
import java.util.Comparator;
48
import org.netbeans.spi.editor.completion.CompletionItem;
49
import org.netbeans.spi.editor.completion.CompletionResultSet;
50
51
/**
52
 * Comparator for completion items either by sort priority or by sort text.
53
 *
54
 * @author Dusan Balek, Miloslav Metelka
55
 */
56
57
public class CompletionItemComparator implements Comparator<CompletionItem> {
58
59
    public static final Comparator<CompletionItem> BY_PRIORITY = new CompletionItemComparator(true);
60
61
    public static final Comparator<CompletionItem> ALPHABETICAL = new CompletionItemComparator(false);
62
    
63
    private final boolean byPriority;
64
    
65
    private CompletionItemComparator(boolean byPriority) {
66
        this.byPriority = byPriority;
67
    }
68
    
69
    public static final Comparator<CompletionItem> get(int sortType) {
70
        if (sortType == CompletionResultSet.PRIORITY_SORT_TYPE)
71
            return BY_PRIORITY;
72
        if (sortType == CompletionResultSet.TEXT_SORT_TYPE)
73
            return ALPHABETICAL;
74
        throw new IllegalArgumentException();
75
    }
76
    
77
    public int compare(CompletionItem i1, CompletionItem i2) {
78
        if (i1 == i2)
79
            return 0;
80
        if (byPriority) {
81
            int importanceDiff = i1.getSortPriority() - i2.getSortPriority();
82
            if (importanceDiff != 0)
83
                return importanceDiff;
84
            int alphabeticalDiff = compareText(i1.getSortText(), i2.getSortText());
85
            return alphabeticalDiff;
86
        } else {
87
            int alphabeticalDiff = compareText(i1.getSortText(), i2.getSortText());
88
            if (alphabeticalDiff != 0)
89
                return alphabeticalDiff;
90
            int importanceDiff = i1.getSortPriority() - i2.getSortPriority();
91
            return importanceDiff;
92
        }
93
    }
94
    
95
    private static int compareText(CharSequence text1, CharSequence text2) {
96
        if (text1 == null)
97
            text1 = ""; //NOI18N
98
        if (text2 == null)
99
            text2 = ""; //NOI18N
100
        int len = Math.min(text1.length(), text2.length());
101
        for (int i = 0; i < len; i++) {
102
            char ch1 = text1.charAt(i);
103
            char ch2 = text2.charAt(i);
104
            if (ch1 != ch2) {
105
                return ch1 - ch2;
106
            }
107
        }
108
        return text1.length() - text2.length();
109
    }
110
111
}
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionJList.java (-40 / +66 lines)
Lines 53-60 Link Here
53
import javax.accessibility.AccessibleContext;
53
import javax.accessibility.AccessibleContext;
54
import javax.swing.*;
54
import javax.swing.*;
55
import javax.swing.text.JTextComponent;
55
import javax.swing.text.JTextComponent;
56
import org.netbeans.api.annotations.common.NonNull;
56
57
57
import org.netbeans.editor.LocaleSupport;
58
import org.netbeans.editor.LocaleSupport;
59
import org.netbeans.spi.editor.completion.CompletionController;
58
import org.netbeans.spi.editor.completion.CompletionItem;
60
import org.netbeans.spi.editor.completion.CompletionItem;
59
import org.netbeans.spi.editor.completion.LazyCompletionItem;
61
import org.netbeans.spi.editor.completion.LazyCompletionItem;
60
62
Lines 75-80 Link Here
75
    private int maxVisibleRowCount;
77
    private int maxVisibleRowCount;
76
    private JTextComponent editorComponent;
78
    private JTextComponent editorComponent;
77
    private int smartIndex;
79
    private int smartIndex;
80
    /** The current completion controller. */
81
    private CompletionController controller;
82
    /** <code>true</code> if the best match is selected, otherwise <code>false</code>. */
83
    private boolean isSelected;
78
    
84
    
79
    public CompletionJList(int maxVisibleRowCount, MouseListener mouseListener, JTextComponent editorComponent) {
85
    public CompletionJList(int maxVisibleRowCount, MouseListener mouseListener, JTextComponent editorComponent) {
80
        this.maxVisibleRowCount = maxVisibleRowCount;
86
        this.maxVisibleRowCount = maxVisibleRowCount;
Lines 91-118 Link Here
91
        setCellRenderer(new ListCellRenderer() {
97
        setCellRenderer(new ListCellRenderer() {
92
            private ListCellRenderer defaultRenderer = new DefaultListCellRenderer();
98
            private ListCellRenderer defaultRenderer = new DefaultListCellRenderer();
93
99
94
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
100
            @Override
101
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isBestMatch, boolean cellHasFocus) {
95
                if( value instanceof CompletionItem ) {
102
                if( value instanceof CompletionItem ) {
96
                    CompletionItem item = (CompletionItem)value;
103
                    CompletionItem item = (CompletionItem)value;
97
                    renderComponent.setItem(item);
104
                    renderComponent.setItem(item);
98
                    renderComponent.setSelected(isSelected);
105
                    renderComponent.setSelected(isBestMatch, isBestMatch && CompletionJList.this.isSelected);
99
                    renderComponent.setSeparator(smartIndex > 0 && smartIndex == index);
106
                    renderComponent.setSeparator(smartIndex > 0 && smartIndex == index);
100
                    Color bgColor;
107
                    Color bgColor = list.getBackground();
101
                    Color fgColor;
108
                    Color bgSelectedColor = list.getSelectionBackground();
102
                    if (isSelected) {
109
                    Color fgColor = list.getForeground();
103
                        bgColor = list.getSelectionBackground();
110
                    Color fgSelectedColor = list.getSelectionForeground();
104
                        fgColor = list.getSelectionForeground();
111
                    if ((index % 2) == 0) { // every second item slightly different
105
                    } else { // not selected
112
                        bgColor = new Color(
106
                        bgColor = list.getBackground();
113
                                Math.abs(bgColor.getRed() - DARKER_COLOR_COMPONENT),
107
                        if ((index % 2) == 0) { // every second item slightly different
114
                                Math.abs(bgColor.getGreen() - DARKER_COLOR_COMPONENT),
108
                            bgColor = new Color(
115
                                Math.abs(bgColor.getBlue() - DARKER_COLOR_COMPONENT)
109
                                    Math.abs(bgColor.getRed() - DARKER_COLOR_COMPONENT),
116
                        );
110
                                    Math.abs(bgColor.getGreen() - DARKER_COLOR_COMPONENT),
111
                                    Math.abs(bgColor.getBlue() - DARKER_COLOR_COMPONENT)
112
                            );
113
                        }
114
                        fgColor = list.getForeground();
115
                    }
117
                    }
118
119
                    renderComponent.setColors(fgColor, bgColor, fgSelectedColor, bgSelectedColor);
116
                    // quick check Component.setBackground() always fires change
120
                    // quick check Component.setBackground() always fires change
117
                    if (renderComponent.getBackground() != bgColor) {
121
                    if (renderComponent.getBackground() != bgColor) {
118
                        renderComponent.setBackground(bgColor);
122
                        renderComponent.setBackground(bgColor);
Lines 123-129 Link Here
123
                    return renderComponent;
127
                    return renderComponent;
124
128
125
                } else {
129
                } else {
126
                    return defaultRenderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus);
130
                    return defaultRenderer.getListCellRendererComponent( list, value, index, isBestMatch, cellHasFocus);
127
                }
131
                }
128
            }
132
            }
129
        });
133
        });
Lines 148-155 Link Here
148
        }
152
        }
149
    }
153
    }
150
    
154
    
151
    void setData(List data) {
155
    void setData(List data, @NonNull CompletionController controller) {
152
        smartIndex = -1;
156
        smartIndex = -1;
157
        this.controller = controller;
153
        if (data != null) {
158
        if (data != null) {
154
            int itemCount = data.size();
159
            int itemCount = data.size();
155
            ListCellRenderer renderer = getCellRenderer();
160
            ListCellRenderer renderer = getCellRenderer();
Lines 179-185 Link Here
179
            setModel(lm);
184
            setModel(lm);
180
            
185
            
181
            if (itemCount > 0) {
186
            if (itemCount > 0) {
182
                setSelectedIndex(0);
187
                setSelection(0, false);
183
            }
188
            }
184
            int visibleRowCount = Math.min(itemCount, maxVisibleRowCount);
189
            int visibleRowCount = Math.min(itemCount, maxVisibleRowCount);
185
            setVisibleRowCount(visibleRowCount);
190
            setVisibleRowCount(visibleRowCount);
Lines 214-219 Link Here
214
            updateAccessible();
219
            updateAccessible();
215
        }
220
        }
216
    }
221
    }
222
223
    public @NonNull CompletionController.Selection getSelection() {
224
        return new CompletionController.Selection(getSelectedIndex(), isSelected);
225
    }
226
227
    public void setSelection(@NonNull CompletionController.Selection selection) {
228
        setSelection(selection.getIndex(), selection.isSelected());
229
    }
230
231
    public void setSelection(int index, boolean isSelected) {
232
        this.isSelected = isSelected;
233
        setSelectedIndex(index);
234
    }
217
    
235
    
218
    private JLabel accessibleLabel;
236
    private JLabel accessibleLabel;
219
    private JLabel accessibleFakeLabel;
237
    private JLabel accessibleFakeLabel;
Lines 241-247 Link Here
241
            int idx = (getSelectedIndex() - 1 + size) % size;
259
            int idx = (getSelectedIndex() - 1 + size) % size;
242
            while(idx > 0 && getModel().getElementAt(idx) == null)
260
            while(idx > 0 && getModel().getElementAt(idx) == null)
243
                idx--;
261
                idx--;
244
            setSelectedIndex(idx);
262
            setSelection(idx, true);
245
            ensureIndexIsVisible(idx);
263
            ensureIndexIsVisible(idx);
246
        }
264
        }
247
    }
265
    }
Lines 254-260 Link Here
254
                idx++;
272
                idx++;
255
            if (idx == size)
273
            if (idx == size)
256
                idx = 0;
274
                idx = 0;
257
            setSelectedIndex(idx);
275
            setSelection(idx, true);
258
            ensureIndexIsVisible(idx);
276
            ensureIndexIsVisible(idx);
259
        }
277
        }
260
    }
278
    }
Lines 265-271 Link Here
265
            int idx = Math.max(getSelectedIndex() - pageSize, 0);
283
            int idx = Math.max(getSelectedIndex() - pageSize, 0);
266
            while(idx > 0 && getModel().getElementAt(idx) == null)
284
            while(idx > 0 && getModel().getElementAt(idx) == null)
267
                idx--;
285
                idx--;
268
            setSelectedIndex(idx);
286
            setSelection(idx, true);
269
            ensureIndexIsVisible(idx);
287
            ensureIndexIsVisible(idx);
270
        }
288
        }
271
    }
289
    }
Lines 282-295 Link Here
282
                while(idx > 0 && getModel().getElementAt(idx) == null)
300
                while(idx > 0 && getModel().getElementAt(idx) == null)
283
                    idx--;
301
                    idx--;
284
            }
302
            }
285
            setSelectedIndex(idx);
303
            setSelection(idx, true);
286
            ensureIndexIsVisible(idx);
304
            ensureIndexIsVisible(idx);
287
        }
305
        }
288
    }
306
    }
289
307
290
    public void begin() {
308
    public void begin() {
291
        if (getModel().getSize() > 0) {
309
        if (getModel().getSize() > 0) {
292
            setSelectedIndex(0);
310
            setSelection(0, true);
293
            ensureIndexIsVisible(0);
311
            ensureIndexIsVisible(0);
294
        }
312
        }
295
    }
313
    }
Lines 300-306 Link Here
300
            int idx = size - 1;
318
            int idx = size - 1;
301
            while(idx > 0 && getModel().getElementAt(idx) == null)
319
            while(idx > 0 && getModel().getElementAt(idx) == null)
302
                idx--;
320
                idx--;
303
            setSelectedIndex(idx);
321
            setSelection(idx, true);
304
            ensureIndexIsVisible(idx);
322
            ensureIndexIsVisible(idx);
305
        }
323
        }
306
    }
324
    }
Lines 323-340 Link Here
323
    }
341
    }
324
    
342
    
325
    private final class RenderComponent extends JComponent {
343
    private final class RenderComponent extends JComponent {
326
        
344
327
        private CompletionItem item;
345
        private CompletionItem item;
328
        
346
        
329
        private boolean selected;
347
        private boolean isBestMatch;
348
        private boolean isSelected;
330
        private boolean separator;
349
        private boolean separator;
350
351
        private Color fgColor;
352
        private Color bgColor;
353
        private Color fgSelectedColor;
354
        private Color bgSelectedColor;
331
        
355
        
332
        void setItem(CompletionItem item) {
356
        void setItem(CompletionItem item) {
333
            this.item = item;
357
            this.item = item;
334
        }
358
        }
335
        
359
        
336
        void setSelected(boolean selected) {
360
        void setSelected(boolean isBestMatch, boolean isSelected) {
337
            this.selected = selected;
361
            this.isBestMatch = isBestMatch;
362
            this.isSelected = isSelected;
338
        }
363
        }
339
        
364
        
340
        void setSeparator(boolean separator) {
365
        void setSeparator(boolean separator) {
Lines 349-366 Link Here
349
            // of the widest item).
374
            // of the widest item).
350
            // Therefore the item's render width is taken from the viewport's width.
375
            // Therefore the item's render width is taken from the viewport's width.
351
            int itemRenderWidth = ((JViewport)CompletionJList.this.getParent()).getWidth();
376
            int itemRenderWidth = ((JViewport)CompletionJList.this.getParent()).getWidth();
352
            Color bgColor = getBackground();
353
            Color fgColor = getForeground();
354
            int height = getHeight();
377
            int height = getHeight();
355
378
356
            // Clear the background
357
            g.setColor(bgColor);
358
            g.fillRect(0, 0, itemRenderWidth, height);
359
            g.setColor(fgColor);
360
361
            // Render the item
379
            // Render the item
362
            item.render(g, CompletionJList.this.getFont(), getForeground(), bgColor,
380
            controller.render(g, CompletionJList.this.getFont(), fgColor, bgColor,
363
                    itemRenderWidth, getHeight(), selected);
381
                    fgSelectedColor, bgSelectedColor, itemRenderWidth, getHeight(),
382
                    item, isBestMatch, isSelected);
364
            
383
            
365
            if (separator) {
384
            if (separator) {
366
                g.setColor(Color.gray);
385
                g.setColor(Color.gray);
Lines 368-374 Link Here
368
                g.setColor(fgColor);
387
                g.setColor(fgColor);
369
            }
388
            }
370
        }
389
        }
371
        
390
372
        public @Override Dimension getPreferredSize() {
391
        public @Override Dimension getPreferredSize() {
373
            if (cellPreferredSizeGraphics == null) {
392
            if (cellPreferredSizeGraphics == null) {
374
                // CompletionJList.this.getGraphics() is null
393
                // CompletionJList.this.getGraphics() is null
Lines 381-386 Link Here
381
                    fixedItemHeight);
400
                    fixedItemHeight);
382
        }
401
        }
383
402
403
        private void setColors(Color fgColor, Color bgColor, Color fgSelectedColor, Color bgSelectedColor) {
404
            this.fgColor = fgColor;
405
            this.bgColor = bgColor;
406
            this.fgSelectedColor = fgSelectedColor;
407
            this.bgSelectedColor = bgSelectedColor;
408
        }
409
384
    }
410
    }
385
411
386
}
412
}
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java (-9 / +14 lines)
Lines 71-79 Link Here
71
import javax.swing.event.ListSelectionListener;
71
import javax.swing.event.ListSelectionListener;
72
import javax.swing.text.Document;
72
import javax.swing.text.Document;
73
import javax.swing.text.JTextComponent;
73
import javax.swing.text.JTextComponent;
74
import org.netbeans.api.annotations.common.CheckForNull;
74
import org.netbeans.editor.GuardedDocument;
75
import org.netbeans.editor.GuardedDocument;
76
import org.netbeans.spi.editor.completion.CompletionController;
75
import org.netbeans.spi.editor.completion.CompletionDocumentation;
77
import org.netbeans.spi.editor.completion.CompletionDocumentation;
76
import org.netbeans.spi.editor.completion.CompletionItem;
77
import org.openide.text.CloneableEditorSupport;
78
import org.openide.text.CloneableEditorSupport;
78
import org.openide.util.NbBundle;
79
import org.openide.util.NbBundle;
79
80
Lines 138-145 Link Here
138
    }
139
    }
139
140
140
    public void showCompletion(List data, String title, int anchorOffset,
141
    public void showCompletion(List data, String title, int anchorOffset,
141
    ListSelectionListener listSelectionListener, String additionalItemsText, String shortcutHint, int selectedIndex) {
142
    ListSelectionListener listSelectionListener, String additionalItemsText,
142
        completionPopup.show(data, title, anchorOffset, listSelectionListener, additionalItemsText, shortcutHint, selectedIndex);
143
    String shortcutHint, CompletionController controller,
144
    CompletionController.Selection selection) {
145
        completionPopup.show(data, title, anchorOffset, listSelectionListener, additionalItemsText, shortcutHint, controller, selection);
143
        if (!visiblePopups.contains(completionPopup))
146
        if (!visiblePopups.contains(completionPopup))
144
            visiblePopups.push(completionPopup);
147
            visiblePopups.push(completionPopup);
145
    }
148
    }
Lines 159-165 Link Here
159
        return completionPopup.isVisible();
162
        return completionPopup.isVisible();
160
    }
163
    }
161
    
164
    
162
    public CompletionItem getSelectedCompletionItem() {
165
    public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
163
        return completionPopup.getSelectedCompletionItem();
166
        return completionPopup.getSelectedCompletionItem();
164
    }
167
    }
165
    
168
    
Lines 305-311 Link Here
305
        private CompletionScrollPane completionScrollPane;
308
        private CompletionScrollPane completionScrollPane;
306
        
309
        
307
        public void show(List data, String title, int anchorOffset,
310
        public void show(List data, String title, int anchorOffset,
308
        ListSelectionListener listSelectionListener, String additionalItemsText, String shortcutHint, int selectedIndex) {
311
        ListSelectionListener listSelectionListener, String additionalItemsText,
312
        String shortcutHint, final CompletionController controller,
313
        CompletionController.Selection selection) {
309
            
314
            
310
	    JTextComponent editorComponent = getEditorComponent();
315
	    JTextComponent editorComponent = getEditorComponent();
311
	    if (editorComponent == null) {
316
	    if (editorComponent == null) {
Lines 330-336 Link Here
330
			    JTextComponent c = getEditorComponent();
335
			    JTextComponent c = getEditorComponent();
331
                            if (SwingUtilities.isLeftMouseButton(evt)) {
336
                            if (SwingUtilities.isLeftMouseButton(evt)) {
332
                                if (c != null && evt.getClickCount() == 2 ) {
337
                                if (c != null && evt.getClickCount() == 2 ) {
333
                                    CompletionItem selectedItem
338
                                    SelectedCompletionItem selectedItem
334
                                            = completionScrollPane.getSelectedCompletionItem();
339
                                            = completionScrollPane.getSelectedCompletionItem();
335
                                    if (selectedItem != null) {
340
                                    if (selectedItem != null) {
336
                                        Document doc = c.getDocument();
341
                                        Document doc = c.getDocument();
Lines 342-348 Link Here
342
                                            CompletionImpl.uilog(r);
347
                                            CompletionImpl.uilog(r);
343
                                            CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
348
                                            CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.BEGIN_COMMIT_GROUP);
344
                                            try {
349
                                            try {
345
                                                selectedItem.defaultAction(c);
350
                                                controller.defaultAction(selectedItem.getItem(), selectedItem.isSelected());
346
                                            } finally {
351
                                            } finally {
347
                                                CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
352
                                                CompletionImpl.sendUndoableEdit(doc, CloneableEditorSupport.END_COMMIT_GROUP);
348
                                            }
353
                                            }
Lines 372-378 Link Here
372
            }
377
            }
373
            // Set the new data
378
            // Set the new data
374
            getPreferredSize();
379
            getPreferredSize();
375
            completionScrollPane.setData(data, title, selectedIndex);
380
            completionScrollPane.setData(data, title, controller, selection);
376
            setAnchorOffset(anchorOffset);
381
            setAnchorOffset(anchorOffset);
377
382
378
            Dimension prefSize = getPreferredSize();
383
            Dimension prefSize = getPreferredSize();
Lines 395-401 Link Here
395
            } // otherwise present popup size will be retained
400
            } // otherwise present popup size will be retained
396
        }
401
        }
397
        
402
        
398
        public CompletionItem getSelectedCompletionItem() {
403
        public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
399
            return isVisible() ? completionScrollPane.getSelectedCompletionItem() : null;
404
            return isVisible() ? completionScrollPane.getSelectedCompletionItem() : null;
400
        }
405
        }
401
406
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionResultSetImpl.java (-4 / +4 lines)
Lines 213-219 Link Here
213
    
213
    
214
    public synchronized void setHasAdditionalItems(boolean value) {
214
    public synchronized void setHasAdditionalItems(boolean value) {
215
        checkNotFinished();
215
        checkNotFinished();
216
        if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
216
        if ((queryType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
217
            return;
217
            return;
218
        }
218
        }
219
        this.hasAdditionalItems = value;
219
        this.hasAdditionalItems = value;
Lines 225-231 Link Here
225
    
225
    
226
    public synchronized void setHasAdditionalItemsText(String text) {
226
    public synchronized void setHasAdditionalItemsText(String text) {
227
        checkNotFinished();
227
        checkNotFinished();
228
        if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
228
        if ((queryType & CompletionProvider.COMPLETION_ALL_QUERY_TYPE) == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) {
229
            return;
229
            return;
230
        }
230
        }
231
        this.hasAdditionalItemsText = text;
231
        this.hasAdditionalItemsText = text;
Lines 237-243 Link Here
237
237
238
    public synchronized void setDocumentation(CompletionDocumentation documentation) {
238
    public synchronized void setDocumentation(CompletionDocumentation documentation) {
239
        checkNotFinished();
239
        checkNotFinished();
240
        if (!active || queryType != CompletionProvider.DOCUMENTATION_QUERY_TYPE) {
240
        if (!active || (queryType & CompletionProvider.DOCUMENTATION_QUERY_TYPE) != CompletionProvider.DOCUMENTATION_QUERY_TYPE) {
241
            return;
241
            return;
242
        }
242
        }
243
        this.documentation = documentation;
243
        this.documentation = documentation;
Lines 253-259 Link Here
253
    
253
    
254
    public synchronized void setToolTip(JToolTip toolTip) {
254
    public synchronized void setToolTip(JToolTip toolTip) {
255
        checkNotFinished();
255
        checkNotFinished();
256
        if (!active || queryType != CompletionProvider.TOOLTIP_QUERY_TYPE) {
256
        if (!active || (queryType & CompletionProvider.TOOLTIP_QUERY_TYPE) != CompletionProvider.TOOLTIP_QUERY_TYPE) {
257
            return;
257
            return;
258
        }
258
        }
259
        this.toolTip = toolTip;
259
        this.toolTip = toolTip;
(-)a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionScrollPane.java (-6 / +16 lines)
Lines 65-72 Link Here
65
import javax.swing.text.JTextComponent;
65
import javax.swing.text.JTextComponent;
66
import javax.swing.text.Keymap;
66
import javax.swing.text.Keymap;
67
import javax.swing.text.EditorKit;
67
import javax.swing.text.EditorKit;
68
import org.netbeans.api.annotations.common.CheckForNull;
68
import org.netbeans.editor.BaseKit;
69
import org.netbeans.editor.BaseKit;
69
import org.netbeans.editor.ext.ExtKit;
70
import org.netbeans.editor.ext.ExtKit;
71
import org.netbeans.spi.editor.completion.CompletionController;
70
import org.netbeans.spi.editor.completion.CompletionItem;
72
import org.netbeans.spi.editor.completion.CompletionItem;
71
73
72
/**
74
/**
Lines 122-132 Link Here
122
        installKeybindings(editorComponent);
124
        installKeybindings(editorComponent);
123
    }
125
    }
124
    
126
    
125
    public void setData(List data, String title, int selectedIndex) {
127
    public void setData(List data,
128
                        String title,
129
                        CompletionController controller,
130
                        CompletionController.Selection selection) {
126
        dataObj = data;
131
        dataObj = data;
127
        view.setData(data);
132
        view.setData(data, controller);
128
        view.setSelectedIndex(selectedIndex);
133
        view.setSelection(selection);
129
        Rectangle r = view.getCellBounds(selectedIndex, selectedIndex);
134
        Rectangle r = view.getCellBounds(selection.getIndex(), selection.getIndex());
130
        if (r != null)
135
        if (r != null)
131
            view.scrollRectToVisible(r);
136
            view.scrollRectToVisible(r);
132
        setTitle(title);
137
        setTitle(title);
Lines 139-147 Link Here
139
        setViewportView(getViewport().getView());
144
        setViewportView(getViewport().getView());
140
    }
145
    }
141
    
146
    
142
    public CompletionItem getSelectedCompletionItem() {
147
    public @CheckForNull SelectedCompletionItem getSelectedCompletionItem() {
143
        Object ret = view.getSelectedValue();
148
        Object ret = view.getSelectedValue();
144
        return ret instanceof CompletionItem ? (CompletionItem) ret : null;
149
        if (ret instanceof CompletionItem) {
150
            boolean isSelected = view.getSelection().isSelected();
151
            return new SelectedCompletionItem((CompletionItem)ret, isSelected);
152
        }
153
154
        return null;
145
    }
155
    }
146
    
156
    
147
    public int getSelectedIndex() {
157
    public int getSelectedIndex() {
(-)81cafa2674cb (+62 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.editor.completion;
43
44
import javax.swing.text.JTextComponent;
45
import org.netbeans.spi.editor.completion.BaseCompletionController;
46
import org.netbeans.spi.editor.completion.CompletionController;
47
import org.netbeans.spi.editor.completion.CompletionControllerProvider;
48
import org.netbeans.spi.editor.completion.CompletionTask;
49
50
/**
51
 *
52
 * @author Sam Harwell
53
 */
54
public class DefaultCompletionControllerProvider implements CompletionControllerProvider {
55
    public static final DefaultCompletionControllerProvider INSTANCE = new DefaultCompletionControllerProvider();
56
57
    @Override
58
    public CompletionController createController(JTextComponent component, CompletionTask task, int queryType) {
59
        return new BaseCompletionController(component, queryType);
60
    }
61
62
}
(-)81cafa2674cb (+66 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.editor.completion;
43
44
import org.netbeans.spi.editor.completion.CompletionItem;
45
46
/**
47
 *
48
 * @author Sam Harwell
49
 */
50
public final class SelectedCompletionItem {
51
    private final CompletionItem item;
52
    private final boolean selected;
53
54
    public SelectedCompletionItem(CompletionItem item, boolean selected) {
55
        this.item = item;
56
        this.selected = selected;
57
    }
58
59
    public CompletionItem getItem() {
60
        return item;
61
    }
62
63
    public boolean isSelected() {
64
        return selected;
65
    }
66
}
(-)81cafa2674cb (+225 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.spi.editor.completion;
43
44
import java.awt.Color;
45
import java.awt.Font;
46
import java.awt.Graphics;
47
import java.awt.event.KeyEvent;
48
import java.util.Collections;
49
import java.util.List;
50
import javax.swing.text.BadLocationException;
51
import javax.swing.text.Document;
52
import javax.swing.text.JTextComponent;
53
import org.netbeans.api.annotations.common.CheckForNull;
54
import org.netbeans.api.annotations.common.NonNull;
55
import org.netbeans.api.annotations.common.NullAllowed;
56
import org.netbeans.editor.BaseDocument;
57
import org.netbeans.editor.Utilities;
58
import org.openide.util.Parameters;
59
60
/**
61
 *
62
 * @author Sam Harwell
63
 */
64
public class BaseCompletionController implements CompletionController {
65
    private final JTextComponent component;
66
    private final int queryType;
67
68
    /**
69
     *
70
     * @param component The active component.
71
     * @param queryType The query type.
72
     *
73
     * @throws NullPointerException if the parameter value is <code>null</code>.
74
     */
75
    public BaseCompletionController(@NonNull JTextComponent component,
76
                                    int queryType) {
77
        Parameters.notNull("component", component);
78
        this.component = component;
79
        this.queryType = queryType;
80
    }
81
82
83
    /**
84
     * Gets the active {@link JTextComponent}.
85
     *
86
     * @return The active component.
87
     */
88
    public @NonNull JTextComponent getComponent() {
89
        return component;
90
    }
91
92
    /**
93
     * Gets the active {@link Document}.
94
     *
95
     * @return The active document.
96
     */
97
    public Document getDocument() {
98
        return getComponent().getDocument();
99
    }
100
101
    @Override
102
    public void sortItems(List<? extends CompletionItem> items, int sortType) {
103
        Collections.sort(items, CompletionItemComparator.get(sortType));
104
    }
105
106
    @Override
107
    public Selection getSelection(List<? extends CompletionItem> items) {
108
        String prefix = getCompletionPrefix();
109
        if (prefix != null && prefix.length() > 0) {
110
            for (int idx = 0; idx < items.size(); idx++) {
111
                CompletionItem item = items.get(idx);
112
                CharSequence text = item.getInsertPrefix();
113
                if (text != null && text.toString().startsWith(prefix)) {
114
                    boolean selected = isSelected(items, prefix, idx);
115
                    boolean unique = isUnique(items, prefix, idx);
116
                    return new Selection(idx, selected, unique);
117
                }
118
            }
119
        }
120
121
        /* This follows existing behavior, which is slightly different from
122
         * Selection.DEFAULT because this method marks the item as selected.
123
         */
124
        return new Selection(0);
125
    }
126
127
    @Override
128
    public void defaultAction(CompletionItem bestMatch, boolean isSelected) {
129
        if (isSelected) {
130
            bestMatch.defaultAction(component);
131
        }
132
    }
133
134
    @Override
135
    public void processKeyEvent(KeyEvent evt, CompletionItem bestMatch, boolean isSelected) {
136
        bestMatch.processKeyEvent(evt);
137
    }
138
139
    @Override
140
    public void render(Graphics g, Font defaultFont, Color foregroundColor,
141
    Color backgroundColor, Color selectedForegroundColor,
142
    Color selectedBackgroundColor, int width, int height, CompletionItem item, boolean isBestMatch, boolean isSelected) {
143
        if (isBestMatch) {
144
            // Clear the background
145
            g.setColor(selectedBackgroundColor);
146
            g.fillRect(0, 0, width, height);
147
            g.setColor(selectedForegroundColor);
148
            item.render(g, defaultFont, selectedForegroundColor, selectedBackgroundColor, width, height, isBestMatch);
149
        } else {
150
            // Clear the background
151
            g.setColor(backgroundColor);
152
            g.fillRect(0, 0, width, height);
153
            g.setColor(foregroundColor);
154
            item.render(g, defaultFont, foregroundColor, backgroundColor, width, height, isBestMatch);
155
        }
156
    }
157
158
    @Override
159
    public boolean instantSubstitution(CompletionItem uniqueMatch) {
160
        return uniqueMatch.instantSubstitution(component);
161
    }
162
163
    /**
164
     * Gets the current completion prefix. The default implementation returns the
165
     * text of the current identifier (per {@link Utilities#getIdentifierBlock})
166
     * up to the location of the caret.
167
     *
168
     * @return The completion prefix.
169
     */
170
    protected @CheckForNull String getCompletionPrefix() {
171
        if(getDocument() instanceof BaseDocument) {
172
            BaseDocument doc = (BaseDocument)getDocument();
173
            int caretOffset = getComponent().getSelectionStart();
174
            try {
175
                int[] block = Utilities.getIdentifierBlock(doc, caretOffset);
176
                if (block != null) {
177
                    block[1] = caretOffset;
178
                    return doc.getText(block);
179
                }
180
            } catch (BadLocationException ble) {
181
            }
182
        }
183
184
        return null;
185
    }
186
187
    /**
188
     *
189
     * @param items
190
     * @param prefix
191
     * @param index
192
     *
193
     * @return <code>true</code> if the item is selected, otherwise <code>false</code>.
194
     */
195
    protected boolean isSelected(@NonNull List<? extends CompletionItem> items,
196
                                 @NullAllowed String prefix,
197
                                 int index) {
198
        return true;
199
    }
200
201
    /**
202
     *
203
     * @param items
204
     * @param prefix
205
     * @param index
206
     *
207
     * @return <code>true</code> if the selection is unique, otherwise <code>false</code>.
208
     */
209
    protected boolean isUnique(@NonNull List<? extends CompletionItem> items,
210
                               @NullAllowed String prefix,
211
                               int index) {
212
        if (items.size() != 1) {
213
            return false;
214
        }
215
216
        try {
217
            int caretOffset = getComponent().getSelectionStart();
218
            int[] block = Utilities.getIdentifierBlock(getComponent(),
219
                       getComponent().getSelectionStart());
220
            return block == null || block[1] == caretOffset;
221
        } catch (BadLocationException ble) {
222
            return false;
223
        }
224
    }
225
}
(-)81cafa2674cb (+236 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.spi.editor.completion;
43
44
import java.awt.Color;
45
import java.awt.Font;
46
import java.awt.Graphics;
47
import java.awt.event.KeyEvent;
48
import java.util.List;
49
import org.netbeans.api.annotations.common.NonNull;
50
51
/**
52
 * This interface controls the sorting and selection behavior of the Code
53
 * Completion drop down.
54
 *
55
 * @author Sam Harwell
56
 */
57
public interface CompletionController {
58
59
    /**
60
     * Sorts the specified list of CompletionItem items.
61
     *
62
     * @param items The list of items to sort.
63
     * @param sortType The desired sort type, one of
64
     *  {@link CompletionResultSet#PRIORITY_SORT_TYPE} or
65
     *  {@link CompletionResultSet#TEXT_SORT_TYPE}.
66
     */
67
    void sortItems(@NonNull List<? extends CompletionItem> items, int sortType);
68
69
    /**
70
     * Gets the initial selected item from a list of CompletionItem items shown
71
     * in a code completion drop down. The initial selection represents a "best
72
     * match" among the available items.
73
     *
74
     * @param items A list of all CompletionItem items shown in the code
75
     *  completion drop down.
76
     *
77
     * @return A {@link Selection} object containing information about the
78
     *  initial selection.
79
     */
80
    @NonNull Selection getSelection(@NonNull List<? extends CompletionItem> items);
81
82
    /**
83
     * Gets invoked when user presses <code>VK_ENTER</code> key
84
     * or when she double-clicks on this item with the mouse cursor.
85
     * <br/>
86
     * This method gets invoked from AWT thread.
87
     *
88
     * @param bestMatch non-null completion item for which the action is invoked
89
     * @param isSelected whether or not the best match is currently selected
90
     */
91
    void defaultAction(@NonNull CompletionItem bestMatch, boolean isSelected);
92
93
    /**
94
     * Process the key pressed when this completion item was selected
95
     * in the completion popup window.
96
     * <br/>
97
     * This method gets invoked from AWT thread.
98
     *
99
     * @param evt non-null key event of the pressed key. It should be consumed
100
     *  in case the item is sensitive to the given key. The source of this
101
     *  event is the text component to which the corresponding action should
102
     *  be performed.
103
     * @param bestMatch non-null completion item which is the current best match
104
     * @param isSelected whether or not the best match is currently selected
105
     */
106
    void processKeyEvent(@NonNull KeyEvent evt, @NonNull CompletionItem bestMatch, boolean isSelected);
107
108
    /**
109
     * Render this item into the given graphics.
110
     *
111
     * @param g graphics to render the item into.
112
     * @param defaultFont default font used for rendering.
113
     * @param foregroundColor foreground color used for rendering.
114
     * @param backgroundColor color used for background.
115
     * @param selectedForegroundColor foreground color used for rendering selected items.
116
     * @param selectedBackgroundColor color used for background selected items.
117
     * @param width width of the area to render into.
118
     * @param height height of the are to render into.
119
     * @param item non-null completion item to render.
120
     * @param isBestMatch true if this item is the best match.
121
     * @param isSelected true if this item is selected.
122
     */
123
    void render(@NonNull Graphics g, @NonNull Font defaultFont, @NonNull Color foregroundColor,
124
    @NonNull Color backgroundColor, @NonNull Color selectedForegroundColor,
125
    @NonNull Color selectedBackgroundColor, int width, int height, @NonNull CompletionItem item,
126
    boolean isBestMatch, boolean isSelected);
127
128
    /**
129
     * When enabled for the item the instant substitution should process the item
130
     * in the same way like when the item is displayed and Enter key gets pressed
131
     * by the user.
132
     * <br>
133
     * Instant substitution is invoked when there would be just a single item
134
     * displayed in the completion popup window.
135
     * <br>
136
     * The implementation can invoke the {@link #defaultAction(JTextComponent)}
137
     * if necessary.
138
     * <br/>
139
     * This method gets invoked from AWT thread.
140
     *
141
     * @param uniqueMatch non-null unique completion item to perform the instant
142
     *  substitution.
143
     * @return <code>true</code> if the instant substitution was successfully done.
144
     *  <code>false</code> means that the instant substitution should not be done
145
     *  for this item and the completion item should normally be displayed.
146
     */
147
    boolean instantSubstitution(@NonNull CompletionItem uniqueMatch);
148
149
    /**
150
     * Represents an initial selected CompletionItem for code completion. This
151
     * item can be seen as the best match for a given input.
152
     */
153
    public static final class Selection {
154
        /**
155
         * The default selected item. The item has index 0 and is not selected
156
         * or unique.
157
         */
158
        public static final Selection DEFAULT = new Selection(0, false, false);
159
160
        private final int index;
161
        private final boolean selected;
162
        private final boolean unique;
163
164
        /**
165
         * Initializes a Selection with the specified index. The item is selected
166
         * but not unique.
167
         *
168
         * @param index The index of the selected CompletionItem.
169
         *
170
         * @throws IllegalArgumentException when the index argument is less than zero.
171
         */
172
        public Selection(int index) {
173
            this(index, true, false);
174
        }
175
176
        /**
177
         * Initializes a Selection with the specified index and selected state.
178
         * The item is not unique.
179
         *
180
         * @param index The index of the selected CompletionItem.
181
         * @param selected <code>true</code> if the match is selected, otherwise
182
         *  <code>false</code>.
183
         *
184
         * @throws IllegalArgumentException when the index argument is less than zero.
185
         */
186
        public Selection(int index, boolean selected) {
187
            this(index, selected, false);
188
        }
189
190
        /**
191
         * Initializes a Selection with the specified index, selected state, and
192
         * uniqueness.
193
         *
194
         * @param index The index of the selected CompletionItem.
195
         * @param selected <code>true</code> if the match is selected, otherwise
196
         *  <code>false</code>.
197
         * @param unique <code>true</code> if the match is unique, otherwise
198
         *  <code>false</code>.
199
         * 
200
         * @throws IllegalArgumentException when the index argument is less than zero.
201
         */
202
        public Selection(int index, boolean selected, boolean unique) {
203
            if (index < 0) {
204
                throw new IllegalArgumentException("The index cannot be negative."); // NOI18N
205
            }
206
207
            this.index = index;
208
            this.selected = selected;
209
            this.unique = unique;
210
        }
211
212
        /**
213
         *
214
         * @return The index of the selected CompletionItem.
215
         */
216
        public int getIndex() {
217
            return index;
218
        }
219
220
        /**
221
         *
222
         * @return <code>true</code> if the match is selected, otherwise <code>false</code>.
223
         */
224
        public boolean isSelected() {
225
            return selected;
226
        }
227
228
        /**
229
         *
230
         * @return <code>true</code> if the match is unique, otherwise <code>false</code>.
231
         */
232
        public boolean isUnique() {
233
            return unique;
234
        }
235
    }
236
}
(-)81cafa2674cb (+73 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.spi.editor.completion;
43
44
import javax.swing.text.JTextComponent;
45
import org.netbeans.api.annotations.common.CheckForNull;
46
import org.netbeans.api.annotations.common.NonNull;
47
import org.netbeans.spi.editor.mimelookup.MimeLocation;
48
49
/**
50
 *
51
 * @author Sam Harwell
52
 */
53
@MimeLocation(subfolderName="CompletionProviders")
54
public interface CompletionControllerProvider {
55
56
    /**
57
     * Creates a {@link CompletionController} which provides behavior for the
58
     * code completion drop down.
59
     * 
60
     * @param component The active component.
61
     * @param task The completion task.
62
     * @param queryType The completion query type.
63
     *
64
     * @return A {@link CompletionController} to provide behavior for the completion drop
65
     *  down, or <code>null</code> if this provider does not support the specified
66
     *  component, task, or query type.
67
     */
68
    public @CheckForNull CompletionController createController(
69
        @NonNull JTextComponent component,
70
        @NonNull CompletionTask task,
71
        int queryType);
72
73
}
(-)81cafa2674cb (+195 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
31
 * Microsystems, Inc. All Rights Reserved.
32
 *
33
 * If you wish your version of this file to be governed by only the CDDL
34
 * or only the GPL Version 2, indicate your decision by adding
35
 * "[Contributor] elects to include this software in this distribution
36
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
37
 * single choice of license, a recipient has the option to distribute
38
 * your version of this file under either the CDDL, the GPL Version 2 or
39
 * to extend the choice of license to its licensees as provided above.
40
 * However, if you add GPL Version 2 code and therefore, elected the GPL
41
 * Version 2 license, then the option applies only if the new code is
42
 * made subject to such option by the copyright holder.
43
 */
44
45
package org.netbeans.spi.editor.completion;
46
47
import java.util.Comparator;
48
import org.netbeans.api.annotations.common.NonNull;
49
import org.openide.util.Parameters;
50
51
/**
52
 * Comparator for completion items either by sort priority or by sort text.
53
 *
54
 * @author Dusan Balek, Miloslav Metelka
55
 */
56
57
public class CompletionItemComparator implements Comparator<CompletionItem> {
58
59
    /**
60
     * A Comparator which sorts CompletionItem items by priority, then alphabetically.
61
     */
62
    public static final Comparator<CompletionItem> BY_PRIORITY =
63
        new CompletionItemComparator(new PriorityComparator(), new TextComparator());
64
65
    /**
66
     * A Comparator which sorts CompletionItem items alphabetically, then by priority.
67
     */
68
    public static final Comparator<CompletionItem> ALPHABETICAL =
69
        new CompletionItemComparator(new TextComparator(), new PriorityComparator());
70
71
    private final Comparator<CompletionItem> primaryComparator;
72
    private final Comparator<CompletionItem> secondaryComparator;
73
    
74
    /**
75
     * Constructs a CompletionItemComparator from the specified primary and secondary
76
     * comparators.
77
     *
78
     * @param primaryComparator non-null primary comparator.
79
     * @param secondaryComparator non-null secondary comparator.
80
     */
81
    public CompletionItemComparator(@NonNull Comparator<CompletionItem> primaryComparator,
82
                                    @NonNull Comparator<CompletionItem> secondaryComparator) {
83
        Parameters.notNull("primaryComparator", primaryComparator);
84
        Parameters.notNull("secondaryComparator", secondaryComparator);
85
        this.primaryComparator = primaryComparator;
86
        this.secondaryComparator = secondaryComparator;
87
    }
88
    
89
    /**
90
     * Gets a default comparator that can be used for sorting CompletionItem lists
91
     * for the specified sort type.
92
     *
93
     * @param sortType The sort type, one of {@link CompletionResultSet#PRIORITY_SORT_TYPE}
94
     *  or {@link CompletionResultSet#TEXT_SORT_TYPE}.
95
     *
96
     * @return The Comparator to use when sorting CompletionItem items.
97
     *
98
     * @throws IllegalArgumentException the sortType argument is not a supported type.
99
     */
100
    public static Comparator<CompletionItem> get(int sortType) {
101
        if (sortType == CompletionResultSet.PRIORITY_SORT_TYPE)
102
            return BY_PRIORITY;
103
104
        if (sortType == CompletionResultSet.TEXT_SORT_TYPE)
105
            return ALPHABETICAL;
106
107
        throw new IllegalArgumentException();
108
    }
109
    
110
    @Override
111
    public int compare(CompletionItem i1, CompletionItem i2) {
112
        if (i1 == i2)
113
            return 0;
114
115
        int primaryDiff = primaryComparator.compare(i1, i2);
116
        if (primaryDiff != 0) {
117
            return primaryDiff;
118
        }
119
120
        return secondaryComparator.compare(i1, i2);
121
    }
122
123
    /**
124
     * A comparator which compares CompletionItem items by priority.
125
     *
126
     * @see CompletionItem#getSortPriority()
127
     */
128
    protected static class PriorityComparator implements Comparator<CompletionItem> {
129
130
        /**
131
         * Initializes a PriorityComparator.
132
         */
133
        public PriorityComparator() {
134
        }
135
136
        @Override
137
        public int compare(CompletionItem o1, CompletionItem o2) {
138
            if (o1 == o2) {
139
                return 0;
140
            }
141
142
            return o1.getSortPriority() - o2.getSortPriority();
143
        }
144
145
    }
146
147
    /**
148
     * A Comparator which compares CompletionItem items by text.
149
     *
150
     * @see CompletionItem#getSortText()
151
     */
152
    protected static class TextComparator implements Comparator<CompletionItem> {
153
154
        /**
155
         * Initializes a TextComparator.
156
         */
157
        public TextComparator() {
158
        }
159
160
        @Override
161
        public int compare(CompletionItem o1, CompletionItem o2) {
162
            return compareText(o1.getSortText(), o2.getSortText());
163
        }
164
165
        /**
166
         * Compares two CharSequence objects for order.
167
         *
168
         * @param text1 the first text to be compared
169
         * @param text2 the second text to be compared
170
         * @return a negative integer, zero, or a positive integer as the
171
         * 	       first argument is less than, equal to, or greater than the
172
         *	       second.
173
         */
174
        protected int compareText(CharSequence text1, CharSequence text2) {
175
            if (text1 == null)
176
                text1 = ""; //NOI18N
177
178
            if (text2 == null)
179
                text2 = ""; //NOI18N
180
181
            int len = Math.min(text1.length(), text2.length());
182
            for (int i = 0; i < len; i++) {
183
                char ch1 = text1.charAt(i);
184
                char ch2 = text2.charAt(i);
185
                if (ch1 != ch2) {
186
                    return ch1 - ch2;
187
                }
188
            }
189
190
            return text1.length() - text2.length();
191
        }
192
193
    }
194
195
}
(-)a/editor.completion/src/org/netbeans/spi/editor/completion/CompletionProvider.java (-4 / +19 lines)
Lines 67-88 Link Here
67
    /**
67
    /**
68
     * The <code>int</code> value representing the query for a code completion.
68
     * The <code>int</code> value representing the query for a code completion.
69
     */
69
     */
70
    public static final int COMPLETION_QUERY_TYPE = 1;
70
    public static final int COMPLETION_QUERY_TYPE = 0x01;
71
71
72
    /**
72
    /**
73
     * The <code>int</code> value representing the query for a documentation.
73
     * The <code>int</code> value representing the query for a documentation.
74
     */    
74
     */    
75
    public static final int DOCUMENTATION_QUERY_TYPE = 2;
75
    public static final int DOCUMENTATION_QUERY_TYPE = 0x02;
76
    
76
    
77
    /**
77
    /**
78
     * The <code>int</code> value representing the query for a tooltip hint.
78
     * The <code>int</code> value representing the query for a tooltip hint.
79
     */    
79
     */    
80
    public static final int TOOLTIP_QUERY_TYPE = 4;
80
    public static final int TOOLTIP_QUERY_TYPE = 0x04;
81
81
82
    /**
82
    /**
83
     * The <code>int</code> value representing the query for an all code completion.
83
     * The <code>int</code> value representing the query for an all code completion.
84
     */
84
     */
85
    public static final int COMPLETION_ALL_QUERY_TYPE = 9;
85
    public static final int COMPLETION_ALL_QUERY_TYPE = 0x11;
86
87
    /**
88
     * The <code>int</code> mask representing the bits used for a completion query type.
89
     */
90
    public static final int COMPLETION_QUERY_MASK = COMPLETION_QUERY_TYPE | COMPLETION_ALL_QUERY_TYPE;
91
92
    /**
93
     * The <code>int</code> mask of bits a user can specify to customize the query type.
94
     */
95
    public static final int USER_QUERY_MASK = 0xFFFF0000;
96
97
    /**
98
     * The <code>int</code> mask of bits used by the API to specify the query type.
99
     */
100
    public static final int RESERVED_QUERY_MASK = ~USER_QUERY_MASK;
86
101
87
    /**
102
    /**
88
     * Creates a task that performs a query of the given type on the given component.
103
     * 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 (-2 / +23 lines)
Lines 45-50 Link Here
45
package org.netbeans.spi.editor.completion;
45
package org.netbeans.spi.editor.completion;
46
46
47
import java.util.Collection;
47
import java.util.Collection;
48
import java.util.Collections;
49
import java.util.List;
48
import javax.swing.JToolTip;
50
import javax.swing.JToolTip;
49
import org.netbeans.modules.editor.completion.CompletionResultSetImpl;
51
import org.netbeans.modules.editor.completion.CompletionResultSetImpl;
50
import org.netbeans.modules.editor.completion.CompletionSpiPackageAccessor;
52
import org.netbeans.modules.editor.completion.CompletionSpiPackageAccessor;
Lines 101-119 Link Here
101
    }
103
    }
102
104
103
    /**
105
    /**
104
     * Set the document offset to which the returned completion items
106
     * Get the document offset to which the returned completion items,
105
     * or documentation or tooltip should be anchored.
107
     * documentation, or tool tip should be anchored.
106
     * <br>
108
     * <br>
107
     * If there will be multiple completion providers setting this property
109
     * If there will be multiple completion providers setting this property
108
     * for the given mime-type then only the first one
110
     * for the given mime-type then only the first one
109
     * (according to the xml-layer registration order)
111
     * (according to the xml-layer registration order)
110
     * will be taken into account.
112
     * will be taken into account.
113
     * @return
114
     */
115
    public int getAnchorOffset() {
116
        return impl.getAnchorOffset();
117
    }
118
119
    /**
120
     * Set the document offset to which the returned completion items
121
     * or documentation or tooltip should be anchored.
122
     *
123
     * @see #getAnchorOffset()
111
     */
124
     */
112
    public void setAnchorOffset(int anchorOffset) {
125
    public void setAnchorOffset(int anchorOffset) {
113
        impl.setAnchorOffset(anchorOffset);
126
        impl.setAnchorOffset(anchorOffset);
114
    }
127
    }
115
128
116
    /**
129
    /**
130
     * Gets an unmodifiable list of completion items in this result set.
131
     * @return
132
     */
133
    public List<? extends CompletionItem> getItems() {
134
        return Collections.unmodifiableList(impl.getItems());
135
    }
136
137
    /**
117
     * Add the completion item to this result set.
138
     * Add the completion item to this result set.
118
     * <br>
139
     * <br>
119
     * This method can be called multiple times until
140
     * This method can be called multiple times until
(-)a/editor.completion/src/org/netbeans/spi/editor/completion/support/AsyncCompletionTask.java (-2 / +23 lines)
Lines 47-52 Link Here
47
import javax.swing.SwingUtilities;
47
import javax.swing.SwingUtilities;
48
import javax.swing.text.Document;
48
import javax.swing.text.Document;
49
import javax.swing.text.JTextComponent;
49
import javax.swing.text.JTextComponent;
50
import org.netbeans.api.annotations.common.CheckForNull;
51
import org.netbeans.api.annotations.common.NonNull;
52
import org.netbeans.api.annotations.common.NullAllowed;
50
import org.netbeans.spi.editor.completion.CompletionResultSet;
53
import org.netbeans.spi.editor.completion.CompletionResultSet;
51
import org.netbeans.spi.editor.completion.CompletionTask;
54
import org.netbeans.spi.editor.completion.CompletionTask;
52
import org.openide.util.RequestProcessor;
55
import org.openide.util.RequestProcessor;
Lines 97-103 Link Here
97
     *  <br>
100
     *  <br>
98
     *  It may be null to indicate that no component was provided.
101
     *  It may be null to indicate that no component was provided.
99
     */
102
     */
100
    public AsyncCompletionTask(AsyncCompletionQuery query, JTextComponent component) {
103
    public AsyncCompletionTask(@NonNull AsyncCompletionQuery query, @NullAllowed JTextComponent component) {
101
        assert (query != null) : "Query must be non-null";
104
        assert (query != null) : "Query must be non-null";
102
        this.query = query;
105
        this.query = query;
103
        this.component = component;
106
        this.component = component;
Lines 110-120 Link Here
110
     *
113
     *
111
     * @param query non-null query implementation.
114
     * @param query non-null query implementation.
112
     */
115
     */
113
    public AsyncCompletionTask(AsyncCompletionQuery query) {
116
    public AsyncCompletionTask(@NonNull AsyncCompletionQuery query) {
114
        this(query, null);
117
        this(query, null);
115
    }
118
    }
116
119
117
    /**
120
    /**
121
     * Gets the {@link AsyncCompletionQuery} wrapped by this task.
122
     *
123
     * @return The {@link AsyncCompletionQuery}.
124
     */
125
    public @NonNull AsyncCompletionQuery getQuery() {
126
        return query;
127
    }
128
129
    /**
130
     * Gets the active component used by this task.
131
     *
132
     * @return The component.
133
     */
134
    public @CheckForNull JTextComponent getComponent() {
135
        return component;
136
    }
137
138
    /**
118
     * Called by completion infrastructure in AWT thread to populate
139
     * Called by completion infrastructure in AWT thread to populate
119
     * the given result set with data.
140
     * the given result set with data.
120
     */
141
     */
(-)a/editor.completion/src/org/netbeans/spi/editor/completion/support/CompletionUtilities.java (-4 / +74 lines)
Lines 49-54 Link Here
49
import java.awt.FontMetrics;
49
import java.awt.FontMetrics;
50
import java.awt.Graphics;
50
import java.awt.Graphics;
51
import javax.swing.ImageIcon;
51
import javax.swing.ImageIcon;
52
import org.netbeans.api.annotations.common.NonNull;
53
import org.netbeans.api.annotations.common.NullAllowed;
52
import org.netbeans.modules.editor.completion.PatchedHtmlRenderer;
54
import org.netbeans.modules.editor.completion.PatchedHtmlRenderer;
53
55
54
/**
56
/**
Lines 119-125 Link Here
119
        }
121
        }
120
        return width;
122
        return width;
121
    }
123
    }
122
    
124
123
    /**
125
    /**
124
     * Render a completion item using the provided icon and left and right
126
     * Render a completion item using the provided icon and left and right
125
     * html texts.
127
     * html texts.
Lines 160-189 Link Here
160
    public static void renderHtml(ImageIcon icon, String leftHtmlText, String rightHtmlText,
162
    public static void renderHtml(ImageIcon icon, String leftHtmlText, String rightHtmlText,
161
    Graphics g, Font defaultFont, Color defaultColor,
163
    Graphics g, Font defaultFont, Color defaultColor,
162
    int width, int height, boolean selected) {
164
    int width, int height, boolean selected) {
165
        renderHtml(icon, leftHtmlText, rightHtmlText, g, defaultFont, defaultColor, defaultColor, width, height, selected, true);
166
    }
167
168
    /**
169
     * Render a completion item using the provided icon and left and right
170
     * html texts.
171
     *
172
     * @param icon icon 16x16 that will be displayed on the left. It may be null
173
     *  which means that no icon will be displayed but the space for the icon
174
     *  will still be reserved (to properly align with other items
175
     *  that will provide an icon).
176
     * 
177
     * @param leftHtmlText html text that will be displayed on the left side
178
     *  of the item's rendering area next to the icon.
179
     *  <br/>
180
     *  It may be null which indicates that no left text will be displayed.
181
     *  <br/>
182
     *  If there's not enough horizontal space in the rendering area
183
     *  the text will be shrinked and "..." will be displayed at the end.
184
     *
185
     * @param rightHtmlText html text that will be aligned to the right edge
186
     *  of the item's rendering area.
187
     *  <br/>
188
     *  It may be null which means that no right text will be displayed.
189
     *  <br/>
190
     *  The right text is always attempted to be fully displayed unlike
191
     *  the left text that may be shrinked if there's not enough rendering space
192
     *  in the horizontal direction.
193
     *  <br/>
194
     *  If there's not enough space even for the right text it will be shrinked
195
     *  and "..." will be displayed at the end of the rendered string.
196
     * @param g non-null graphics through which the rendering happens.
197
     * @param defaultFont non-null default font to be used for rendering.
198
     * @param foregroundColor non-null default color to be used for rendering.
199
     * @param selectedBackgroundColor non-null color to be used a the background
200
     *  for rendering selected items.
201
     * @param width &gt;=0 available width for rendering.
202
     * @param height &gt;=0 available height for rendering.
203
     * @param isBestMatch whether the item being rendered is currently the best
204
     *  match in the completion's JList. If selected the foreground color is forced
205
     *  to be black for all parts of the rendered strings.
206
     * @param isSelected whether the item being rendered is currently selected in
207
     *  the completion's JList. If <code>true</code>, the foreground color is
208
     *  forced to the value of the foregroundColor argument for all parts of the
209
     *  rendered strings.
210
     */
211
    public static void renderHtml(@NullAllowed ImageIcon icon,
212
                                  @NullAllowed String leftHtmlText,
213
                                  @NullAllowed String rightHtmlText,
214
                                  @NonNull Graphics g,
215
                                  @NonNull Font defaultFont,
216
                                  @NonNull Color foregroundColor,
217
                                  @NonNull Color selectedBackgroundColor,
218
                                  int width,
219
                                  int height,
220
                                  boolean isBestMatch,
221
                                  boolean isSelected) {
163
        if (icon != null) {
222
        if (icon != null) {
164
            // The image of the ImageIcon should already be loaded
223
            // The image of the ImageIcon should already be loaded
165
            // so no ImageObserver should be necessary
224
            // so no ImageObserver should be necessary
166
            boolean done = g.drawImage(icon.getImage(), BEFORE_ICON_GAP, (height - icon.getIconHeight()) /2, null);
225
            boolean done = g.drawImage(icon.getImage(), BEFORE_ICON_GAP, (height - icon.getIconHeight()) /2, null);
167
            assert (done);
226
            assert (done);
168
        }
227
        }
228
        
229
        if (isBestMatch && isSelected) {
230
            g.setColor(foregroundColor);
231
        }
232
169
        int iconWidth = BEFORE_ICON_GAP + ICON_WIDTH + AFTER_ICON_GAP;
233
        int iconWidth = BEFORE_ICON_GAP + ICON_WIDTH + AFTER_ICON_GAP;
170
        int rightTextX = width - AFTER_RIGHT_TEXT_GAP;
234
        int rightTextX = width - AFTER_RIGHT_TEXT_GAP;
171
        FontMetrics fm = g.getFontMetrics(defaultFont);
235
        FontMetrics fm = g.getFontMetrics(defaultFont);
172
        int textY = (height - fm.getHeight())/2 + fm.getHeight() - fm.getDescent();
236
        int textY = (height - fm.getHeight())/2 + fm.getHeight() - fm.getDescent();
173
        if (rightHtmlText != null && rightHtmlText.length() > 0) {
237
        if (rightHtmlText != null && rightHtmlText.length() > 0) {
174
            int rightTextWidth = (int)PatchedHtmlRenderer.renderHTML(rightHtmlText, g, 0, 0, Integer.MAX_VALUE, 0,
238
            int rightTextWidth = (int)PatchedHtmlRenderer.renderHTML(rightHtmlText, g, 0, 0, Integer.MAX_VALUE, 0,
175
                    defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_CLIP, false, true);
239
                    defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_CLIP, false, true);
176
            rightTextX = Math.max(iconWidth, rightTextX - rightTextWidth);
240
            rightTextX = Math.max(iconWidth, rightTextX - rightTextWidth);
177
            // Render right text
241
            // Render right text
178
            PatchedHtmlRenderer.renderHTML(rightHtmlText, g, rightTextX, textY, rightTextWidth, textY,
242
            PatchedHtmlRenderer.renderHTML(rightHtmlText, g, rightTextX, textY, rightTextWidth, textY,
179
                defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_CLIP, true, selected);
243
                defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_CLIP, true, isBestMatch && isSelected);
180
            rightTextX = Math.max(iconWidth, rightTextX - BEFORE_RIGHT_TEXT_GAP);
244
            rightTextX = Math.max(iconWidth, rightTextX - BEFORE_RIGHT_TEXT_GAP);
181
        }
245
        }
182
246
183
        // Render left text
247
        // Render left text
184
        if (leftHtmlText != null && leftHtmlText.length() > 0 && rightTextX > iconWidth) { // any space for left text?
248
        if (leftHtmlText != null && leftHtmlText.length() > 0 && rightTextX > iconWidth) { // any space for left text?
185
            PatchedHtmlRenderer.renderHTML(leftHtmlText, g, iconWidth, textY, rightTextX - iconWidth, textY,
249
            PatchedHtmlRenderer.renderHTML(leftHtmlText, g, iconWidth, textY, rightTextX - iconWidth, textY,
186
                defaultFont, defaultColor, PatchedHtmlRenderer.STYLE_TRUNCATE, true, selected);
250
                defaultFont, foregroundColor, PatchedHtmlRenderer.STYLE_TRUNCATE, true, isBestMatch && isSelected);
251
        }
252
253
        // Render border for best match items that are not selected
254
        if (isBestMatch && !isSelected) {
255
            g.setColor(selectedBackgroundColor);
256
            g.drawRect(0, 0, width - 1, height - 1);
187
        }
257
        }
188
    }
258
    }
189
    
259
    
(-)a/java.editor/test/unit/src/org/netbeans/modules/java/editor/completion/CompletionTestBase.java (-1 / +1 lines)
Lines 74-80 Link Here
74
import org.netbeans.api.java.source.gen.WhitespaceIgnoringDiff;
74
import org.netbeans.api.java.source.gen.WhitespaceIgnoringDiff;
75
import org.netbeans.api.lexer.Language;
75
import org.netbeans.api.lexer.Language;
76
import org.netbeans.junit.NbTestCase;
76
import org.netbeans.junit.NbTestCase;
77
import org.netbeans.modules.editor.completion.CompletionItemComparator;
77
import org.netbeans.spi.editor.completion.CompletionItemComparator;
78
import org.netbeans.modules.editor.java.JavaCompletionProvider;
78
import org.netbeans.modules.editor.java.JavaCompletionProvider;
79
import org.netbeans.modules.editor.java.JavaKit;
79
import org.netbeans.modules.editor.java.JavaKit;
80
import org.netbeans.modules.editor.java.Utilities;
80
import org.netbeans.modules.editor.java.Utilities;

Return to bug 204867