KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > tasklist > suggestions > SuggestionCache


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.tasklist.suggestions;
21
22 import java.util.List JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.beans.PropertyChangeEvent JavaDoc;
28 import java.beans.PropertyChangeListener JavaDoc;
29 import javax.swing.text.Document JavaDoc;
30 import javax.swing.event.DocumentListener JavaDoc;
31 import javax.swing.event.DocumentEvent JavaDoc;
32 import org.netbeans.modules.tasklist.client.SuggestionPerformer;
33 import org.netbeans.modules.tasklist.client.SuggestionManager;
34 import org.openide.cookies.EditorCookie;
35 import org.openide.ErrorManager;
36 import org.openide.loaders.DataObject;
37 import org.openide.nodes.Node;
38 import org.netbeans.modules.tasklist.core.*;
39 import org.openide.text.CloneableEditorSupport;
40
41 /**
42   Implements a document suggestion cache.
43   This makes switching back and forth between files
44   "immediate" once the suggestions have been computed
45   in the first place. The suggestions are immediately
46   posted (not just meaning that it's not recomputed
47   so you get the slow refresh one by one, but there's
48   no delay either).
49 <p>
50 The cache works as follows:
51 <ul>
52    <li> When an entry is added to the cache, it adds a listener
53      to the document. If the document changes when the
54      document is not showing, the cache entry is invalidated/
55      removed.
56    <li> SuggestionImpl's keep a provider reference. When
57      you swap files, all the suggestions currently showing
58      are dumped to the cache.
59    <li> when you open a file, in docShown we first
60      consult the cache. If found, simply use those,
61      otherwise call docShown as before.
62    <li> TODO: the cache listens for document closes, and wipes
63      out cache entries
64    <li> PENDING: the cache is a weak listener so does not
65      prevent garbage collection.
66    <li> PENDING: Consider whether or not the cache should have
67      a max size.
68 </ul>
69 <p>
70 Here's how the SuggestionManager uses the cache:
71 <ul>
72   <li> When suggestions are modified for a document,
73         the cache is cleared for that document.
74   <li> When the suggestions window is hidden, the cache
75         is flushed
76   <li> When a file is switched:
77     <ul>
78      <li> the current contents are added to the cache. Some
79         optimization should be added here such that if you don't edit the
80         file that's open, no work is done. The items are then
81         removed from the list.
82      <li> the cache is consulted for the list in the existing
83         file, and only if empty (or is scanOnShow is true) does a
84         new scan take place.
85     </ul>
86    <li> When documents are closed, the cache should be notified.
87         This is done because the cache cannot easily listen for
88         document close events, and the suggestion manager already
89         has a way of detecting these.
90 </ul>
91 <p>
92   @todo What about suggestions derived from Documents which have
93      external dependencies? For example, after changing document
94      "foo", document Bar may get new scan errors in it - but
95      we wouldn't notice. Perhaps DocumentSuggestionProviders can
96      provide a hint about whether or not they expect their
97      contents to be 100% derivable from a single document.
98 <p>
99  * @author Tor Norbye
100  */

101
102 class SuggestionCache implements DocumentListener JavaDoc, PropertyChangeListener JavaDoc {
103
104     private HashMap JavaDoc map = null;
105
106     /** Add the given document and its associated suggestions
107         to the cache. It will automatically be removed when
108       <ul>
109        <li> The document is edited
110        <li> The document is closed
111        <li> The cache is full
112        <li> remove() is called
113        <li> flush() is called
114       </ul>
115      <p>
116         It's okay to call add repeatedly to update - you don't
117         have to call remove() between add() calls.
118      <p>
119         @param doc The document to monitor in the cache
120         @param suggestions The list of suggestions to cache.
121             NOTE: The list should not be null. It can be empty.
122             Null as returned from @{link lookup} means "entry
123             not in cache.
124     */

125     public void add(Document JavaDoc doc, DataObject dobj, List JavaDoc suggestions) {
126         if (map == null) {
127             map = new HashMap JavaDoc(60); // PENDING What size to use here?
128
}
129
130         doc.removeDocumentListener(this); // prevent double registering
131
doc.addDocumentListener(this);
132
133         EditorCookie.Observable observable =
134             (EditorCookie.Observable)dobj.getCookie(
135                                          EditorCookie.Observable.class);
136         if (observable != null) {
137             observable.removePropertyChangeListener(this); // prevent dupes
138
observable.addPropertyChangeListener(this);
139         }
140         Entry entry = new Entry(doc, suggestions, observable);
141         map.put(doc, entry);
142     }
143
144     /** Look up the given document's suggestions list.
145      * @param doc The document to look up suggestions for
146      * @return The list of suggestions associated with this
147      * document. Will return null if the document has
148      * not been cached, or if it has been flushed from the
149      * cache.
150      */

151     public List JavaDoc lookup(Document JavaDoc doc) {
152         if (map == null) {
153             return null;
154         }
155         Entry entry = (Entry)map.get(doc);
156         if (entry == null) {
157             return null;
158         }
159         return entry.list;
160     }
161
162     /** Remove all items from the cache */
163     public void flush() {
164         if (map == null) {
165             return;
166         }
167         map.clear();
168     }
169
170     /** Remove a particular document's stashed list in the
171         cache.
172         @param doc The document we want removed from the
173           cache
174     */

175     public void remove(Document JavaDoc doc) {
176         Entry entry = (Entry)map.remove(doc);
177         if (entry != null) {
178             // Was in the table - gotta remove doc listeners
179
doc.removeDocumentListener(this);
180             if (entry.listener != null) {
181                 entry.listener.removePropertyChangeListener(this);
182             }
183         }
184     }
185
186     /** Reacts to changes */
187     public void propertyChange(PropertyChangeEvent JavaDoc ev) {
188         String JavaDoc prop = ev.getPropertyName();
189         if (prop.equals(EditorCookie.Observable.PROP_DOCUMENT)) {
190             try {
191                 EditorCookie ec = (EditorCookie)ev.getSource();
192                 Document JavaDoc doc = ec.getDocument();
193                 invalidate(doc);
194             } catch (Exception JavaDoc e) {
195                 ErrorManager.getDefault().log("ev.getSource().getClass() = " + ev.getSource().getClass().getName());
196         ErrorManager.getDefault().
197              notify(ErrorManager.INFORMATIONAL, e);
198             }
199         }
200     }
201
202     /** The given document should be removed from the map */
203     private void invalidate(Document JavaDoc doc) {
204         remove(doc);
205     }
206
207     // Implements DocumentListener
208
public void changedUpdate(DocumentEvent JavaDoc e) {
209         // Don't care - attribute changes only
210
}
211
212     public void insertUpdate(DocumentEvent JavaDoc e) {
213         invalidate(e.getDocument());
214     }
215
216     public void removeUpdate(DocumentEvent JavaDoc e) {
217         invalidate(e.getDocument());
218     }
219
220     private static class Entry {
221     List JavaDoc list;
222         Document JavaDoc doc;
223         EditorCookie.Observable listener;
224
225         Entry(Document JavaDoc doc, List JavaDoc list, EditorCookie.Observable listener) {
226             this.list = list;
227             this.doc = doc;
228             this.listener = listener;
229         }
230     }
231 }
232
Popular Tags