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 208794
Collapse All | Expand All

(-)a/openide.explorer/apichanges.xml (+14 lines)
Lines 50-55 Link Here
50
<apidef name="explorer">Explorer API</apidef>
50
<apidef name="explorer">Explorer API</apidef>
51
</apidefs>
51
</apidefs>
52
<changes>
52
<changes>
53
    <change id="OutlineView_with_quicksearch">
54
        <api name="explorer"/>
55
        <summary>QuickSearch attached to OutlineView</summary>
56
        <version major="6" minor="43"/>
57
        <date day="29" month="2" year="2012"/>
58
        <author login="mentlicher"/>
59
        <compatibility binary="compatible" source="compatible" deprecation="no" deletion="no" addition="yes"/>
60
        <description>
61
            Added <a href="@TOP@/org/openide/explorer/view/OutlineView.html#getQuickSearch()">OutlineView.getQuickSearch()</a>
62
            method to get and control quick search functionality on OutlineView.
63
        </description>
64
        <class package="org.openide.explorer.view" name="OutlineView"/>
65
        <issue number="110686"/>
66
    </change>
53
    <change id="PropertyEnv.create">
67
    <change id="PropertyEnv.create">
54
        <api name="explorer"/>
68
        <api name="explorer"/>
55
        <summary>API method for creating a PropertyEnv instance</summary>
69
        <summary>API method for creating a PropertyEnv instance</summary>
(-)a/openide.explorer/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
OpenIDE-Module: org.openide.explorer
2
OpenIDE-Module: org.openide.explorer
3
OpenIDE-Module-Localizing-Bundle: org/openide/explorer/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/openide/explorer/Bundle.properties
4
AutoUpdate-Essential-Module: true
4
AutoUpdate-Essential-Module: true
5
OpenIDE-Module-Specification-Version: 6.42
5
OpenIDE-Module-Specification-Version: 6.43
6
6
(-)a/openide.explorer/nbproject/project.xml (-1 / +1 lines)
Lines 70-76 Link Here
70
                    <build-prerequisite/>
70
                    <build-prerequisite/>
71
                    <compile-dependency/>
71
                    <compile-dependency/>
72
                    <run-dependency>
72
                    <run-dependency>
73
                        <specification-version>6.2</specification-version>
73
                        <specification-version>7.43</specification-version>
74
                    </run-dependency>
74
                    </run-dependency>
75
                </dependency>
75
                </dependency>
76
                <dependency>
76
                <dependency>
(-)a/openide.explorer/src/org/openide/explorer/view/OutlineView.java (-40 / +56 lines)
Lines 132-137 Link Here
132
import org.netbeans.swing.outline.TreePathSupport;
132
import org.netbeans.swing.outline.TreePathSupport;
133
import org.openide.awt.Mnemonics;
133
import org.openide.awt.Mnemonics;
134
import org.openide.awt.MouseUtils;
134
import org.openide.awt.MouseUtils;
135
import org.openide.awt.QuickSearch;
135
import org.openide.explorer.ExplorerManager;
136
import org.openide.explorer.ExplorerManager;
136
import org.openide.explorer.ExplorerUtils;
137
import org.openide.explorer.ExplorerUtils;
137
import org.openide.explorer.propertysheet.PropertyPanel;
138
import org.openide.explorer.propertysheet.PropertyPanel;
Lines 233-241 Link Here
233
        rowModel = new PropertiesRowModel();
234
        rowModel = new PropertiesRowModel();
234
        model = createOutlineModel(treeModel, rowModel, nodesColumnLabel);
235
        model = createOutlineModel(treeModel, rowModel, nodesColumnLabel);
235
        outline = new OutlineViewOutline(model, rowModel);
236
        outline = new OutlineViewOutline(model, rowModel);
236
        quickSearch = QuickSearch.attach(this, searchConstraints);
237
        //quickSearch = QuickSearch.attach(this, searchConstraints);
237
        TableQuickSearchSupport tqss = new TableQuickSearchSupport(outline, outline, outline.qss);
238
        TableQuickSearchSupport tqss = outline.tqss;
238
        quickSearch.addQuickSearchListener(tqss);
239
        quickSearch = QuickSearch.attach(this, searchConstraints, tqss, tqss.createSearchPopupMenu());
240
        //quickSearch.addQuickSearchListener(tqss);
239
        outline.addKeyListener(new KeyListener() {
241
        outline.addKeyListener(new KeyListener() {
240
            @Override
242
            @Override
241
            public void keyTyped(KeyEvent e) {
243
            public void keyTyped(KeyEvent e) {
Lines 250-256 Link Here
250
                quickSearch.processKeyEvent(e);
252
                quickSearch.processKeyEvent(e);
251
            }
253
            }
252
        });
254
        });
253
        quickSearch.setPopupMenu(tqss.createSearchPopupMenu());
255
        //quickSearch.setPopupMenu(tqss.createSearchPopupMenu());
254
        rowModel.setOutline(outline);
256
        rowModel.setOutline(outline);
255
        outline.setRenderDataProvider(new NodeRenderDataProvider(outline));
257
        outline.setRenderDataProvider(new NodeRenderDataProvider(outline));
256
        SheetCell tableCell = new SheetCell.OutlineSheetCell(outline);
258
        SheetCell tableCell = new SheetCell.OutlineSheetCell(outline);
Lines 681-704 Link Here
681
    }
683
    }
682
    
684
    
683
    /**
685
    /**
684
     * Test whether the quick search feature is enabled or not.
686
     * Get the quick search support, that is attached to this view.
685
     * Default is enabled (true).
687
     * @return The quick search support.
686
     * @since 
688
     * @since 6.43
687
     * @return <code>true</code> if quick search feature is enabled, <code>false</code> otherwise.
688
     */
689
     */
689
    /*public*/ boolean isQuickSearchAllowed() {
690
    public final QuickSearch getQuickSearch() {
690
        return quickSearch.isEnabled();
691
        return quickSearch;
691
    }
692
    }
692
    
693
    
693
    /**
694
    /**
694
     * Set whether the quick search feature is enabled or not.
695
     * Set a quick search filter.
695
     * @since 
696
     * @param quickSearchTableFilter The quick search filter
696
     * @param allowedQuickSearch <code>true</code> if quick search shall be enabled
697
     * @since 6.43
697
     */
698
     */
698
    /*public*/ void setQuickSearchAllowed(boolean allowedQuickSearch) {
699
    public void setQuickSearchTableFilter(QuickSearchTableFilter quickSearchTableFilter) {
699
        quickSearch.setEnabled(allowedQuickSearch);
700
        outline.setQuickSearchTableFilter(quickSearchTableFilter);
700
    }
701
    }
701
702
    
702
    /** Initializes the component and lookup explorer manager.
703
    /** Initializes the component and lookup explorer manager.
703
     */
704
     */
704
    @Override
