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 (-33 / +63 lines)
Lines 88-93 Link Here
88
import javax.swing.BorderFactory;
88
import javax.swing.BorderFactory;
89
import javax.swing.InputMap;
89
import javax.swing.InputMap;
90
import javax.swing.JComponent;
90
import javax.swing.JComponent;
91
import javax.swing.JMenu;
91
import javax.swing.JPopupMenu;
92
import javax.swing.JPopupMenu;
92
import javax.swing.JScrollBar;
93
import javax.swing.JScrollBar;
93
import javax.swing.JScrollPane;
94
import javax.swing.JScrollPane;
Lines 132-137 Link Here
132
import org.netbeans.swing.outline.TreePathSupport;
133
import org.netbeans.swing.outline.TreePathSupport;
133
import org.openide.awt.Mnemonics;
134
import org.openide.awt.Mnemonics;
134
import org.openide.awt.MouseUtils;
135
import org.openide.awt.MouseUtils;
136
import org.openide.awt.QuickSearch;
135
import org.openide.explorer.ExplorerManager;
137
import org.openide.explorer.ExplorerManager;
136
import org.openide.explorer.ExplorerUtils;
138
import org.openide.explorer.ExplorerUtils;
137
import org.openide.explorer.propertysheet.PropertyPanel;
139
import org.openide.explorer.propertysheet.PropertyPanel;
Lines 233-241 Link Here
233
        rowModel = new PropertiesRowModel();
235
        rowModel = new PropertiesRowModel();
234
        model = createOutlineModel(treeModel, rowModel, nodesColumnLabel);
236
        model = createOutlineModel(treeModel, rowModel, nodesColumnLabel);
235
        outline = new OutlineViewOutline(model, rowModel);
237
        outline = new OutlineViewOutline(model, rowModel);
236
        quickSearch = QuickSearch.attach(this, searchConstraints);
238
        TableQuickSearchSupport tqss = outline.createDefaultTableQuickSearchSupport();
237
        TableQuickSearchSupport tqss = new TableQuickSearchSupport(outline, outline, outline.qss);
239
        attachQuickSearch(tqss, false, tqss.createSearchPopupMenu());
238
        quickSearch.addQuickSearchListener(tqss);
239
        outline.addKeyListener(new KeyListener() {
240
        outline.addKeyListener(new KeyListener() {
240
            @Override
241
            @Override
241
            public void keyTyped(KeyEvent e) {
242
            public void keyTyped(KeyEvent e) {
Lines 250-256 Link Here
250
                quickSearch.processKeyEvent(e);
251
                quickSearch.processKeyEvent(e);
251
            }
252
            }
252
        });
253
        });
253
        quickSearch.setPopupMenu(tqss.createSearchPopupMenu());
254
        rowModel.setOutline(outline);
254
        rowModel.setOutline(outline);
255
        outline.setRenderDataProvider(new NodeRenderDataProvider(outline));
255
        outline.setRenderDataProvider(new NodeRenderDataProvider(outline));
256
        SheetCell tableCell = new SheetCell.OutlineSheetCell(outline);
256
        SheetCell tableCell = new SheetCell.OutlineSheetCell(outline);
Lines 316-321 Link Here
316
316
317
        initializeTreeScrollSupport();
317
        initializeTreeScrollSupport();
318
    }
318
    }
319
    
320
    private void attachQuickSearch(QuickSearch.Callback callback, boolean asynchronous, JMenu popup) {
321
        if (quickSearch != null) {
322
            quickSearch.detach();
323
        }
324
        quickSearch = QuickSearch.attach(this, searchConstraints, callback, asynchronous, popup);
325
    }
319
326
320
    @Override
327
    @Override
