KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > text > completion > NodeSelector


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.xml.text.completion;
21
22 import java.awt.Container JavaDoc;
23 import java.awt.event.ActionListener JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import javax.swing.JEditorPane JavaDoc;
26 import javax.swing.Timer JavaDoc;
27 import javax.swing.event.CaretEvent JavaDoc;
28 import javax.swing.event.CaretListener JavaDoc;
29 import javax.swing.text.BadLocationException JavaDoc;
30 import javax.swing.text.Caret JavaDoc;
31 import javax.swing.text.Document JavaDoc;
32
33 import org.netbeans.editor.BaseDocument;
34 import org.netbeans.modules.xml.api.model.GrammarQuery;
35 import org.netbeans.modules.xml.api.model.HintContext;
36 import org.netbeans.modules.xml.text.completion.XMLCompletionQuery;
37 import org.netbeans.modules.xml.text.completion.GrammarManager;
38 import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport;
39 import org.openide.nodes.FilterNode;
40 import org.openide.nodes.Node;
41 import org.openide.nodes.Sheet;
42 import org.openide.windows.TopComponent;
43 import org.openide.util.NbBundle;
44 import org.w3c.dom.DOMException JavaDoc;
45
46 /**
47  * Finds SyntaxNode at the Carat position in the text editor
48  * and asks grammars to provide customizer and properties.
49  * The customizer and properties are added to the selected node in the editors
50  * TopComponent.
51  *
52  * @author asgeir@dimonsoftware.com
53  */

54 public final class NodeSelector {
55     
56     /** Listener on caret movements */
57     private CaretListener JavaDoc caretListener;
58     
59     /** Timer which countdowns the "update selected element node" time. */ // NOI18N
60
private Timer JavaDoc timerSelNodes;
61     
62     /** The last caret offset position. */
63     private int lastCaretOffset = -1;
64     
65     /** Default delay between cursor movement and updating selected element nodes. */
66     private static final int SELECTED_NODES_DELAY = 200;
67     
68     private JEditorPane JavaDoc pane;
69     
70     private XMLSyntaxSupport syntaxSupport;
71     
72     private Node originalUINode;
73     
74     HintContext hintContext;
75     
76     /** Creates a new instance of NodeSelector */
77     public NodeSelector(final JEditorPane JavaDoc pane) {
78         this.pane = pane;
79         
80         caretListener = new CaretListener JavaDoc() {
81             public void caretUpdate(CaretEvent JavaDoc e) {
82                 restartTimerSelNodes(e.getDot());
83             }
84         };
85         
86         timerSelNodes = new Timer JavaDoc(100, new java.awt.event.ActionListener JavaDoc() {
87             public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
88                 if (lastCaretOffset == -1 && pane != null) {
89                     Caret JavaDoc caret = pane.getCaret();
90                     if (caret != null)
91                         lastCaretOffset = caret.getDot();
92                 }
93                 selectElementsAtOffset(lastCaretOffset);
94             }
95         });
96         timerSelNodes.setInitialDelay(100);
97         timerSelNodes.setRepeats(false);
98         timerSelNodes.restart();
99         
100         pane.addCaretListener(caretListener);
101
102         //!!! It should also listen on current TopComponent
103
}
104     
105     /** Restart the timer which updates the selected nodes after the specified delay from
106      * last caret movement.
107      */