705
    @Override
Lines 1327-1333 Link Here
1327
     * Extension of the ETable that allows adding a special comparator
1328
     * Extension of the ETable that allows adding a special comparator
1328
     * for sorting the rows.
1329
     * for sorting the rows.
1329
     */
1330
     */
1330
    static class OutlineViewOutline extends Outline implements TableQuickSearchSupport.StringValuedTable {
1331
    static class OutlineViewOutline extends Outline {
1331
        private final PropertiesRowModel rowModel;
1332
        private final PropertiesRowModel rowModel;
1332
        private static final String COLUMNS_SELECTOR_HINT = "ColumnsSelectorHint"; // NOI18N
1333
        private static final String COLUMNS_SELECTOR_HINT = "ColumnsSelectorHint"; // NOI18N
1333
        private static final String COPY_ACTION_DELEGATE = "Outline Copy Action Delegate "; // NOI18N
1334
        private static final String COPY_ACTION_DELEGATE = "Outline Copy Action Delegate "; // NOI18N
Lines 1345-1350 Link Here
1345
        private ExplorerManager manager;
1346
        private ExplorerManager manager;
1346
        //private int maxRowWidth;
1347
        //private int maxRowWidth;
1347
        private QuickSearchSettings qss = new QuickSearchSettings();
1348
        private QuickSearchSettings qss = new QuickSearchSettings();
1349
        private TableQuickSearchSupport tqss;
1348
1350
1349
        public OutlineViewOutline(final OutlineModel mdl, PropertiesRowModel rowModel) {
1351
        public OutlineViewOutline(final OutlineModel mdl, PropertiesRowModel rowModel) {
1350
            super(mdl);
1352
            super(mdl);
Lines 1364-1369 Link Here
1364
            getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ctrlSpace, "invokeCustomEditor"); //NOI18N
1366
            getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ctrlSpace, "invokeCustomEditor"); //NOI18N
1365
            Action invokeCustomEditorAction = new InvokeCustomEditorAction(ctrlSpaceActionBind);
1367
            Action invokeCustomEditorAction = new InvokeCustomEditorAction(ctrlSpaceActionBind);
1366
            getActionMap().put("invokeCustomEditor", invokeCustomEditorAction);
1368
            getActionMap().put("invokeCustomEditor", invokeCustomEditorAction);
1369
            tqss = new TableQuickSearchSupport(this, new DefaultQuickSearchTableFilter(), qss);
1367
        }
1370
        }
1368
        
1371
        
1369
        private void removeDefaultCutCopyPaste(InputMap map) {
1372
        private void removeDefaultCutCopyPaste(InputMap map) {
Lines 1406-1439 Link Here
1406
            }
1409
            }
1407
            return null;
1410
            return null;
1408
        }
1411
        }
1412
        
1413
        public final void setQuickSearchTableFilter(QuickSearchTableFilter quickSearchTableFilter) {
1414
            tqss.setQuickSearchTableFilter(quickSearchTableFilter);
1415
        }
1409
1416
1410
        @Override
1417
        private final class DefaultQuickSearchTableFilter implements QuickSearchTableFilter {
1411
        public String getStringValueAt(int row, int col) {
1418
1412
            Object value = transformValue(getValueAt(row, col));
1419
            @Override
1413
            String str;
1420
            public boolean asynchronous() {
1414
            if (value instanceof Property) {
1421
                return false;
1415
                Property p = (Property) value;
1422
            }
1416
                Object v = null;
1423
1417
                try {
1424
            @Override
1418
                    v = p.getValue();
1425
            public String getStringValueAt(int row, int col) {
1419
                } catch (IllegalAccessException ex) {
1426
                Object value = transformValue(getValueAt(row, col));
1420
                } catch (InvocationTargetException ex) {
1427
                String str;
1421
                }
1428
                if (value instanceof Property) {
1422
                if (v instanceof String) {
1429
                    Property p = (Property) value;
1423
                    str = (String) v;
1430
                    Object v = null;
1431
                    try {
1432
                        v = p.getValue();
1433
                    } catch (IllegalAccessException ex) {
1434
                    } catch (InvocationTargetException ex) {
1435
                    }
1436
                    if (v instanceof String) {
1437
                        str = (String) v;
1438
                    } else {
1439
                        str = null;
1440
                    }
1441
                } else if (value instanceof VisualizerNode) {
1442
                    str = ((VisualizerNode) value).getDisplayName();
1443
                } else if (value instanceof Node) {
1444
                    str = ((Node) value).getDisplayName();
1445
                } else if (value instanceof String) {
1446
                    str = (String) value;
1424
                } else {
1447
                } else {
1425
                    str = null;
1448
                    str = null;
1426
                }
1449
                }
1427
            } else if (value instanceof VisualizerNode) {
1450
                return str;
1428
                str = ((VisualizerNode) value).getDisplayName();
1429
            } else if (value instanceof Node) {
1430
                str = ((Node) value).getDisplayName();
1431
            } else if (value instanceof String) {
1432
                str = (String) value;
1433
            } else {
1434
                str = null;
1435
            }
1451
            }
1436
            return str;
1452
        
1437
        }
1453
        }
