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

(-)openide/src/org/openide/explorer/view/TreeView.java (-106 / +121 lines)
Lines 1127-1207 Link Here
1127
            }
1127
            }
1128
            setupSearch();
1128
            setupSearch();
1129
        }
1129
        }
1130
        
1130
    
1131
        private JTextField searchTextField = new JTextField();
1131
        private JTextField searchTextField = new JTextField();
1132
        final private int heightOfTextField = searchTextField.getPreferredSize().height;
1133
        
1132
        
1133
        final private int heightOfTextField = searchTextField.getPreferredSize().height;
1134
1134
        private void setupSearch() {
1135
        private void setupSearch() {
1136
            // Remove the default key listeners
1135
            KeyListener keyListeners[] = (KeyListener[]) (getListeners(KeyListener.class));
1137
            KeyListener keyListeners[] = (KeyListener[]) (getListeners(KeyListener.class));
1136
            for (int i = 0; i < keyListeners.length; i++) {
1138
            for (int i = 0; i < keyListeners.length; i++) {
1137
                removeKeyListener(keyListeners[i]);
1139
                removeKeyListener(keyListeners[i]);
1138
            }
1140
            }
1139
            // Invoked when the search field should be dismissed by using
1141
            // Add new key listeners
1140
            // the escape key
1141
            ActionListener escapeListener = new ActionListener() {
1142
                public void actionPerformed(ActionEvent e) {
1143
                    removeSearchField();
1144
                    ExplorerTree.this.requestFocus();
1145
                }
1146
            };
1147
            searchTextField.registerKeyboardAction(escapeListener, 
1148
                    KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 0);
1149
            // An action in the textfield will expand the selected node
1150
            searchTextField.addActionListener(new ActionListener() {
1151
                public void actionPerformed(ActionEvent e) {
1152
                    removeSearchField();
1153
                    ExplorerTree.this.requestFocus();
1154
                    expandPath(getSelectionPath());
1155
                }
1156
            });
1157
            // When the search field looses focus, hide it
1158
            searchTextField.addFocusListener(new FocusAdapter() {
1159
                public void focusLost(FocusEvent e) {
1160
                    removeSearchField();
1161
                }
1162
            });
1163
            // Every change in the search fields document adds invokes a new search
1164
            // action
1165
            searchTextField.getDocument().addDocumentListener(new DocumentListener() {
1166
                public void insertUpdate(DocumentEvent e) {
1167
                    searchForNode();
1168
                }
1169
                public void removeUpdate(DocumentEvent e) {
1170
                    searchForNode();
1171
                }
1172
                public void changedUpdate(DocumentEvent e) {
1173
                    searchForNode();
1174
                }
1175
1176
                private void searchForNode() {
1177
                    String text = searchTextField.getText().toUpperCase();
1178
                    if (text.length() == 0) {
1179
                        return;
1180
                    }
1181
                    
1182
                    TreePath selectionPath = getSelectionPath();
1183
                    TreePath rootPath = new TreePath(getModel().getRoot());
1184
                    TreePath newPath = null;
1185
                    if (selectionPath != null) {
1186
                        newPath = doSearch(text, selectionPath);
1187
                    }
1188
                    if (newPath == null) {
1189
                        newPath = doSearch(text, rootPath);
1190
                    }
1191
                    if (newPath != null) {
1192
                        setSelectionPath(newPath);
1193
                        scrollPathToVisible(newPath);
1194
                    } else {
1195
                        clearSelection();
1196
                    }
1197
                }
1198
            });
1199
            // The first key press in the tree must be dispatched to the text field
1200
            addKeyListener(new KeyAdapter() {
1142
            addKeyListener(new KeyAdapter() {
1201
                public void keyPressed(KeyEvent e) {
1143
                public void keyPressed(KeyEvent e) {
1202
                    if (e.getModifiers () > 0 ||
1144
                    int modifiers = e.getModifiers();
1203
                            KeyEvent.VK_DELETE == e.getKeyCode () ||
1145
                    int keyCode = e.getKeyCode();
1204
                            KeyEvent.VK_ESCAPE == e.getKeyCode ())
1146
                    // If the only modifier is SHIFT, allow it
1147
                    if ((modifiers > 0 && modifiers != KeyEvent.SHIFT_MASK) ||
1148
                            KeyEvent.VK_DELETE == keyCode ||
1149
                            KeyEvent.VK_ESCAPE == keyCode)
1205
                        return ;
1150
                        return ;
1206
                    char c = e.getKeyChar();
1151
                    char c = e.getKeyChar();
1207
                    if (Character.isJavaIdentifierPart(c) || (c == File.separatorChar)) {
1152
                    if (Character.isJavaIdentifierPart(c) || (c == File.separatorChar)) {
Lines 1210-1256 Link Here
1210
                    }
1155
                    }
1211
                }
1156
                }
1212
            });
1157
            });
1213
            // Any key press in the text field triggers the addition of the
1158
            // Create a the "multi-event" listener for the text field. Instead of
1214
            // search field to the tree
1159
            // adding separate instances of each needed listener, we're using a
1215
            ActionListener keyPressListener = new ActionListener() {
1160
            // class which implements them all. This approach is used in order 
1216
                public void actionPerformed(ActionEvent e) {
1161
            // to avoid the creation of 4 instances which takes some time
1217
                    displaySearchField();
1162
            SearchFieldListener searchFieldListener = new SearchFieldListener();
1163
            searchTextField.addKeyListener(searchFieldListener);
1164
            searchTextField.addFocusListener(searchFieldListener);
1165
            searchTextField.getDocument().addDocumentListener(searchFieldListener);
1166
        }
1167
        
1168
        private class SearchFieldListener extends KeyAdapter 
1169
                implements DocumentListener, FocusListener {
1170
            /** The last search results */
1171
            private ArrayList results = new ArrayList();
1172
            /** The last selected index from the search results. */
1173
            private int currentSelectionIndex;
1174
            
1175
            public void changedUpdate(DocumentEvent e) {
1176
                searchForNode();
1177
            }
1178
            
1179
            public void insertUpdate(DocumentEvent e) {
1180
                searchForNode();
1181
            }
1182
            
1183
            public void removeUpdate(DocumentEvent e) {
1184
                searchForNode();
1185
            }
1186
            
1187
            public void keyPressed(KeyEvent e) {
1188
                int keyCode = e.getKeyCode();
1189
                if (keyCode == KeyEvent.VK_ESCAPE) {
1190
                    removeSearchField();
1191
                } else if (keyCode == KeyEvent.VK_UP) {
1192
                    currentSelectionIndex--;
1193
                    displaySearchResult();
1194
                    // Stop processing the event here. Otherwise it's dispatched
1195
                    // to the tree too (which scrolls)
1196
                    e.consume();
1197
                } else if (keyCode == KeyEvent.VK_DOWN) {
1198
                    currentSelectionIndex++;
1199
                    displaySearchResult();
1200
                    // Stop processing the event here. Otherwise it's dispatched
1201
                    // to the tree too (which scrolls)
1202
                    e.consume();
1203
                } else if (keyCode == KeyEvent.VK_ENTER) {
1204
                    removeSearchField();
1205
                    expandPath(getSelectionPath());
1206
                    ExplorerTree.this.requestFocus();
1207
                    ExplorerTree.this.dispatchEvent(e);
1218
                }
1208
                }
1219
            };
1209
            }
1210
            
1211
            /** Searches for a node in the tree. */
1212
            private void searchForNode() {
1213
                currentSelectionIndex = 0;
1214
                results.clear();
1215
                String text = searchTextField.getText().toUpperCase();
1216
                if (text.length() > 0) {
1217
                    doSearch(text, results);
1218
                    displaySearchResult();
1219
                }
1220
            }
1220
            
1221
            
1222
            private void displaySearchResult() {
1223
                int sz = results.size();
1224
                if (sz > 0) {
1225
                    if (currentSelectionIndex < 0) {
1226
                        currentSelectionIndex = sz - 1;
1227
                    } else if (currentSelectionIndex >= sz) {
1228
                        currentSelectionIndex = 0;
1229
                    }
1230
                    TreePath path = (TreePath) results.get(currentSelectionIndex);
1231
                    setSelectionPath(path);
1232
                    scrollPathToVisible(path);
1233
                } else {
1234
                    clearSelection();
1235
                }
1236
            }
1237
            
1238
            public void focusGained(FocusEvent e) {
1239
                // Do nothing
1240
            }
1241
            
1242
            public void focusLost(FocusEvent e) {
1243
                removeSearchField();
1244
            }
1221
        }
1245
        }