321
    public void add(Component comp, Object constraints) {
328
    public void add(Component comp, Object constraints) {
Lines 683-704 Link Here
683
    /**
690
    /**
684
     * Test whether the quick search feature is enabled or not.
691
     * Test whether the quick search feature is enabled or not.
685
     * Default is enabled (true).
692
     * Default is enabled (true).
686
     * @since 
693
     * @since 6.43
687
     * @return <code>true</code> if quick search feature is enabled, <code>false</code> otherwise.
694
     * @return true if quick search feature is enabled, false otherwise.
688
     */
695
     */
689
    /*public*/ boolean isQuickSearchAllowed() {
696
    public boolean isQuickSearchAllowed() {
690
        return quickSearch.isEnabled();
697
        return quickSearch.isEnabled();
691
    }
698
    }
692
    
699
    
693
    /**
700
    /**
694
     * Set whether the quick search feature is enabled or not.
701
     * Set whether the quick search feature is enabled or not.
695
     * @since 
702
     * @since 6.43
696
     * @param allowedQuickSearch <code>true</code> if quick search shall be enabled
703
     * @param allowedQuickSearch <code>true</code> if quick search shall be enabled
697
     */
704
     */
698
    /*public*/ void setQuickSearchAllowed(boolean allowedQuickSearch) {
705
    public void setQuickSearchAllowed(boolean allowedQuickSearch) {
699
        quickSearch.setEnabled(allowedQuickSearch);
706
        quickSearch.setEnabled(allowedQuickSearch);
700
    }
707
    }
701
708
709
    /**
710
     * Set a quick search filter.
711
     * @param quickSearchTableFilter The quick search filter
712
     * @param asynchronous
713
     * @since 6.43
714
     */
715
    public void setQuickSearchTableFilter(QuickSearchTableFilter quickSearchTableFilter, boolean asynchronous) {
716
        TableQuickSearchSupport tqss = outline.createTableQuickSearchSupport(quickSearchTableFilter);
717
        attachQuickSearch(tqss, asynchronous, tqss.createSearchPopupMenu());
718
    }
719
    
702
    /** Initializes the component and lookup explorer manager.
720
    /** Initializes the component and lookup explorer manager.
703
     */
721
     */
704
    @Override
722
    @Override
Lines 1327-1333 Link Here
1327
     * Extension of the ETable that allows adding a special comparator
1345
     * Extension of the ETable that allows adding a special comparator
1328
     * for sorting the rows.
1346
     * for sorting the rows.
1329
     */
1347
     */
1330
    static class OutlineViewOutline extends Outline implements TableQuickSearchSupport.StringValuedTable {
1348
    static class OutlineViewOutline extends Outline {
1331
        private final PropertiesRowModel rowModel;
1349
        private final PropertiesRowModel rowModel;
1332
        private static final String COLUMNS_SELECTOR_HINT = "ColumnsSelectorHint"; // NOI18N
1350
        private static final String COLUMNS_SELECTOR_HINT = "ColumnsSelectorHint"; // NOI18N
1333
        private static final String COPY_ACTION_DELEGATE = "Outline Copy Action Delegate "; // NOI18N
1351
        private static final String COPY_ACTION_DELEGATE = "Outline Copy Action Delegate "; // NOI18N
Lines 1406-1439 Link Here
1406
            }
1424
            }
1407
            return null;
1425
            return null;
1408
        }
1426
        }
1427
        
1428
        private TableQuickSearchSupport createDefaultTableQuickSearchSupport() {
1429
            return new TableQuickSearchSupport(this, new DefaultQuickSearchTableFilter(), qss);
1430
        }
1409
1431
1410
        @Override