1438
1454
1439
        private class CopyToClipboardAction implements Action {
1455
        private class CopyToClipboardAction implements Action {
(-)a/openide.explorer/src/org/openide/explorer/view/QuickSearchTableFilter.java (+54 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2012 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 2012 Sun Microsystems, Inc.
41
 */
42
package org.openide.explorer.view;
43
44
/**
45
 *
46
 * @author Martin Entlicher
47
 */
48
public interface QuickSearchTableFilter {
49
    
50
    boolean asynchronous();
51
    
52
    String getStringValueAt(int row, int col);
53
    
54
}
(-)a/openide.explorer/src/org/openide/explorer/view/TableQuickSearchSupport.java (-19 / +29 lines)
Lines 61-67 Link Here
61
import javax.swing.event.ChangeListener;
61
import javax.swing.event.ChangeListener;
62
import javax.swing.table.TableColumn;
62
import javax.swing.table.TableColumn;
63
import javax.swing.table.TableColumnModel;
63
import javax.swing.table.TableColumnModel;
64
import javax.swing.text.Position;
64
import org.openide.awt.QuickSearch;
65
import org.openide.util.NbBundle;
65
import org.openide.util.NbBundle;
66
import org.openide.util.NbPreferences;
66
import org.openide.util.NbPreferences;
67
67
Lines 70-76 Link Here
70
 * 
70
 * 
71
 * @author Martin Entlicher
71
 * @author Martin Entlicher
72
 */
72
 */
73
class TableQuickSearchSupport implements QuickSearch.QuickSearchListener {
73
class TableQuickSearchSupport implements QuickSearch.Callback {
74
    
74
    
75
    private int quickSearchInitialRow = -1;     // The search was initiated here
75
    private int quickSearchInitialRow = -1;     // The search was initiated here
76
    private int quickSearchInitialColumn = -1;  // The search was initiated here
76
    private int quickSearchInitialColumn = -1;  // The search was initiated here
Lines 79-93 Link Here
79
    private String lastSearchText;
79
    private String lastSearchText;
80
    
80
    
81
    private JTable table;
81
    private JTable table;
82
    private StringValuedTable svTable;
82
    //private StringValuedTable svTable;
83
    private QuickSearchTableFilter quickSearchTableFilter;
83
    private QuickSearchSettings qss;
84
    private QuickSearchSettings qss;
84
    
85
    
85
    TableQuickSearchSupport(JTable table, StringValuedTable svTable, QuickSearchSettings qss) {
86
    TableQuickSearchSupport(JTable table, QuickSearchTableFilter quickSearchTableFilter, QuickSearchSettings qss) {
86
        this.table = table;
87
        this.table = table;
87
        this.svTable = svTable;
88
        this.quickSearchTableFilter = quickSearchTableFilter;
88
        this.qss = qss;
89
        this.qss = qss;
89
    }
90
    }
90
    
91
    
92
    public void setQuickSearchTableFilter(QuickSearchTableFilter quickSearchTableFilter) {
93
        this.quickSearchTableFilter = quickSearchTableFilter;
94
    }
95
96
    @Override
97
    public boolean asynchronous() {
98
        return quickSearchTableFilter.asynchronous();
99
    }
100
    
91
    @Override
101
    @Override
92
    public void quickSearchUpdate(String searchText) {
102
    public void quickSearchUpdate(String searchText) {
93
        lastSearchText = searchText;
103
        lastSearchText = searchText;
Lines 103-114 Link Here
103
        }
113
        }
104
        quickSearchLastRow = quickSearchInitialRow;
114
        quickSearchLastRow = quickSearchInitialRow;
105
        quickSearchLastColumn = quickSearchInitialColumn;
115
        quickSearchLastColumn = quickSearchInitialColumn;
106
        doSearch(searchText, Position.Bias.Forward);
116
        doSearch(searchText, true);
107
    }
117
    }
108
118
109
    @Override
119
    @Override
110
    public void showNextSelection(Position.Bias bias) {
120
    public void showNextSelection(boolean forward) {
111
        if (bias == Position.Bias.Forward) {
121
        if (forward) {
112
            if (++quickSearchLastColumn >= table.getColumnCount()) {
122
            if (++quickSearchLastColumn >= table.getColumnCount()) {
113
                quickSearchLastColumn = 0;
123
                quickSearchLastColumn = 0;
114
                if (++quickSearchLastRow >= table.getRowCount()) {
124
                if (++quickSearchLastRow >= table.getRowCount()) {
Lines 116-122 Link Here
116
                }
126
                }
117
            }
127
            }
118
        }
128
        }
119
        doSearch(lastSearchText, bias);
129
        doSearch(lastSearchText, forward);
120
    }
130
    }
121
131
122
    @Override
132
    @Override
Lines 134-140 Link Here
134
        String maxPrefix = null;
144
        String maxPrefix = null;
135
        for (int row = row1; row < row2; row++) {
145
        for (int row = row1; row < row2; row++) {
136
            for (int col = col1; col < col2; col++) {
146
            for (int col = col1; col < col2; col++) {
137
                String str = svTable.getStringValueAt(row, col);
147
                String str = quickSearchTableFilter.getStringValueAt(row, col);
138
                String strUp;
148
                String strUp;
139
                if (qss.isMatchCase()) {
149
                if (qss.isMatchCase()) {
140
                    strUp = str;
150
                    strUp = str;
Lines 145-151 Link Here
145
                    if (maxPrefix == null) {
155
                    if (maxPrefix == null) {
146
                        maxPrefix = str;
156
                        maxPrefix = str;
147
                    } else {
157
                    } else {
148
                        maxPrefix = QuickSearch.findMaxCommonSubstring(maxPrefix, str, !qss.isMatchCase());
158
                        maxPrefix = QuickSearch.findMaxPrefix(maxPrefix, str, !qss.isMatchCase());
149
                    }
159
                    }
150
                }
160
                }
151
            }
161
            }
Lines 170-195 Link Here
170
        quickSearchInitialColumn = -1;
180
        quickSearchInitialColumn = -1;
171
    }
181
    }
172
182
173
    private void doSearch(String searchText, Position.Bias bias) {
183
    private void doSearch(String searchText, boolean forward) {
174
        if (!qss.isMatchCase()) {
184
        if (!qss.isMatchCase()) {
175
            searchText = searchText.toUpperCase();
185
            searchText = searchText.toUpperCase();
176
        }
186
        }
177
        int n = table.getRowCount();
187
        int n = table.getRowCount();
178
        boolean backward = bias == Position.Bias.Backward;
188
        //boolean backward = bias == Position.Bias.Backward;
179
        int row1 = quickSearchLastRow;
189
        int row1 = quickSearchLastRow;
180
        int row2 = quickSearchLastRow + n;
190
        int row2 = quickSearchLastRow + n;
181
        boolean lineStartSearch = true;
191
        boolean lineStartSearch = true;
182
        Set<String> columnsIgnoredToSearch = qss.getColumnsIgnoredToSearch();
192
        Set<String> columnsIgnoredToSearch = qss.getColumnsIgnoredToSearch();
183
        do {
193
        do {
184
            int col1 = quickSearchLastColumn;
194
            int col1 = quickSearchLastColumn;
185
            int col2 = (backward) ? 0 : table.getColumnCount();
195
            int col2 = (forward) ? table.getColumnCount() : 0;
186
            for (int row = (backward) ? (row2 - 1) : row1; (backward) ? row >= row1 : row < row2; row = (backward) ? --row : ++row) {
196
            for (int row = (forward) ? row1 : (row2 - 1); (forward) ? row < row2 : row >= row1; row = (forward) ? ++row : --row) {
187
                for (int col = col1; (backward) ? col >= col2 : col < col2; col = (backward) ? --col : ++col) {
197
                for (int col = col1; (forward) ? col < col2 : col >= col2; col = (forward) ? ++col : --col) {
188
                    String cName = table.getColumnName(col);
198
                    String cName = table.getColumnName(col);
189
                    if (columnsIgnoredToSearch.contains(cName)) {
199
                    if (columnsIgnoredToSearch.contains(cName)) {
190
                        continue;
200
                        continue;
191
                    }
201
                    }
192
                    String str = svTable.getStringValueAt(row % n, col);
202
                    String str = quickSearchTableFilter.getStringValueAt(row % n, col);
193
                    if (str == null) {
203
                    if (str == null) {
194
                        continue;
204
                        continue;
195
                    }
205
                    }
Lines 208-214 Link Here
208
                        }
218
                        }
209
                    }
219
                    }
210
                }
220
                }
211
                col1 = (backward) ? table.getColumnCount() - 1 : 0;
221
                col1 = (forward) ? 0 : table.getColumnCount() - 1;
212
            }
222
            }
213
            lineStartSearch = !lineStartSearch;
223
            lineStartSearch = !lineStartSearch;
214
        } while (!lineStartSearch);
224
        } while (!lineStartSearch);
Lines 234-240 Link Here
234
                return TableQuickSearchSupport.getSearchPopupMenu(qss, table.getColumnModel(), new ActionListener() {
244
                return TableQuickSearchSupport.getSearchPopupMenu(qss, table.getColumnModel(), new ActionListener() {
235
                    @Override
245
                    @Override
236
                    public void actionPerformed(ActionEvent e) {
246
                    public void actionPerformed(ActionEvent e) {
237
                        doSearch(lastSearchText, Position.Bias.Forward);
247
                        doSearch(lastSearchText, true);
238
                    }
248
                    }
239
                });
249
                });
240
            }