1222
        
1246
1223
        private int originalScrollMode;
1247
        private int originalScrollMode;
1224
        
1248
        
1225
        /**
1249
        private void doSearch(String str, ArrayList results) {
1226
         * Method used to recursively search for a named node in a tree path.
1250
            int rows[] = getSelectionRows();
1227
         */
1251
            int row = (rows == null || rows.length == 0) ? 0 : rows[0];
1228
        private TreePath doSearch(String str, TreePath path) {
1252
            int rowCount = getRowCount();
1229
            TreeNode node = (TreeNode) path.getLastPathComponent();
1253
            for (int i = row; i < getRowCount(); i++) {
1230
            if (node.toString().toUpperCase().startsWith(str)) {
1254
                addPathIfMatches(str, i, results);
1231
                // Return if the current path matches
1232
                return path;
1233
            }
1255
            }
1234
            // It's a collapsed path, so return
1256
            for (int i = 0; i < row && i < rowCount; i++) {
1235
            if (isCollapsed(path)) {
1257
                addPathIfMatches(str, i, results);
1236
                return null;
1237
            }
1238
            Enumeration children = node.children();
1239
            while (children.hasMoreElements()) {
1240
                TreeNode child = (TreeNode) children.nextElement();
1241
                TreePath newPath = path.pathByAddingChild(child);
1242
                if (child.toString().toUpperCase().startsWith(str)) {
1243
                    return newPath;
1244
                }
1245
                // Recursive search
1246
                newPath = doSearch(str, newPath);
1247
                if (newPath != null) {
1248
                    return newPath;
1249
                }
1250
            }
1258
            }
1251
            return null;
1252
        }