1432
        private TableQuickSearchSupport createTableQuickSearchSupport(QuickSearchTableFilter quickSearchTableFilter) {
1411
        public String getStringValueAt(int row, int col) {
1433
            return new TableQuickSearchSupport(this, quickSearchTableFilter, qss);
1412
            Object value = transformValue(getValueAt(row, col));
1434
        }
1413
            String str;
1435
        
1414
            if (value instanceof Property) {
1436
        private final class DefaultQuickSearchTableFilter implements QuickSearchTableFilter {
1415
                Property p = (Property) value;
1437
1416
                Object v = null;
1438
            @Override
1417
                try {
1439
            public String getStringValueAt(int row, int col) {
1418
                    v = p.getValue();
1440
                Object value = transformValue(getValueAt(row, col));
1419
                } catch (IllegalAccessException ex) {
1441
                String str;
1420
                } catch (InvocationTargetException ex) {
1442
                if (value instanceof Property) {
1421
                }
1443
                    Property p = (Property) value;
1422
                if (v instanceof String) {
1444
                    Object v = null;
1423
                    str = (String) v;
1445
                    try {
1446
                        v = p.getValue();
1447
                    } catch (IllegalAccessException ex) {
1448
                    } catch (InvocationTargetException ex) {
1449
                    }
1450
                    if (v instanceof String) {
1451
                        str = (String) v;
1452
                    } else {
1453
                        str = null;
1454
                    }
1455
                } else if (value instanceof VisualizerNode) {
1456
                    str = ((VisualizerNode) value).getDisplayName();
1457
                } else if (value instanceof Node) {
1458
                    str = ((Node) value).getDisplayName();
1459
                } else if (value instanceof String) {
1460
                    str = (String) value;
1424
                } else {
1461
                } else {
1425
                    str = null;
1462
                    str = null;
1426
                }
1463
                }
1427
            } else if (value instanceof VisualizerNode) {
1464
                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
            }
1465
            }
1436
            return str;
1466
        
1437
        }
1467
        }
1438
1468
1439
        private class CopyToClipboardAction implements Action {
1469
        private class CopyToClipboardAction implements Action {
(-)6bce66b50582 (+52 lines)
Added 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
    String getStringValueAt(int row, int col);
51
    
52
}
(-)a/openide.explorer/src/org/openide/explorer/view/TableQuickSearchSupport.java (-19 / +24 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, boolean asynchronous) {
93
        this.quickSearchTableFilter = quickSearchTableFilter;
94
    }
95
91
    @Override
96
    @Override
92
    public void quickSearchUpdate(String searchText) {
97
    public void quickSearchUpdate(String searchText) {
93
        lastSearchText = searchText;
98
        lastSearchText = searchText;
Lines 103-114 Link Here
103
        }
108
        }
104
        quickSearchLastRow = quickSearchInitialRow;
109
        quickSearchLastRow = quickSearchInitialRow;
105
        quickSearchLastColumn = quickSearchInitialColumn;
110
        quickSearchLastColumn = quickSearchInitialColumn;
106
        doSearch(searchText, Position.Bias.Forward);
111
        doSearch(searchText, true);
107
    }
112
    }
108
113
109
    @Override
114
    @Override
110
    public void showNextSelection(Position.Bias bias) {
115
    public void showNextSelection(boolean forward) {
111
        if (bias == Position.Bias.Forward) {
116
        if (forward) {
112
            if (++quickSearchLastColumn >= table.getColumnCount()) {
117
            if (++quickSearchLastColumn >= table.getColumnCount()) {
113
                quickSearchLastColumn = 0;
118
                quickSearchLastColumn = 0;
114
                if (++quickSearchLastRow >= table.getRowCount()) {
119
                if (++quickSearchLastRow >= table.getRowCount()) {
Lines 116-122 Link Here
116
                }
121
                }
117
            }
122
            }
118
        }
123
        }
119
        doSearch(lastSearchText, bias);
124
        doSearch(lastSearchText, forward);
120
    }
125
    }
121
126
122
    @Override
127
    @Override
Lines 134-140 Link Here
134
        String maxPrefix = null;
139
        String maxPrefix = null;
135
        for (int row = row1; row < row2; row++) {
140
        for (int row = row1; row < row2; row++) {
136
            for (int col = col1; col < col2; col++) {
141
            for (int col = col1; col < col2; col++) {
137
                String str = svTable.getStringValueAt(row, col);
142
                String str = quickSearchTableFilter.getStringValueAt(row, col);
138
                String strUp;
143
                String strUp;
139
                if (qss.isMatchCase()) {
144
                if (qss.isMatchCase()) {
140
                    strUp = str;
145
                    strUp = str;
Lines 145-151 Link Here
145
                    if (maxPrefix == null) {
150
                    if (maxPrefix == null) {
146
                        maxPrefix = str;
151
                        maxPrefix = str;
147
                    } else {
152
                    } else {
148
                        maxPrefix = QuickSearch.findMaxCommonSubstring(maxPrefix, str, !qss.isMatchCase());
153
                        maxPrefix = QuickSearch.findMaxPrefix(maxPrefix, str, !qss.isMatchCase());
149
                    }
154
                    }
150
                }
155
                }
151
            }
156
            }
Lines 170-195 Link Here
170
        quickSearchInitialColumn = -1;
175
        quickSearchInitialColumn = -1;
171
    }
176
    }