250
            }
(-)a/openide.explorer/src/org/openide/explorer/view/TreeTable.java (-21 / +36 lines)
Lines 87-93 Link Here
87
 *
87
 *
88
 * @author Jan Rojcek
88
 * @author Jan Rojcek
89
 */
89
 */
90
class TreeTable extends JTable implements Runnable, TableQuickSearchSupport.StringValuedTable {
90
class TreeTable extends JTable implements Runnable {
91
    /** Action key for up/down focus action */
91
    /** Action key for up/down focus action */
92
    private static final String ACTION_FOCUS_NEXT = "focusNext"; //NOI18N
92
    private static final String ACTION_FOCUS_NEXT = "focusNext"; //NOI18N
93
    private static Color unfocusedSelBg = null;
93
    private static Color unfocusedSelBg = null;
Lines 337-367 Link Here
337
    QuickSearchSettings getQuickSearchSettings() {
337
    QuickSearchSettings getQuickSearchSettings() {
338
        return qss;
338
        return qss;
339
    }
339
    }
340
    
341
    private QuickSearchTableFilter qstf = new DefaultQuickSearchTableFilter();
342
    
343
    QuickSearchTableFilter getQuickSearchTableFilter() {
344
        return qstf;
345
    }
340
346
341
    @Override
347
    private final class DefaultQuickSearchTableFilter implements QuickSearchTableFilter {
342
    public String getStringValueAt(int row, int col) {
348
343
        Object value = getValueAt(row, col);
349
        @Override
344
        String str;
350
        public boolean asynchronous() {
345
        if (value instanceof Property) {
351
            return false;
346
            Property p = (Property) value;
352
        }
347
            Object v = null;
353
348
            try {
354
        @Override
349
                v = p.getValue();
355
        public String getStringValueAt(int row, int col) {
350
            } catch (IllegalAccessException ex) {
356
            Object value = getValueAt(row, col);
351
            } catch (InvocationTargetException ex) {
357
            String str;
352
            }
358
            if (value instanceof Property) {
353
            if (v instanceof String) {
359
                Property p = (Property) value;
354
                str = (String) v;
360
                Object v = null;
361
                try {
362
                    v = p.getValue();
363
                } catch (IllegalAccessException ex) {
364
                } catch (InvocationTargetException ex) {
365
                }
366
                if (v instanceof String) {
367
                    str = (String) v;
368
                } else {
369
                    str = null;
370
                }
371
            } else if (value instanceof VisualizerNode) {
372
                str = ((VisualizerNode) value).getDisplayName();
373
                //str = Visualizer.findNode(value).getDisplayName();
355
            } else {
374
            } else {
356
                str = null;
375
                str = null;
357
            }
376
            }
358
        } else if (value instanceof VisualizerNode) {
377
            return str;
359
            str = ((VisualizerNode) value).getDisplayName();
360
            //str = Visualizer.findNode(value).getDisplayName();
361
        } else {
362
            str = null;
363
        }
378
        }
364
        return str;
379
        
365
    }
380
    }
366
    
381
    
367
    private class GuardedActions implements Mutex.Action<Object> {
382
    private class GuardedActions implements Mutex.Action<Object> {
(-)a/openide.explorer/src/org/openide/explorer/view/TreeTableView.java (-4 / +3 lines)
Lines 77-82 Link Here
77
import javax.swing.plaf.metal.MetalScrollBarUI;
77
import javax.swing.plaf.metal.MetalScrollBarUI;
78
import javax.swing.table.*;
78
import javax.swing.table.*;
79
import javax.swing.tree.*;
79
import javax.swing.tree.*;
80
import org.openide.awt.QuickSearch;
80
import org.openide.explorer.view.TreeView.PopupAdapter;
81
import org.openide.explorer.view.TreeView.PopupAdapter;
81
import org.openide.explorer.view.TreeView.PopupSupport;
82
import org.openide.explorer.view.TreeView.PopupSupport;
82
import org.openide.explorer.view.TreeView.TreePropertyListener;
83
import org.openide.explorer.view.TreeView.TreePropertyListener;
Lines 500-508 Link Here
500
        TreeTable tt = new TreeTable(treeModel, tableModel);
501
        TreeTable tt = new TreeTable(treeModel, tableModel);
501
        treeTable = tt;
502
        treeTable = tt;
502
        tree = ((TreeTable) treeTable).getTree();
503
        tree = ((TreeTable) treeTable).getTree();
503
        quickSearch = QuickSearch.attach(this, searchConstraints);
504
        TableQuickSearchSupport tqss = new TableQuickSearchSupport(tt, tt.getQuickSearchTableFilter(), tt.getQuickSearchSettings());
504
        TableQuickSearchSupport tqss = new TableQuickSearchSupport(tt, tt, tt.getQuickSearchSettings());
505
        quickSearch = QuickSearch.attach(this, searchConstraints, tqss, tqss.createSearchPopupMenu());
505
        quickSearch.addQuickSearchListener(tqss);
506
        tt.addKeyListener(new KeyListener() {
506
        tt.addKeyListener(new KeyListener() {
507
            @Override
507
            @Override
508
            public void keyTyped(KeyEvent e) {
508
            public void keyTyped(KeyEvent e) {
Lines 517-523 Link Here
517
                quickSearch.processKeyEvent(e);
517
                quickSearch.processKeyEvent(e);
518
            }
518
            }
519
        });
519
        });
520
        quickSearch.setPopupMenu(tqss.createSearchPopupMenu());
521
        
520
        
522
        defaultHeaderRenderer = treeTable.getTableHeader().getDefaultRenderer();
521
        defaultHeaderRenderer = treeTable.getTableHeader().getDefaultRenderer();
523
        treeTable.getTableHeader().setDefaultRenderer(new SortingHeaderRenderer());
522
        treeTable.getTableHeader().setDefaultRenderer(new SortingHeaderRenderer());
(-)a/openide.explorer/src/org/openide/explorer/view/TreeView.java (-331 / +134 lines)
Lines 133-139 Link Here
133
import javax.swing.event.TreeWillExpandListener;
133
import javax.swing.event.TreeWillExpandListener;
134
import javax.swing.plaf.TreeUI;
134
import javax.swing.plaf.TreeUI;
135
import javax.swing.plaf.UIResource;
135
import javax.swing.plaf.UIResource;
136
import javax.swing.text.Position;
137
import javax.swing.tree.ExpandVetoException;
136
import javax.swing.tree.ExpandVetoException;
138
import javax.swing.tree.RowMapper;
137
import javax.swing.tree.RowMapper;
139
import javax.swing.tree.TreeCellEditor;
138
import javax.swing.tree.TreeCellEditor;
Lines 141-146 Link Here
141
import javax.swing.tree.TreeNode;
140
import javax.swing.tree.TreeNode;
142
import javax.swing.tree.TreePath;
141
import javax.swing.tree.TreePath;
143
import javax.swing.tree.TreeSelectionModel;
142
import javax.swing.tree.TreeSelectionModel;
143
import org.openide.awt.QuickSearch;
144
144
145
145
146
/**
146
/**
Lines 224-231 Link Here
224
    transient private int allowedDropActions = DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE;
224
    transient private int allowedDropActions = DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE;
225
    
225
    
226
    /** Quick Search support */
226
    /** Quick Search support */
227
    transient private boolean allowedQuickSearch = true;
227
    transient private QuickSearch qs;
228
    transient private KeyAdapter quickSearchKeyAdapter;
229
    
228
    
230
    /** wait cursor is shown automatically during expanding */
229
    /** wait cursor is shown automatically during expanding */
231
    transient private boolean autoWaitCursor = true;
230
    transient private boolean autoWaitCursor = true;
Lines 454-460 Link Here
454
     * @return true if quick search feature is enabled, false otherwise.
453
     * @return true if quick search feature is enabled, false otherwise.
455
     */
454
     */
456
    public boolean isQuickSearchAllowed() {
455
    public boolean isQuickSearchAllowed() {
457
        return allowedQuickSearch;
456
        return qs.isEnabled();
458
    }
457
    }
459
    
458
    
460
    /**
459
    /**
Lines 463-477 Link Here
463
     * @param allowedQuickSearch <code>true</code> if quick search shall be enabled
462
     * @param allowedQuickSearch <code>true</code> if quick search shall be enabled
464
     */
463
     */
465
    public void setQuickSearchAllowed(boolean allowedQuickSearch) {
464
    public void setQuickSearchAllowed(boolean allowedQuickSearch) {
466
        this.allowedQuickSearch = allowedQuickSearch;
465
        qs.setEnabled(allowedQuickSearch);
467
         if (quickSearchKeyAdapter != null && tree != null) {
468
            if (allowedQuickSearch) {
469
               tree.addKeyListener(quickSearchKeyAdapter);
470
            } else {
471
               removeSearchField();
472
               tree.removeKeyListener(quickSearchKeyAdapter);
473
            }
474
         }
475
    }
466
    }
476
467
477
    
468
    
Lines 1683-1693 Link Here
1683
    }
1674
    }
1684
1675
1685
    @Override
1676
    @Override
1677
    public void add(Component comp, Object constraints) {
1678
        if (constraints == searchConstraints) {
1679
            searchPanel = comp;
1680
            constraints = null;
1681
        }
1682
        super.add(comp, constraints);
1683
    }
1684
    
1685
    @Override
1686
    public void remove(Component comp) {
1687
        if (comp == searchPanel) {
1688
            searchPanel = null;
1689
        }
1690
        super.remove(comp);
1691
    }
1692
    
1693
    @Override
1686
    public Insets getInsets() {
1694
    public Insets getInsets() {
1687
        Insets res = getInnerInsets();
1695
        Insets res = getInnerInsets();
1688
        res = new Insets(res.top, res.left, res.bottom, res.right);
1696
        res = new Insets(res.top, res.left, res.bottom, res.right);
1689
        if( null != searchpanel && searchpanel.isVisible() ) {
1697
        if( null != searchPanel && searchPanel.isVisible() ) {
1690
            res.bottom += searchpanel.getPreferredSize().height;
1698
            res.bottom += searchPanel.getPreferredSize().height;
1691
        }
1699
        }
1692
        return res;
1700
        return res;
1693
    }
1701
    }
Lines 1701-1830 Link Here
1701
    }
1709
    }