1259
        }
1253
        
1260
        
1261
        private void addPathIfMatches(String str, int row, ArrayList results) {
1262
            TreePath path = getPathForRow(row);
1263
            TreeNode node = (TreeNode) path.getLastPathComponent();
1264
            if (node.toString().toUpperCase().startsWith(str)) {
1265
                results.add(path);
1266
            }
1267
        }
1268
1254
        /**
1269
        /**
1255
         * Adds the search field to the tree.
1270
         * Adds the search field to the tree.
1256
         */
1271
         */
Lines 1265-1279 Link Here
1265
                searchTextField.requestFocus();
1280
                searchTextField.requestFocus();
1266
            }
1281
            }
1267
        }
1282
        }
1268
        
1283
1269
        public void paint(Graphics g) {
1284
        public void paint(Graphics g) {
1270
            Rectangle visibleRect = getVisibleRect();
1285
            Rectangle visibleRect = getVisibleRect();
1271
            if (searchTextField.isDisplayable()) {
1286
            if (searchTextField.isDisplayable()) {
1272
                searchTextField.setBounds(
1287
                searchTextField.setBounds(
1273
                            Math.max(3, visibleRect.x + visibleRect.width - 163),
1288
                        Math.max(3, visibleRect.x + visibleRect.width - 163),
1274
                            visibleRect.y + 3,
1289
                        visibleRect.y + 3,
1275
                            Math.min(getPreferredSize().width - 6, 160),
1290
                        Math.min(getPreferredSize().width - 6, 160),
1276
                            heightOfTextField);
1291
                        heightOfTextField);
1277
            }
1292
            }
1278
            super.paint(g);
1293
            super.paint(g);
1279
        }
1294
        }
Lines 1283-1293 Link Here
1283
        private void removeSearchField() {
1298
        private void removeSearchField() {
1284
            remove(searchTextField);
1299
            remove(searchTextField);
1285
            TreeView.this.getViewport().setScrollMode(originalScrollMode);
1300
            TreeView.this.getViewport().setScrollMode(originalScrollMode);
1301
            ExplorerTree.this.requestFocus();
1286
            this.repaint();
1302
            this.repaint();
1287
        }
1303
        }
1288
1304
	
1289
1305
        /** notify the Component to autoscroll */
1290
	/** notify the Component to autoscroll */
1291
        public void autoscroll (Point cursorLoc) {
1306
        public void autoscroll (Point cursorLoc) {
1292
	    getSupport().autoscroll(cursorLoc);
1307
	    getSupport().autoscroll(cursorLoc);
1293
	}
1308
	}

Return to bug 28311