172
177
173
    private void doSearch(String searchText, Position.Bias bias) {
178
    private void doSearch(String searchText, boolean forward) {
174
        if (!qss.isMatchCase()) {
179
        if (!qss.isMatchCase()) {
175
            searchText = searchText.toUpperCase();
180
            searchText = searchText.toUpperCase();
176
        }
181
        }
177
        int n = table.getRowCount();
182
        int n = table.getRowCount();
178
        boolean backward = bias == Position.Bias.Backward;
183
        //boolean backward = bias == Position.Bias.Backward;
179
        int row1 = quickSearchLastRow;
184
        int row1 = quickSearchLastRow;
180
        int row2 = quickSearchLastRow + n;
185
        int row2 = quickSearchLastRow + n;
181
        boolean lineStartSearch = true;
186
        boolean lineStartSearch = true;
182
        Set<String> columnsIgnoredToSearch = qss.getColumnsIgnoredToSearch();
187
        Set<String> columnsIgnoredToSearch = qss.getColumnsIgnoredToSearch();
183
        do {
188
        do {
184
            int col1 = quickSearchLastColumn;
189
            int col1 = quickSearchLastColumn;
185
            int col2 = (backward) ? 0 : table.getColumnCount();
190
            int col2 = (forward) ? table.getColumnCount() : 0;
186
            for (int row = (backward) ? (row2 - 1) : row1; (backward) ? row >= row1 : row < row2; row = (backward) ? --row : ++row) {
191
            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) {
192
                for (int col = col1; (forward) ? col < col2 : col >= col2; col = (forward) ? ++col : --col) {
188
                    String cName = table.getColumnName(col);
193
                    String cName = table.getColumnName(col);
189
                    if (columnsIgnoredToSearch.contains(cName)) {
194
                    if (columnsIgnoredToSearch.contains(cName)) {
190
                        continue;
195
                        continue;
191
                    }
196
                    }
192
                    String str = svTable.getStringValueAt(row % n, col);
197
                    String str = quickSearchTableFilter.getStringValueAt(row % n, col);
193
                    if (str == null) {
198
                    if (str == null) {
194
                        continue;
199
                        continue;
195
                    }
200
                    }
Lines 208-214 Link Here
208
                        }
213
                        }
209
                    }
214
                    }
210
                }
215
                }
211
                col1 = (backward) ? table.getColumnCount() - 1 : 0;
216
                col1 = (forward) ? 0 : table.getColumnCount() - 1;
212
            }
217
            }
213
            lineStartSearch = !lineStartSearch;
218
            lineStartSearch = !lineStartSearch;
214
        } while (!lineStartSearch);
219
        } while (!lineStartSearch);
Lines 234-240 Link Here
234
                return TableQuickSearchSupport.getSearchPopupMenu(qss, table.getColumnModel(), new ActionListener() {
239
                return TableQuickSearchSupport.getSearchPopupMenu(qss, table.getColumnModel(), new ActionListener() {
235
                    @Override
240
                    @Override
236
                    public void actionPerformed(ActionEvent e) {
241
                    public void actionPerformed(ActionEvent e) {
237
                        doSearch(lastSearchText, Position.Bias.Forward);
242
                        doSearch(lastSearchText, true);
238
                    }
243
                    }
239
                });
244
                });
240
            }
245
            }