108     void restartTimerSelNodes(int pos) {
109         timerSelNodes.setInitialDelay(SELECTED_NODES_DELAY);
110         lastCaretOffset = pos;
111         timerSelNodes.restart();
112     }
113     
114     /** Selects element at the given position. */
115     synchronized void selectElementsAtOffset(final int offset) {
116         if (syntaxSupport == null) {
117             Document JavaDoc doc = pane.getDocument();
118             if (doc instanceof BaseDocument) {
119                 syntaxSupport = (XMLSyntaxSupport) ((BaseDocument)doc).getSyntaxSupport();
120             }
121             if (syntaxSupport == null) {
122                 return;
123             }
124         }
125         
126         Container JavaDoc parent = pane.getParent();
127         while (parent != null && !(parent instanceof TopComponent)){
128             parent = parent.getParent();
129         }
130         if (parent == null) {
131             return;
132         }
133         
134         TopComponent topComp = (TopComponent)parent;
135         Node activeNodes[] = topComp.getActivatedNodes();
136         if (activeNodes == null || activeNodes.length == 0) {
137             return; // No nodes active
138
}
139         
140         if (originalUINode == null) {
141             originalUINode = activeNodes[0];
142         }
143
144         //it must be called from separate thread, it may the block UI thread
145

146         GrammarQuery grammarQuery = XMLCompletionQuery.getPerformer(pane.getDocument(), syntaxSupport);
147         if (grammarQuery == null) {
148             return;
149         }
150         
151         SyntaxQueryHelper helper = null;
152         try {
153             helper = new SyntaxQueryHelper(syntaxSupport, offset);
154         } catch (BadLocationException JavaDoc e) {
155             topComp.setActivatedNodes(new Node[]{new DelegatingNode(originalUINode, null, null)});
156             return;
157         }
158         
159         Node newUiNode = new DelegatingNode(originalUINode, grammarQuery, helper.getContext());
160         
161         topComp.setActivatedNodes(new Node[]{newUiNode});
162     }
163     
164     private class DelegatingNode extends FilterNode {
165         
166         GrammarQuery grammarQuery;
167         
168         HintContext hintContext;
169         
170         Sheet propSheet;
171         
172         public DelegatingNode(Node peer, GrammarQuery grammarQuery, HintContext hintContext) {
173             super(peer);
174             this.grammarQuery = grammarQuery;
175             this.hintContext = hintContext;
176         }
177         
178         public java.awt.Component JavaDoc getCustomizer() {
179             if (grammarQuery == null || hintContext == null) {
180                 return super.getCustomizer();
181             } else {
182                 return grammarQuery.getCustomizer(hintContext);
183             }
184         }
185         
186         public boolean hasCustomizer() {
187             if (grammarQuery == null || hintContext == null) {
188                 return super.hasCustomizer();
189             } else {
190                 return grammarQuery.hasCustomizer(hintContext);
191             }
192         }
193         
194         public Node.PropertySet[] getPropertySets() {
195             if (propSheet == null) {
196                 propSheet = Sheet.createDefault();
197                 Sheet.Set nodePropertySet = propSheet.get(Sheet.PROPERTIES);
198                 
199                 if (grammarQuery != null && hintContext != null) {
200                     Node.Property[] nodeProperties = grammarQuery.getProperties(hintContext);
201                     if (nodeProperties != null && nodeProperties.length > 0) {
202                         // The GrammarQuery controls the properties
203
nodePropertySet.put(nodeProperties);
204                         return propSheet.toArray();
205                     }
206                 }
207                 
208                 // By default, we try to create properties from the attributes of the
209
// selected element.
210
org.w3c.dom.Element JavaDoc attributeOwningElem = null;
211                 if (hintContext != null) {
212                     if (hintContext.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
213                         attributeOwningElem = (org.w3c.dom.Element JavaDoc)hintContext;
214                     } else if (hintContext.getNodeType() == org.w3c.dom.Node.ATTRIBUTE_NODE) {
215                         attributeOwningElem = (org.w3c.dom.Element JavaDoc)((org.w3c.dom.Attr JavaDoc)hintContext).getOwnerElement();
216                     }
217                 }
218                 
219                 if (attributeOwningElem != null) {
220                     // We have a selected element that might have attributes
221
org.w3c.dom.NamedNodeMap JavaDoc attributes = attributeOwningElem.getAttributes();
222                     for (int ind = 0; ind < attributes.getLength(); ind++) {
223                         org.w3c.dom.Node JavaDoc node = attributes.item(ind);
224                         nodePropertySet.put(new AttributeProperty(attributeOwningElem, node.getNodeName()));
225                     }
226                     
227                 }
228             }
229             
230             return propSheet.toArray();
231         }
232     }
233
234     /**
235      * It models attribute as node property.
236      */

237     private class AttributeProperty extends org.openide.nodes.PropertySupport {
238         private final String JavaDoc propName;
239         private final org.w3c.dom.Element JavaDoc ownerElem;
240         private boolean canWrite = true;
241
242         public AttributeProperty(org.w3c.dom.Element JavaDoc ownerElem, String JavaDoc propName) {
243             super(propName, String JavaDoc.class, propName, propName, true, true);
244             this.ownerElem = ownerElem;
245             this.propName = propName;
246         }
247         
248         public void setValue(Object JavaDoc value) {
249             try {
250                 ownerElem.setAttribute(propName, (String JavaDoc)value);
251             } catch (DOMException JavaDoc ex) {
252                 canWrite = false;
253             }
254         }
255         
256         public Object JavaDoc getValue() {
257             try {
258                 return ownerElem.getAttribute(propName);
259             } catch (DOMException JavaDoc ex) {
260                 // #29618 lifetime problem
261
canWrite = false;
262                 return NbBundle.getMessage(NodeSelector.class, "BK0001");
263             }
264         }
265
266         /**
267          * Writeability can change during lifetime.
268          * So nobody can cache this flag.
269          */

270         public boolean canWrite() {
271             return canWrite;
272         }
273
274     }
275 }
276
Popular Tags