1702
1710
1703
    TreePath[] origSelectionPaths = null;
1711
    TreePath[] origSelectionPaths = null;
1704
    JPanel searchpanel = null;
1712
    private Component searchPanel = null;
1705
    // searchTextField manages focus because it handles VK_TAB key
1713
    private final Object searchConstraints = new Object();
1706
    private JTextField searchTextField = new JTextField() {
1714
    
1707
        @Override
1715
    /** Called from tests */
1708
        public boolean isManagingFocus() {
1716
    Component getSearchPanel() {
1709
            return true;
1717
        return searchPanel;
1710
        }
1711
1712
        @Override
1713
        public void processKeyEvent(KeyEvent ke) {
1714
            //override the default handling so that
1715
            //the parent will never receive the escape key and
1716
            //close a modal dialog
1717
            if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) {
1718
                removeSearchField();
1719
                ke.consume();
1720
1721
                // bugfix #32909, reqest focus when search field is removed
1722
                SwingUtilities.invokeLater(
1723
                    new Runnable() {
1724
                        //additional bugfix - do focus change later or removing
1725
                        //the component while it's focused will cause focus to
1726
                        //get transferred to the next component in the
1727
                        //parent focusTraversalPolicy *after* our request
1728
                        //focus completes, so focus goes into a black hole - Tim
1729
                        @Override
1730
                        public void run() {
1731
                            if( null != tree )
1732
                                tree.requestFocus();
1733
                        }
1734
                    }
1735
                );
1736
            } else {
1737
                super.processKeyEvent(ke);
1738
            }
1739
        }
1740
    };
1741
    private int originalScrollMode;
1742
1743
    private static class SearchPanel extends JPanel {
1744
        public SearchPanel() {
1745
            if( ViewUtil.isAquaLaF )
1746
                setBorder(BorderFactory.createEmptyBorder(9,6,8,2));
1747
            else
1748
                setBorder(BorderFactory.createEmptyBorder(2,6,2,2));
1749
            setOpaque( true );
1750
        }
1751
1752
        @Override
1753
        protected void paintComponent(Graphics g) {
1754
            if( ViewUtil.isAquaLaF && g instanceof Graphics2D ) {
1755
                Graphics2D g2d = (Graphics2D) g;
1756
                g2d.setPaint( new GradientPaint(0, 0, UIManager.getColor("NbExplorerView.quicksearch.background.top"),
1757
                        0, getHeight(), UIManager.getColor("NbExplorerView.quicksearch.background.bottom")));//NOI18N
1758
                g2d.fillRect(0, 0, getWidth(), getHeight());
1759
                g2d.setColor( UIManager.getColor("NbExplorerView.quicksearch.border") ); //NOI18N
1760
                g2d.drawLine(0, 0, getWidth(), 0);
1761
            } else {
1762
                super.paintComponent(g);
1763
            }
1764
        }
1765
    }
