|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.java.ui.editors; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.util.Enumeration; import java.util.StringTokenizer; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.SwingUtilities; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.openide.nodes.Node; import org.openide.nodes.NodeOp; import org.openide.explorer.ExplorerManager; /** * This class is designed to be a liaison between an JTextComponent and * an Explorer TreeView. The class can be used either as one way synchonizer * between any {@link Document} and {@link ExplorerManager}, so it will parse * the document and select or expand appropriate nodes using the manager, or * a bidirectional one. In the latter case, it needs a JTextComponent to operate * on and it will complete the document, if possible, from the nodes collection * and manage selection for the user to save typing. * * @author sd99038 * @version */ public class TreePathWalker implements DocumentListener, PropertyChangeListener { /** * ExplorerManager used to navigate. */ ExplorerManager manager; /** * Current delimiter. */ String delimiter; /** * Text component to work with. */ JTextComponent textComponent; /** * Disable handling events from the explorer manager. */ boolean disableExplorer; /** * Default delimiter used to split input contents to a path. */ public static final String DEFAULT_DELIMITER = "."; // NOI18N /** * Constructs a navigator which uses a particular Explorer manager. Default * delimiter (dot) is used in this case. * @param em manager which will be used for navigation and context search */ public TreePathWalker(ExplorerManager em) { this(em, DEFAULT_DELIMITER); } /** * Constructs the navigator with some explorer manager and string tokenizer * used to split document contents into node names. * @param em manager which will be used for navigation and context search. * @param delimiter to use when parsing user input */ public TreePathWalker(ExplorerManager man, String delimiter) { this.delimiter = delimiter; this.manager = man; man.addPropertyChangeListener(this); } /** * Attaches the navigation support to a text component so it can * update selection in it. */ public void setTextComponent(JTextComponent text) { if (this.textComponent != null) textComponent.getDocument().removeDocumentListener(this); textComponent = text; if (text != null) text.getDocument().addDocumentListener(this); } /** * Retrieves the associated text component. * @return text component, or null. */ public JTextComponent getTextComponent() { return textComponent; } private void selectString(Document doc) { try { String s = doc.getText(0, doc.getLength()); selectString(s); } catch (BadLocationException ex) { } } /** * Implementation method. Do not call or override. */ public final void removeUpdate(javax.swing.event.DocumentEvent documentEvent) { //selectString(documentEvent.getDocument()); } /** * Implementation method. Do not call or override. */ public final void insertUpdate(javax.swing.event.DocumentEvent documentEvent) { selectString(documentEvent.getDocument()); } /** * Implementation method. Do not call or override. */ public final void changedUpdate(javax.swing.event.DocumentEvent documentEvent) { selectString(documentEvent.getDocument()); } private boolean nameMatches(Node child, String component) { return child.getName().startsWith(component); } private boolean namesEqual(Node child, String component) { return child.getName().equals(component); } private Enumeration enumerateComponents(String s) { return new StringTokenizer(s, getDelimiter()); } public String getDelimiter() { return this.delimiter; } public ExplorerManager getExplorerManager() { return this.manager; } /** * Method which actually selects (or attempts to) some node in the Manager. */ private void selectString(String sel) { Enumeration components = enumerateComponents(sel); Node context = getExplorerManager().getRootContext(); String component; Node found = null; boolean exact = false; String suffix = ""; // NOI18N //Collection candidates = new LinkedList(); boolean ambiguous = false; System.err.println("begin search"); // NOI18N while (components.hasMoreElements()) { String comp = (String)components.nextElement(); Enumeration children = context.getChildren().nodes(); int compLen = comp.length(); found = null; exact = false; //candidates.clear(); ambiguous = false; System.err.println("got component: " + comp); // NOI18N suffix = null; while (children.hasMoreElements()) { Node ch = (Node)children.nextElement(); String childName = ch.getName(); // node name does not start with the prefix -> ignore. if (!nameMatches(ch, comp)) { continue; } if (found != null) ambiguous = true; if (!exact) { found = ch; } if (namesEqual(ch, comp)) { // exact match! exact = true; // overrides ambiguous. suffix = ""; // NOI18N } else { String childSuffix = childName.substring(compLen); if (suffix == null) suffix = childSuffix; else suffix = commonPrefix(suffix, childSuffix); } // node matches, need to put it on the candidate list. //candidates.add(ch); } if (found == null || (ambiguous && !exact)) { // match was not found, or was not exact - we cannot // proceed to further items in the selector anyway. break; } context = found; } // nothing was found -> do nothing. if (found == null) return; if (exact || !ambiguous) { // select the corresponding Node in the ExplorerManager: selectNode(found); // if the text really ends in a separator -> expand the node! if (sel.endsWith(getDelimiter())) { expandNode(found); } } JTextComponent textComp = getTextComponent(); if ("".equals(suffix) || textComp == null) return; appendSelectedString(textComp, suffix); } private void expandNode(Node n) { getExplorerManager().setExploredContext(n); } private void selectNode(Node n) { try { disableExplorer = true; getExplorerManager().setSelectedNodes(new Node[] { n }); } catch (PropertyVetoException ex) { // ignore the veto. // Advanced feature -- display reason of the veto in // the text component's tooltip ?? } finally { disableExplorer = false; } } private void appendSelectedString(final JTextComponent comp, final String suffix) { if ("".equals(suffix)) return; final Document doc = comp.getDocument(); SwingUtilities.invokeLater(new Runnable() { public void run() { try { Caret c = comp.getCaret(); int docLength = doc.getLength(); doc.insertString(docLength, suffix, null); int newLength = doc.getLength(); c.setDot(newLength); c.moveDot(docLength); } catch (BadLocationException ex) { ex.printStackTrace(); } } }); } /** * Returns a common prefix of the two passed strings. */ private String commonPrefix(String first, String second) { int l1 = first.length(); int l2 = second.length(); int maxl = l1 > l2 ? l2 : l1; for (int i = 0; i < maxl; i++) { if (first.charAt(i) != second.charAt(i)) { return first.substring(0, i); } } return maxl == l1 ? first : second; } private void displayNodePath(Node target) { String[] path = NodeOp.createPath(target, getExplorerManager().getRootContext()); StringBuffer sb = new StringBuffer(); for (int i = 0; i < path.length; i++) { if (i > 0) sb.append(getDelimiter()); sb.append(path[i]); } JTextComponent txt = getTextComponent(); if (txt != null) { Document d = txt.getDocument(); try { d.remove(0, d.getLength()); d.insertString(0, sb.toString(), null); } catch (BadLocationException ex) { } } } public void propertyChange(java.beans.PropertyChangeEvent propertyChangeEvent) { if (disableExplorer) return; String evName = propertyChangeEvent.getPropertyName(); if (ExplorerManager.PROP_SELECTED_NODES.equals(evName)) { // Need a policy how to reflect changes made in the explorer back // to the document or input line Node[] selNodes = getExplorerManager().getSelectedNodes(); if (selNodes.length == 0) return; displayNodePath(selNodes[0]); } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.