(-)a/openide.explorer/src/org/openide/explorer/view/TreeTable.java (-21 / +31 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 String getStringValueAt(int row, int col) {
345
        if (value instanceof Property) {
351
            Object value = getValueAt(row, col);
346
            Property p = (Property) value;
352
            String str;
347
            Object v = null;
353
            if (value instanceof Property) {
348
            try {
354
                Property p = (Property) value;
349
                v = p.getValue();
355
                Object v = null;
350
            } catch (IllegalAccessException ex) {
356
                try {
351
            } catch (InvocationTargetException ex) {
357
                    v = p.getValue();
352
            }
358
                } catch (IllegalAccessException ex) {
353
            if (v instanceof String) {
359
                } catch (InvocationTargetException ex) {
354
                str = (String) v;
360
                }
361
                if (v instanceof String) {
362
                    str = (String) v;
363
                } else {
364
                    str = null;
365
                }
366
            } else if (value instanceof VisualizerNode) {
367
                str = ((VisualizerNode) value).getDisplayName();
368
                //str = Visualizer.findNode(value).getDisplayName();
355
            } else {
369
            } else {
356
                str = null;
370
                str = null;
357
            }
371
            }
358
        } else if (value instanceof VisualizerNode) {
372
            return str;
359
            str = ((VisualizerNode) value).getDisplayName();
360
            //str = Visualizer.findNode(value).getDisplayName();
361
        } else {
362
            str = null;
363
        }
373
        }
364
        return str;
374
        
365
    }
375
    }
366
    
376
    