1766
1767
1768
    private void prepareSearchPanel() {
1769
        if( searchpanel == null ) {
1770
            searchpanel = new SearchPanel();
1771
1772
            JLabel lbl = new JLabel(NbBundle.getMessage(TreeView.class, "LBL_QUICKSEARCH")); //NOI18N
1773
            searchpanel.setLayout(new BoxLayout(searchpanel, BoxLayout.X_AXIS));
1774
            searchpanel.add(lbl);
1775
            searchpanel.add(searchTextField);
1776
            lbl.setLabelFor(searchTextField);
1777
            searchTextField.setColumns(10);
1778
            searchTextField.setMaximumSize(searchTextField.getPreferredSize());
1779
            searchTextField.putClientProperty("JTextField.variant", "search"); //NOI18N
1780
            lbl.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
1781
        }
1782
    }
1783
1784
    /**
1785
     * Adds the search field to the tree.
1786
     */
1787
    private void displaySearchField() {
1788
        if( null != searchpanel || !isQuickSearchAllowed())
1789
            return;
1790
1791
        TreeView previousSearchField = lastSearchField.get();
1792
        if (previousSearchField != null && previousSearchField != this) {
1793
            previousSearchField.removeSearchField();
1794
        }
1795
1796
        JViewport vp = getViewport();
1797
        originalScrollMode = vp.getScrollMode();
1798
        vp.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
1799
        searchTextField.setFont(tree.getFont());
1800
        prepareSearchPanel();
1801
        add(searchpanel);
1802
        invalidate();
1803
        revalidate();
1804
        repaint();
1805
        searchTextField.requestFocus();
1806
1807
        lastSearchField = new WeakReference<TreeView>(this);
1808
    }
1809
1810
    /**
1811
     * Removes the search field from the tree.
1812
     */
1813
    private void removeSearchField() {
1814
        if( null == searchpanel )
1815
            return;
1816
1817
        if (tree.getSelectionPaths() == null && origSelectionPaths != null) {
1818
            tree.setSelectionPaths(origSelectionPaths);
1819
        }
1820
1821
        remove(searchpanel);
1822
        searchpanel = null;
1823
        origSelectionPaths = null;
1824
        getViewport().setScrollMode(originalScrollMode);
1825
        invalidate();
1826
        revalidate();
1827
        repaint();
1828
    }
1718
    }
1829
1719
1830
    private class ExplorerScrollPaneLayout extends ScrollPaneLayout {
1720
    private class ExplorerScrollPaneLayout extends ScrollPaneLayout {
Lines 1832-1851 Link Here
1832
        @Override
1722
        @Override
1833
        public void layoutContainer( Container parent ) {
1723
        public void layoutContainer( Container parent ) {
1834
            super.layoutContainer(parent);
1724
            super.layoutContainer(parent);
1835
            if( null != searchpanel && searchpanel.isVisible() ) {
1725
            if( null != searchPanel && searchPanel.isVisible() ) {
1836
                Insets innerInsets = getInnerInsets();
1726
                Insets innerInsets = getInnerInsets();
1837
                Dimension prefSize = searchpanel.getPreferredSize();
1727
                Dimension prefSize = searchPanel.getPreferredSize();
1838
                searchpanel.setBounds(innerInsets.left, parent.getHeight()-innerInsets.bottom-prefSize.height,
1728
                searchPanel.setBounds(innerInsets.left, parent.getHeight()-innerInsets.bottom-prefSize.height,
1839
                        parent.getWidth()-innerInsets.left-innerInsets.right, prefSize.height);
1729
                        parent.getWidth()-innerInsets.left-innerInsets.right, prefSize.height);
1840
            }
1730
            }
1841
        }
1731
        }
1842
    }
1732
    }
