@@ -, +, @@ Index: TreeView.java =================================================================== RCS file: /cvs/openide/src/org/openide/explorer/view/TreeView.java,v retrieving revision 1.101 retrieving revision 1.102 diff -u -b -r1.101 -r1.102 --- TreeView.java 2002/09/27 17:14:52 1.101 +++ TreeView.java 2002/10/25 13:14:48 1.102 @@ -23,6 +23,8 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; +import java.io.File; +import java.util.Enumeration; import java.util.ArrayList; import java.util.Arrays; import javax.swing.*; @@ -1123,6 +1125,161 @@ // TreeCancelEditingAction was fixed in BasicTreeUI for JDK1.4 getActionMap().put("cancel", new OurTreeCancelEditingAction()); // NOI18N } + setupSearch(); + } + + private JTextField searchTextField = new JTextField(); + final private int heightOfTextField = searchTextField.getPreferredSize().height; + + private void setupSearch() { + KeyListener keyListeners[] = (KeyListener[]) (getListeners(KeyListener.class)); + 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(); + ExplorerTree.this.requestFocus(); + } + }; + 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(); + ExplorerTree.this.requestFocus(); + 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 (Character.isJavaIdentifierPart(c)||(c == File.separatorChar)) { + searchTextField.setText(String.valueOf(c)); + displaySearchField(); + } + } + }); + // 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(); + } + }; + + } + + 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; + } + + /** + * 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( + Math.max(3, visibleRect.x + visibleRect.width - 163), + visibleRect.y + 3, + Math.min(getPreferredSize().width - 6, 160), + heightOfTextField); + } + super.paint(g); + } + /** + * Removes the search field from the tree. + */ + private void removeSearchField() { + remove(searchTextField); + TreeView.this.getViewport().setScrollMode(originalScrollMode); + this.repaint(); }