Index: openide/src/org/openide/explorer/view/TreeView.java =================================================================== RCS file: /cvs/openide/src/org/openide/explorer/view/TreeView.java,v retrieving revision 1.101 diff -u -r1.101 TreeView.java --- openide/src/org/openide/explorer/view/TreeView.java 27 Sep 2002 17:14:52 -0000 1.101 +++ openide/src/org/openide/explorer/view/TreeView.java 24 Oct 2002 09:30:57 -0000 @@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; +import java.util.Enumeration; import java.util.ArrayList; import java.util.Arrays; import javax.swing.*; @@ -1123,6 +1124,162 @@ // TreeCancelEditingAction was fixed in BasicTreeUI for JDK1.4 getActionMap().put("cancel", new OurTreeCancelEditingAction()); // NOI18N } + setupSearch(); + } + + private JTextField searchTextField = new JTextField(); + + private void setupSearch() { + KeyListener keyListeners[] = getKeyListeners(); + for (int i = 0; i < keyListeners.length; i++) { + removeKeyListener(keyListeners[i]); + } + // Invoked when the search field should be dismissed by using + // the escape key + ActionListener escapeListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + removeSearchField(); + } + }; + searchTextField.registerKeyboardAction(escapeListener, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), 0); + // An action in the textfield will expand the selected node + searchTextField.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + removeSearchField(); + expandPath(getSelectionPath()); + } + }); + // When the search field looses focus, hide it +// searchTextField.addFocusListener(new FocusAdapter() { +// public void focusLost(FocusEvent e) { +// removeSearchField(); +// } +// }); + // Every change in the search fields document adds invokes a new search + // action + searchTextField.getDocument().addDocumentListener(new DocumentListener() { + public void insertUpdate(DocumentEvent e) { + searchForNode(); + } + public void removeUpdate(DocumentEvent e) { + searchForNode(); + } + public void changedUpdate(DocumentEvent e) { + searchForNode(); + } + + private void searchForNode() { + String text = searchTextField.getText().toUpperCase(); + if (text.length() == 0) { + return; + } + + TreePath selectionPath = getSelectionPath(); + TreePath rootPath = new TreePath(getModel().getRoot()); + TreePath newPath = null; + if (selectionPath != null) { + newPath = doSearch(text, selectionPath); + } + if (newPath == null) { + newPath = doSearch(text, rootPath); + } + if (newPath != null) { + setSelectionPath(newPath); + scrollPathToVisible(newPath); + } else { + clearSelection(); + } + } + }); + // The first key press in the tree must be dispatched to the text field + addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + char c = e.getKeyChar(); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + searchTextField.setText(String.valueOf(c)); + } + } + }); + // Any key press in the text field triggers the addition of the + // search field to the tree + ActionListener keyPressListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + displaySearchField(); + } + }; + registerKeyboardActions(keyPressListener, 'a', 'z'); + registerKeyboardActions(keyPressListener, 'A', 'Z'); + + } + + private int originalScrollMode; + + /** + * Method used to recursively search for a named node in a tree path. + */ + private TreePath doSearch(String str, TreePath path) { + TreeNode node = (TreeNode) path.getLastPathComponent(); + if (node.toString().toUpperCase().startsWith(str)) { + // Return if the current path matches + return path; + } + // It's a collapsed path, so return + if (isCollapsed(path)) { + return null; + } + Enumeration children = node.children(); + while (children.hasMoreElements()) { + TreeNode child = (TreeNode) children.nextElement(); + TreePath newPath = path.pathByAddingChild(child); + if (child.toString().toUpperCase().startsWith(str)) { + return newPath; + } + // Recursive search + newPath = doSearch(str, newPath); + if (newPath != null) { + return newPath; + } + } + return null; + } + + private void registerKeyboardActions(ActionListener keyPressListener, char lowerChar, char upperChar) { + for (char c = lowerChar; c <= upperChar; c++) { + registerKeyboardAction(keyPressListener, KeyStroke.getKeyStroke(c), 0); + } + } + /** + * Adds the search field to the tree. + */ + private void displaySearchField() { + if (!searchTextField.isDisplayable()) { + JViewport viewport = TreeView.this.getViewport(); + originalScrollMode = viewport.getScrollMode(); + viewport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE); + Rectangle visibleTreeRect = getVisibleRect(); + add(searchTextField); + repaint(); + searchTextField.requestFocus(); + } + } + + public void paint(Graphics g) { + Rectangle visibleRect = getVisibleRect(); + if (searchTextField.isDisplayable()) { + searchTextField.setBounds(visibleRect.x + visibleRect.width - 163, visibleRect.y + 3, 160, 18); + } + super.paint(g); + } + /** + * Removes the search field from the tree. + */ + private void removeSearchField() { + searchTextField.setText(""); + remove(searchTextField); + TreeView.this.getViewport().setScrollMode(originalScrollMode); + repaint(); + requestFocus(); }