1843
1733
1844
    private final class ExplorerTree extends JTree implements Autoscroll {
1734
    private final class ExplorerTree extends JTree implements Autoscroll, QuickSearch.Callback {
1845
        AutoscrollSupport support;
1735
        AutoscrollSupport support;
1846
        private String maxPrefix;
1736
        private String maxPrefix;
1847
        int SEARCH_FIELD_SPACE = 3;
1737
        int SEARCH_FIELD_SPACE = 3;
1848
        private boolean firstPaint = true;
1738
        private boolean firstPaint = true;
1739
        /** The last search searchResults */
1740
        private List<TreePath> searchResults = new ArrayList<TreePath>();
1741
        /** The last selected index from the search searchResults. */
1742
        private int currentSelectionIndex;
1743
        private String lastSearchText;
1849
1744
1850
1745
1851
        ExplorerTree(TreeModel model) {
1746
        ExplorerTree(TreeModel model) {
Lines 2008-2013 Link Here
2008
            new GuardedActions(3, fe);
1903
            new GuardedActions(3, fe);
2009
        }
1904
        }
2010
1905
1906
        @Override
1907
        protected void processKeyEvent(KeyEvent e) {
1908
            qs.processKeyEvent(e);
1909
            if (!e.isConsumed()) {
1910
                super.processKeyEvent(e);
1911
            }
1912
        }
1913
        
2011
        private void repaintSelection() {
1914
        private void repaintSelection() {
2012
            int first = getSelectionModel().getMinSelectionRow();
1915
            int first = getSelectionModel().getMinSelectionRow();
2013
            int last = getSelectionModel().getMaxSelectionRow();
1916
            int last = getSelectionModel().getMaxSelectionRow();
Lines 2039-2096 Link Here
2039
1942
2040
        private void setupSearch() {
1943
        private void setupSearch() {
2041
            // Remove the default key listeners
1944
            // Remove the default key listeners
2042
            KeyListener[] keyListeners = getListeners(KeyListener.class);
1945
//            KeyListener[] keyListeners = getListeners(KeyListener.class);
1946
//
1947
//            for (int i = 0; i < keyListeners.length; i++) {
1948
//                removeKeyListener(keyListeners[i]);
1949
//            }
1950
            
1951
            qs = QuickSearch.attach(TreeView.this, searchConstraints, this);
1952
        }
2043
1953
2044
            for (int i = 0; i < keyListeners.length; i++) {
1954
        @Override
2045
                removeKeyListener(keyListeners[i]);
1955
        public boolean asynchronous() {
2046
            }
1956
            return false;
2047
2048
            // create new key listeners
2049
            quickSearchKeyAdapter = (
2050
                new KeyAdapter() {
2051
                @Override
2052
                    public void keyTyped(KeyEvent e) {
2053
                        int modifiers = e.getModifiers();
2054
                        int keyCode = e.getKeyCode();
2055
                        char c = e.getKeyChar();
2056
2057
                        //#43617 - don't eat + and -
2058
                        //#98634 - and all its duplicates dont't react to space
2059
                        if ((c == '+') || (c == '-') || (c==' ')) return; // NOI18N
2060
2061
                        if (((modifiers > 0) && (modifiers != KeyEvent.SHIFT_MASK)) || e.isActionKey()) {
2062
                            return;
2063
                        }
2064
2065
                        if (Character.isISOControl(c) ||
2066
                              (keyCode == KeyEvent.VK_SHIFT) ||
2067
			      (keyCode == KeyEvent.VK_ESCAPE)) return;
2068
2069
                        final KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e);
2070
                        origSelectionPaths = getSelectionPaths();
2071
                        if (origSelectionPaths != null && origSelectionPaths.length == 0) {
2072
                            origSelectionPaths = null;
2073
                        }
2074
                        searchTextField.setText(String.valueOf(stroke.getKeyChar()));
2075
2076
                        displaySearchField();
2077
                        e.consume();
2078
                    }
2079
                }
2080
            );
2081
            if(isQuickSearchAllowed()){
2082
                addKeyListener(quickSearchKeyAdapter);
2083
            }
2084
            // Create a the "multi-event" listener for the text field. Instead of
2085
            // adding separate instances of each needed listener, we're using a
2086
            // class which implements them all. This approach is used in order 
2087
            // to avoid the creation of 4 instances which takes some time
2088
            SearchFieldListener searchFieldListener = new SearchFieldListener();
2089
            searchTextField.addKeyListener(searchFieldListener);
2090
            searchTextField.addFocusListener(searchFieldListener);
2091
            searchTextField.getDocument().addDocumentListener(searchFieldListener);
2092
        }
1957
        }
2093
        
1958
        
1959
        @Override
1960
        public void quickSearchUpdate(String searchText) {
1961
            lastSearchText = searchText;
1962
            currentSelectionIndex = 0;
1963
            searchResults.clear();
1964
            maxPrefix = null;
1965
1966
            String text = searchText.toUpperCase();
1967
1968
            if (text.length() > 0) {
1969
                searchResults = doSearch(text);
1970
            }
1971
            displaySearchResult();
1972
        }
1973
1974
        @Override
1975
        public void showNextSelection(boolean forward) {
1976
            if (forward) {
1977
                currentSelectionIndex++;
1978
            } else {
1979
                currentSelectionIndex--;
1980
            }
1981
            displaySearchResult();
1982
        }
1983
1984
        @Override
1985
        public String findMaxPrefix(String prefix) {
1986
            return maxPrefix;
1987
        }
1988
1989
        @Override
1990
        public void quickSearchConfirmed() {
1991
            TreePath selectedTPath = getSelectionPath();
1992
            if (selectedTPath != null) {
1993
                TreeNode selectedTNode = (TreeNode) selectedTPath.getLastPathComponent();
1994
                Node selectedNode = Visualizer.findNode(selectedTNode);
1995
                performPreferredActionOnNodes(new Node[] { selectedNode });
1996
            }
1997
            origSelectionPaths = null;
1998
            searchResults.clear();
1999
            lastSearchText = null;
2000
        }
2001
2002
        @Override
2003
        public void quickSearchCanceled() {
2004
            origSelectionPaths = null;
2005
            searchResults.clear();
2006
            lastSearchText = null;
2007
        }
2008
2094
        private List<TreePath> doSearch(String prefix) {
2009
        private List<TreePath> doSearch(String prefix) {
2095
            List<TreePath> results = new ArrayList<TreePath>();
2010
            List<TreePath> results = new ArrayList<TreePath>();
2096
            Set<TreePath> resSet = new HashSet<TreePath>();
2011
            Set<TreePath> resSet = new HashSet<TreePath>();
Lines 2109-2115 Link Here
2109
            while (true) {
2024
            while (true) {
2110
                startIndex = startIndex % size;
2025
                startIndex = startIndex % size;
2111
2026
2112
                SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, Position.Bias.Forward);
2027
                SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, true);
2113
                TreePath path = substringSearchResult != null? substringSearchResult.treePath: null;
2028
                TreePath path = substringSearchResult != null? substringSearchResult.treePath: null;
2114
2029
2115
                if ((path != null) && !resSet.contains(path)) {
2030
                if ((path != null) && !resSet.contains(path)) {
Lines 2134-2140 Link Here
2134
                            maxPrefix = elementName;
2049
                            maxPrefix = elementName;
2135
                        }
2050
                        }
2136
2051
2137
                        maxPrefix = findMaxPrefix(maxPrefix, elementName);
2052
                        maxPrefix = QuickSearch.findMaxPrefix(maxPrefix, elementName, true);
2138
                    }
2053
                    }
2139
                    // try next element
2054
                    // try next element
2140
                    startIndex++;
2055
                    startIndex++;
Lines 2146-2161 Link Here
2146
            return results;
2061
            return results;
2147
        }
2062
        }
2148
2063
2149
        private String findMaxPrefix(String str1, String str2) {
2150
            String res = null;
2151
2152
            for (int i = 0; str1.regionMatches(true, 0, str2, 0, i); i++) {
2153
                res = str1.substring(0, i);
2154
            }
2155
2156
            return res;
2157
        }
2158
        
2159
        /**
2064
        /**
2160
         * Copied and adapted from JTree.getNextMatch(...).
2065
         * Copied and adapted from JTree.getNextMatch(...).
2161
         * 
2066
         * 
Lines 2163-2169 Link Here
2163
         *         and the index of the first occurrence of the substring in TreePath.
2068
         *         and the index of the first occurrence of the substring in TreePath.
2164
         */
2069
         */
2165
        private SubstringSearchResult getNextSubstringMatch(
2070
        private SubstringSearchResult getNextSubstringMatch(
2166
                String substring, int startingRow, Position.Bias bias) {
2071
                String substring, int startingRow, boolean forward) {
2167
2072
2168
            int max = getRowCount();
2073
            int max = getRowCount();
2169
            if (substring == null) {
2074
            if (substring == null) {
Lines 2176-2182 Link Here
2176
2081
2177
            // start search from the next/previous element froom the 
2082
            // start search from the next/previous element froom the 
2178
            // selected element
2083
            // selected element
2179
            int increment = (bias == Position.Bias.Forward) ? 1 : -1;
2084
            int increment = (forward) ? 1 : -1;
2180
            int row = startingRow;
2085
            int row = startingRow;
2181
            do {
2086
            do {
2182
                TreePath path = getPathForRow(row);
2087
                TreePath path = getPathForRow(row);
Lines 2193-2198 Link Here
2193
            return null;
2098
            return null;
2194
        }
2099
        }
2195
2100
2101
        private void displaySearchResult() {
2102
            int sz = searchResults.size();
2103
2104
            if (sz > 0) {
2105
                if (currentSelectionIndex < 0) {
2106
                    currentSelectionIndex = sz - 1;
2107
                } else if (currentSelectionIndex >= sz) {
2108
                    currentSelectionIndex = 0;
2109
                }
2110
2111
                TreePath path = searchResults.get(currentSelectionIndex);
2112
                setSelectionPath(path);
2113
                scrollPathToVisible(path);
2114
            } else {
2115
                if (lastSearchText.isEmpty() && origSelectionPaths != null) {
2116
                    setSelectionPaths(origSelectionPaths);
2117
                    scrollPathToVisible(origSelectionPaths[0]);
2118
                } else {
2119
                    clearSelection();
2120
                }
2121
            }
2122
        }
2123
2196
        /** notify the Component to autoscroll */
2124
        /** notify the Component to autoscroll */
2197
        @Override
2125
        @Override
2198
        public void autoscroll(Point cursorLoc) {
2126
        public void autoscroll(Point cursorLoc) {
Lines 2295-2425 Link Here
2295
            }
2223
            }
2296
        }
2224
        }
2297
2225
2298
        private class SearchFieldListener extends KeyAdapter implements DocumentListener, FocusListener {
2299
            /** The last search results */
2300
            private List<TreePath> results = new ArrayList<TreePath>();
2301
2302
            /** The last selected index from the search results. */
2303
            private int currentSelectionIndex;
2304
2305
            SearchFieldListener() {
2306
            }
2307
2308
            @Override
2309
            public void changedUpdate(DocumentEvent e) {
2310
                searchForNode();
2311
            }
2312
2313
            @Override
2314
            public void insertUpdate(DocumentEvent e) {
2315
                searchForNode();
2316
            }
2317
2318
            @Override
2319
            public void removeUpdate(DocumentEvent e) {
2320
                searchForNode();
2321
            }
2322
2323
            @Override
2324
            public void keyPressed(KeyEvent e) {
2325
                int keyCode = e.getKeyCode();
2326
2327
                if (keyCode == KeyEvent.VK_ESCAPE) {
2328
                    removeSearchField();
2329
                    ExplorerTree.this.requestFocus();
2330
                } else if (keyCode == KeyEvent.VK_UP || (keyCode == KeyEvent.VK_F3 && e.isShiftDown())) {
2331
                    currentSelectionIndex--;
2332
                    displaySearchResult();
2333
2334
                    // Stop processing the event here. Otherwise it's dispatched
2335
                    // to the tree too (which scrolls)
2336
                    e.consume();
2337
                } else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_F3) {
2338
                    currentSelectionIndex++;
2339
                    displaySearchResult();
2340
2341
                    // Stop processing the event here. Otherwise it's dispatched
2342
                    // to the tree too (which scrolls)
2343
                    e.consume();
2344
                } else if (keyCode == KeyEvent.VK_TAB) {
2345
                    if (maxPrefix != null) {
2346
                        searchTextField.setText(maxPrefix);
2347
                    }
2348
2349
                    e.consume();
2350
                } else if (keyCode == KeyEvent.VK_ENTER) {
2351
                    removeSearchField();
2352
2353
                    // bugfix #39607, don't expand selected node when default action invoked
2354
                    TreePath selectedTPath = getSelectionPath();
2355
2356
                    if (selectedTPath != null) {
2357
                        TreeNode selectedTNode = (TreeNode) selectedTPath.getLastPathComponent();
2358
                        Node selectedNode = Visualizer.findNode(selectedTNode);
2359
2360
                        if (
2361
                            (selectedNode.getPreferredAction() == null) ||
2362
                                !selectedNode.getPreferredAction().isEnabled()
2363
                        ) {
2364
                            expandPath(getSelectionPath());
2365
                        }
2366
                    }
2367
2368
                    ExplorerTree.this.requestFocus();
2369
                    ExplorerTree.this.dispatchEvent(e);
2370
                }
2371
            }
2372
2373
            /** Searches for a node in the tree. */
2374
            private void searchForNode() {
2375
                currentSelectionIndex = 0;
2376
                results.clear();
2377
                maxPrefix = null;
2378
2379
                String text = searchTextField.getText().toUpperCase();
2380
2381
                if (text.length() > 0) {
2382
                    results = doSearch(text);
2383
                }
2384
                displaySearchResult();
2385
            }
2386
2387
            private void displaySearchResult() {
2388
                int sz = results.size();
2389
2390
                if (sz > 0) {
2391
                    if (currentSelectionIndex < 0) {
2392
                        currentSelectionIndex = sz - 1;
2393
                    } else if (currentSelectionIndex >= sz) {
2394
                        currentSelectionIndex = 0;
2395
                    }
2396
2397
                    TreePath path = results.get(currentSelectionIndex);
2398
                    setSelectionPath(path);
2399
                    scrollPathToVisible(path);
2400
                } else {
2401
                    if (searchTextField.getText().length() == 0 && origSelectionPaths != null) {
2402
                        setSelectionPaths(origSelectionPaths);
2403
                        scrollPathToVisible(origSelectionPaths[0]);
2404
                    } else {
2405
                        clearSelection();
2406
                    }
2407
                }
2408
            }
2409
2410
            @Override
2411
            public void focusGained(FocusEvent e) {
2412
                // make sure nothing is selected
2413
                searchTextField.select(1, 1);
2414
            }
2415
2416
            @Override
2417
            public void focusLost(FocusEvent e) {
2418
                results.clear();
2419
                removeSearchField();
2420
            }
2421
        }
2422
2423
        private class AccessibleExplorerTree extends JTree.AccessibleJTree {
2226
        private class AccessibleExplorerTree extends JTree.AccessibleJTree {
2424
            AccessibleExplorerTree() {
2227
            AccessibleExplorerTree() {
2425
            }
2228
            }
(-)a/openide.explorer/test/unit/src/org/openide/explorer/view/TreeViewQuickSearchTest.java (-2 / +2 lines)
Lines 219-227 Link Here
219
219
220
                if (phase[0] != 0) {
220
                if (phase[0] != 0) {
221
                    if (btv.isQuickSearchAllowed()) {
221
                    if (btv.isQuickSearchAllowed()) {
222
                        assertNotNull("Quick Search enabled ", btv.searchpanel);
222
                        assertNotNull("Quick Search enabled ", btv.getSearchPanel());
223
                    } else {
223
                    } else {
224
                        assertNull("Quick Search disable", btv.searchpanel);
224
                        assertNull("Quick Search disable", btv.getSearchPanel());
225
                    }
225
                    }
226
                }
226
                }
227
            }
227
            }

Return to bug 208794