KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > ui > editors > TreePathWalker


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.ui.editors;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyVetoException JavaDoc;
24
25 import java.util.Enumeration JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27
28 import javax.swing.event.DocumentListener JavaDoc;
29 import javax.swing.event.DocumentEvent JavaDoc;
30
31 import javax.swing.SwingUtilities JavaDoc;
32 import javax.swing.text.BadLocationException JavaDoc;
33 import javax.swing.text.Caret JavaDoc;
34 import javax.swing.text.Document JavaDoc;
35 import javax.swing.text.JTextComponent JavaDoc;
36
37 import org.openide.nodes.Node;
38 import org.openide.nodes.NodeOp;
39 import org.openide.explorer.ExplorerManager;
40
41
42 /**
43  * This class is designed to be a liaison between an JTextComponent and
44  * an Explorer TreeView. The class can be used either as one way synchonizer
45  * between any {@link Document} and {@link ExplorerManager}, so it will parse
46  * the document and select or expand appropriate nodes using the manager, or
47  * a bidirectional one. In the latter case, it needs a JTextComponent to operate
48  * on and it will complete the document, if possible, from the nodes collection
49  * and manage selection for the user to save typing.
50  *
51  * @author sd99038
52  * @version
53  */

54 public class TreePathWalker implements DocumentListener JavaDoc, PropertyChangeListener JavaDoc {
55     /**
56      * ExplorerManager used to navigate.
57      */

58     ExplorerManager manager;
59     
60     /**
61      * Current delimiter.
62      */

63     String JavaDoc delimiter;
64     
65     /**
66      * Text component to work with.
67      */

68     JTextComponent JavaDoc textComponent;
69     
70     /**
71      * Disable handling events from the explorer manager.
72      */

73     boolean disableExplorer;
74     
75     /**
76      * Default delimiter used to split input contents to a path.
77      */

78     public static final String JavaDoc DEFAULT_DELIMITER = "."; // NOI18N
79

80     /**
81      * Constructs a navigator which uses a particular Explorer manager. Default
82      * delimiter (dot) is used in this case.
83      * @param em manager which will be used for navigation and context search
84      */

85     public TreePathWalker(ExplorerManager em) {
86         this(em, DEFAULT_DELIMITER);
87     }
88     
89     /**
90      * Constructs the navigator with some explorer manager and string tokenizer
91      * used to split document contents into node names.
92      * @param em manager which will be used for navigation and context search.
93      * @param delimiter to use when parsing user input
94      */

95     public TreePathWalker(ExplorerManager man, String JavaDoc delimiter) {
96        this.delimiter = delimiter;
97        this.manager = man;
98        
99        man.addPropertyChangeListener(this);
100     }
101
102     /**
103      * Attaches the navigation support to a text component so it can
104      * update selection in it.
105      */

106     public void setTextComponent(JTextComponent JavaDoc text) {
107         if (this.textComponent != null)
108             textComponent.getDocument().removeDocumentListener(this);
109         textComponent = text;
110         if (text != null)
111             text.getDocument().addDocumentListener(this);
112     }
113     
114     /**
115      * Retrieves the associated text component.
116      * @return text component, or null.
117      */

118     public JTextComponent JavaDoc getTextComponent() {
119         return textComponent;
120     }
121     
122     private void selectString(Document JavaDoc doc) {
123         try {
124             String JavaDoc s = doc.getText(0, doc.getLength());
125             selectString(s);
126         } catch (BadLocationException JavaDoc ex) {
127         }
128     }
129
130     /**
131      * Implementation method. Do not call or override.
132      */

133     public final void removeUpdate(javax.swing.event.DocumentEvent JavaDoc documentEvent) {
134         //selectString(documentEvent.getDocument());
135
}
136
137     /**
138      * Implementation method. Do not call or override.
139      */

140     public final void insertUpdate(javax.swing.event.DocumentEvent JavaDoc documentEvent) {
141         selectString(documentEvent.getDocument());
142     }
143     
144     /**
145      * Implementation method. Do not call or override.
146      */

147     public final void changedUpdate(javax.swing.event.DocumentEvent JavaDoc documentEvent) {
148         selectString(documentEvent.getDocument());
149     }
150     
151     private boolean nameMatches(Node child, String JavaDoc component) {
152         return child.getName().startsWith(component);
153     }
154     
155     private boolean namesEqual(Node child, String JavaDoc component) {
156         return child.getName().equals(component);
157     }
158     
159     private Enumeration JavaDoc enumerateComponents(String JavaDoc s) {
160         return new StringTokenizer JavaDoc(s, getDelimiter());
161     }
162     
163     public String JavaDoc getDelimiter() {
164         return this.delimiter;
165     }
166     
167     public ExplorerManager getExplorerManager() {
168         return this.manager;
169     }
170
171     /**
172      * Method which actually selects (or attempts to) some node in the Manager.
173      */

174     private void selectString(String JavaDoc sel) {
175         Enumeration JavaDoc components = enumerateComponents(sel);
176         
177         Node context = getExplorerManager().getRootContext();
178         String JavaDoc component;
179         Node found = null;
180         boolean exact = false;
181         String JavaDoc suffix = ""; // NOI18N
182
//Collection candidates = new LinkedList();
183
boolean ambiguous = false;
184         
185         System.err.println("begin search"); // NOI18N
186

187         while (components.hasMoreElements()) {
188             String JavaDoc comp = (String JavaDoc)components.nextElement();
189             Enumeration JavaDoc children = context.getChildren().nodes();
190             int compLen = comp.length();
191             found = null;
192             exact = false;
193             //candidates.clear();
194
ambiguous = false;
195             
196             System.err.println("got component: " + comp); // NOI18N
197
suffix = null;
198             
199             while (children.hasMoreElements()) {
200                 Node ch = (Node)children.nextElement();
201                 String JavaDoc childName = ch.getName();
202
203                 // node name does not start with the prefix -> ignore.
204
if (!nameMatches(ch, comp)) {
205                     continue;
206                 }
207                 if (found != null)
208                     ambiguous = true;
209                 if (!exact) {
210                     found = ch;
211                 }
212                 if (namesEqual(ch, comp)) {
213                     // exact match!
214
exact = true; // overrides ambiguous.
215
suffix = ""; // NOI18N
216
} else {
217                     String JavaDoc childSuffix = childName.substring(compLen);
218                     if (suffix == null)
219                         suffix = childSuffix;
220                     else
221                         suffix = commonPrefix(suffix, childSuffix);
222                 }
223                 
224                 // node matches, need to put it on the candidate list.
225
//candidates.add(ch);
226
}
227             
228             if (found == null ||
229                 (ambiguous && !exact)) {
230                 // match was not found, or was not exact - we cannot
231
// proceed to further items in the selector anyway.
232
break;
233             }
234             
235             context = found;
236         }
237         // nothing was found -> do nothing.
238
if (found == null)
239             return;
240         
241         if (exact || !ambiguous) {
242             // select the corresponding Node in the ExplorerManager:
243
selectNode(found);
244             // if the text really ends in a separator -> expand the node!
245
if (sel.endsWith(getDelimiter())) {
246                 expandNode(found);
247             }
248         }
249         
250         JTextComponent JavaDoc textComp = getTextComponent();
251         if ("".equals(suffix) || textComp == null)
252             return;
253         appendSelectedString(textComp, suffix);
254     }
255
256     private void expandNode(Node n) {
257         getExplorerManager().setExploredContext(n);
258     }
259      
260     
261     private void selectNode(Node n) {
262         try {
263             disableExplorer = true;
264             getExplorerManager().setSelectedNodes(new Node[] {
265                 n
266             });
267         } catch (PropertyVetoException JavaDoc ex) {
268             // ignore the veto.
269
// Advanced feature -- display reason of the veto in
270
// the text component's tooltip ??
271
} finally {
272             disableExplorer = false;
273         }
274     }
275     
276     private void appendSelectedString(final JTextComponent JavaDoc comp, final String JavaDoc suffix) {
277         if ("".equals(suffix))
278             return;
279         
280         final Document JavaDoc doc = comp.getDocument();
281         SwingUtilities.invokeLater(new Runnable JavaDoc() {
282             public void run() {
283                 try {
284                     Caret JavaDoc c = comp.getCaret();
285                     int docLength = doc.getLength();
286                     doc.insertString(docLength, suffix, null);
287
288                     int newLength = doc.getLength();
289                     c.setDot(newLength);
290                     c.moveDot(docLength);
291                 } catch (BadLocationException JavaDoc ex) {
292                     ex.printStackTrace();
293                 }
294             }
295         });
296     }
297     
298     /**
299      * Returns a common prefix of the two passed strings.
300      */

301     private String JavaDoc commonPrefix(String JavaDoc first, String JavaDoc second) {
302         int l1 = first.length();
303         int l2 = second.length();
304         int maxl = l1 > l2 ? l2 : l1;
305         
306         for (int i = 0; i < maxl; i++) {
307             if (first.charAt(i) != second.charAt(i)) {
308                 return first.substring(0, i);
309             }
310         }
311         return maxl == l1 ? first : second;
312     }
313     
314     private void displayNodePath(Node target) {
315         String JavaDoc[] path = NodeOp.createPath(target, getExplorerManager().getRootContext());
316         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
317         for (int i = 0; i < path.length; i++) {
318             if (i > 0)
319                 sb.append(getDelimiter());
320             sb.append(path[i]);
321         }
322         JTextComponent JavaDoc txt = getTextComponent();
323         if (txt != null) {
324             Document JavaDoc d = txt.getDocument();
325             try {
326                 d.remove(0, d.getLength());
327                 d.insertString(0, sb.toString(), null);
328             } catch (BadLocationException JavaDoc ex) {
329             }
330         }
331     }
332     
333     public void propertyChange(java.beans.PropertyChangeEvent JavaDoc propertyChangeEvent) {
334         if (disableExplorer)
335             return;
336         
337         String JavaDoc evName = propertyChangeEvent.getPropertyName();
338         if (ExplorerManager.PROP_SELECTED_NODES.equals(evName)) {
339             // Need a policy how to reflect changes made in the explorer back
340
// to the document or input line
341
Node[] selNodes = getExplorerManager().getSelectedNodes();
342             if (selNodes.length == 0)
343                 return;
344             displayNodePath(selNodes[0]);
345         }
346     }
347 }
348
Popular Tags