367
    private class GuardedActions implements Mutex.Action<Object> {
377
    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 (-327 / +125 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 void quickSearchUpdate(String searchText) {
1956
            lastSearchText = searchText;
1957
            currentSelectionIndex = 0;
1958
            searchResults.clear();
1959
            maxPrefix = null;
1960
1961
            String text = searchText.toUpperCase();
1962
1963
            if (text.length() > 0) {
1964
                searchResults = doSearch(text);
2046
            }
1965
            }
1966
            displaySearchResult();
1967
        }
2047
1968
2048
            // create new key listeners
1969
        @Override
2049
            quickSearchKeyAdapter = (
1970
        public void showNextSelection(boolean forward) {
2050
                new KeyAdapter() {
1971
            if (forward) {
2051
                @Override
1972
                currentSelectionIndex++;
2052
                    public void keyTyped(KeyEvent e) {
1973
            } else {
2053
                        int modifiers = e.getModifiers();
1974
                currentSelectionIndex--;
2054
                        int keyCode = e.getKeyCode();
1975
            }
2055
                        char c = e.getKeyChar();
1976
            displaySearchResult();
1977
        }
2056
1978
2057
                        //#43617 - don't eat + and -
1979
        @Override
2058
                        //#98634 - and all its duplicates dont't react to space
1980
        public String findMaxPrefix(String prefix) {
2059
                        if ((c == '+') || (c == '-') || (c==' ')) return; // NOI18N
1981
            return maxPrefix;
1982
        }
2060
1983
2061
                        if (((modifiers > 0) && (modifiers != KeyEvent.SHIFT_MASK)) || e.isActionKey()) {
1984
        @Override
2062
                            return;
1985
        public void quickSearchConfirmed() {
2063
                        }
1986
            TreePath selectedTPath = getSelectionPath();
1987
            if (selectedTPath != null) {
1988
                TreeNode selectedTNode = (TreeNode) selectedTPath.getLastPathComponent();
1989
                Node selectedNode = Visualizer.findNode(selectedTNode);
1990
                performPreferredActionOnNodes(new Node[] { selectedNode });
1991
            }
1992
            origSelectionPaths = null;
1993
            searchResults.clear();
1994
            lastSearchText = null;
1995
        }
2064
1996
2065
                        if (Character.isISOControl(c) ||
1997
        @Override
2066
                              (keyCode == KeyEvent.VK_SHIFT) ||
1998
        public void quickSearchCanceled() {
2067
			      (keyCode == KeyEvent.VK_ESCAPE)) return;
1999
            origSelectionPaths = null;
2000
            searchResults.clear();
2001
            lastSearchText = null;
2002
        }
2068
2003
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
        }
2093
        
2094
        private List<TreePath> doSearch(String prefix) {
2004
        private List<TreePath> doSearch(String prefix) {
2095
            List<TreePath> results = new ArrayList<TreePath>();
2005
            List<TreePath> results = new ArrayList<TreePath>();
2096
            Set<TreePath> resSet = new HashSet<TreePath>();
2006
            Set<TreePath> resSet = new HashSet<TreePath>();
Lines 2109-2115 Link Here
2109
            while (true) {
2019
            while (true) {
2110
                startIndex = startIndex % size;
2020
                startIndex = startIndex % size;
2111
2021
2112
                SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, Position.Bias.Forward);
2022
                SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, true);
2113
                TreePath path = substringSearchResult != null? substringSearchResult.treePath: null;
2023
                TreePath path = substringSearchResult != null? substringSearchResult.treePath: null;
2114
2024
2115
                if ((path != null) && !resSet.contains(path)) {
2025
                if ((path != null) && !resSet.contains(path)) {
Lines 2134-2140 Link Here
2134
                            maxPrefix = elementName;
2044
                            maxPrefix = elementName;
2135
                        }
2045
                        }
2136
2046
2137
                        maxPrefix = findMaxPrefix(maxPrefix, elementName);
2047
                        maxPrefix = QuickSearch.findMaxPrefix(maxPrefix, elementName, true);
2138
                    }
2048
                    }
2139
                    // try next element
2049
                    // try next element
2140
                    startIndex++;
2050
                    startIndex++;
Lines 2146-2161 Link Here
2146
            return results;
2056
            return results;
2147
        }
2057
        }
2148
2058
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
        /**
2059
        /**
2160
         * Copied and adapted from JTree.getNextMatch(...).
2060
         * Copied and adapted from JTree.getNextMatch(...).
2161
         * 
2061
         * 
Lines 2163-2169 Link Here
2163
         *         and the index of the first occurrence of the substring in TreePath.
2063
         *         and the index of the first occurrence of the substring in TreePath.
2164
         */
2064
         */
2165
        private SubstringSearchResult getNextSubstringMatch(
2065
        private SubstringSearchResult getNextSubstringMatch(
2166
                String substring, int startingRow, Position.Bias bias) {
2066
                String substring, int startingRow, boolean forward) {
2167
2067
2168
            int max = getRowCount();
2068
            int max = getRowCount();
2169
            if (substring == null) {
2069
            if (substring == null) {
Lines 2176-2182 Link Here
2176
2076
2177
            // start search from the next/previous element froom the 
2077
            // start search from the next/previous element froom the 
2178
            // selected element
2078
            // selected element
2179
            int increment = (bias == Position.Bias.Forward) ? 1 : -1;
2079
            int increment = (forward) ? 1 : -1;
2180
            int row = startingRow;
2080
            int row = startingRow;
2181
            do {
2081
            do {
2182
                TreePath path = getPathForRow(row);
2082
                TreePath path = getPathForRow(row);
Lines 2193-2198 Link Here
2193
            return null;
2093
            return null;
2194
        }
2094
        }
2195
2095
2096
        private void displaySearchResult() {
2097
            int sz = searchResults.size();
2098
2099
            if (sz > 0) {
2100
                if (currentSelectionIndex < 0) {
2101
                    currentSelectionIndex = sz - 1;
2102
                } else if (currentSelectionIndex >= sz) {
2103
                    currentSelectionIndex = 0;
2104
                }
2105
2106
                TreePath path = searchResults.get(currentSelectionIndex);
2107
                setSelectionPath(path);
2108
                scrollPathToVisible(path);
2109
            } else {
2110
                if (lastSearchText.isEmpty() && origSelectionPaths != null) {
2111
                    setSelectionPaths(origSelectionPaths);
2112
                    scrollPathToVisible(origSelectionPaths[0]);
2113
                } else {
2114
                    clearSelection();
2115
                }
2116
            }
2117
        }
2118
2196
        /** notify the Component to autoscroll */
2119
        /** notify the Component to autoscroll */
2197
        @Override
2120
        @Override
2198
        public void autoscroll(Point cursorLoc) {
2121
        public void autoscroll(Point cursorLoc) {
Lines 2295-2425 Link Here
2295
            }
2218
            }
2296
        }
2219
        }
2297
2220
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 {
2221
        private class AccessibleExplorerTree extends JTree.AccessibleJTree {
2424
            AccessibleExplorerTree() {
2222
            AccessibleExplorerTree() {
2425
            }
2223
            }
(-)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