KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.netbeans.modules.tasklist.client.SuggestionManager;
23 import org.netbeans.modules.tasklist.client.Suggestion;
24 import org.netbeans.modules.tasklist.client.SuggestionPerformer;
25 import org.netbeans.modules.tasklist.client.SuggestionAgent;
26
27 import java.util.List JavaDoc;
28 import java.util.ListIterator JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import org.openide.filesystems.FileObject;
32
33 /**
34  * Passive suggestion manager implementation:
35  * <ul>
36  * <li>creates Suggestion instances
37  * <li>always enabled and observed (does not know its views)
38  * <li>registers suggestions to provided list only
39  * (default register does nothing) supporting single
40  * suggestion type filters.
41  * </ul>
42  *
43  * <p>
44  * See {@link SuggestionManagerImpl} for active implementation
45  * that handles events from environment to identify currently
46  * opened file and shows suggestions related to it.
47  *
48  * @author Petr Kuzel
49  */

50 public class DefaultSuggestionManager extends SuggestionManager {
51
52     // See super for accurate javadoc
53
public SuggestionAgent createSuggestion(FileObject fo, String JavaDoc type,
54         String JavaDoc summary, SuggestionPerformer action, Object JavaDoc data) {
55
56         // "Sanitize" the summary: replace newlines with ':'
57
// " " or ":" (let's pick one).
58
// (Oh crap. What do we do about CRLF's? Replace with ": " ?
59
// This won't work right for \r-only systems, but surely OSX didn't
60
// keep that bad MacOS habit, did it?
61
if (summary.indexOf('\n') != -1) {
62             int n = summary.length();
63             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(2 * n); // worst case
64
for (int i = 0; i < n; i++) {
65                 char c = summary.charAt(i);
66                 if (c == '\n') {
67                     sb.append(':');
68                     sb.append(' ');
69                 } else if (c != '\r') {
70                     sb.append(c);
71                 }
72             }
73             summary = sb.toString();
74         }
75
76         SPIMonitor.log(" create type: " + type + " summary: " + summary); // NOI18N
77

78         SuggestionType st = SuggestionTypes.getDefault().getType(type);
79         if (st == null) {
80             throw new IllegalArgumentException JavaDoc("type " + st + // NOI18N
81
" is not registered");
82         }
83         SuggestionImpl s = new SuggestionImpl(fo,
84             summary, st, action, data);
85         return new SuggestionAgent(s);
86     }
87
88     public boolean isEnabled(String JavaDoc id) {
89         return true;
90     }
91
92     public boolean isObserved(String JavaDoc id) {
93         return true;
94     }
95
96     /**
97      * Must be over written, does nothing.
98      */

99     public void register(String JavaDoc type, List JavaDoc add, List JavaDoc remove) {
100         assert false : "This public contract is not implemented use private one!";
101     }
102
103
104     /**
105      * Update target tasklist including grouping (if over treshold).
106      *
107      * @param typeName suggestion type
108      * @param addList suggestions to add
109      * @param removeList suggestion sto remove or null
110      * @param tasklist target tasklist
111      * @param sizeKnown is this registration final (otherwise
112      * another one is planned by registrant)
113      */

114     public void register(String JavaDoc typeName,
115         List JavaDoc addList, List JavaDoc removeList,
116         SuggestionList tasklist, boolean sizeKnown) {
117
118         //System.err.println("register(" + typeName + ", " + addList +
119
// ", " + removeList + "," + tasklist + ", " +
120
// request + ", " + sizeKnown + ")");
121

122
123         // TODO check instanceof Task here, and throw an exception if not?
124

125         // Get the first element, and use its type as the type for all.
126
// This works because all elements in the list must have the same
127
// (meta?) type.
128
SuggestionType type = null;
129         if (typeName != null) {
130             type = SuggestionTypes.getDefault().getType(typeName);
131             if (type == null) {
132                 throw new IllegalArgumentException JavaDoc("No such SuggestionType: " + typeName);
133             }
134         }
135
136         /* Not yet necessary - I'm always stuffing the cache on docHidden()
137         // Clear SuggestionCache entry, if necessary
138         Suggestion first = null;
139         SuggestionProvider provider = null;
140         if ((addList != null) && (addList.size() > 0)) {
141             first = (Suggestion)addList.get(0);
142         } else if ((removeList != null) && (removeList.size() > 0)) {
143             first = (Suggestion)removeList.get(0);
144         }
145         if ((cache != null) && (first != null)) {
146             provider = first.getProvider();
147             if ((provider != null) &&
148                 (provider instanceof DocumentSuggestionProvider)) {
149                 Line l = first.getLine();
150                 if (l != null) {
151                     Document doc = TLUtils.getDocument(l);
152                     if (doc != null) {
153                         cache.remove(doc);
154                     }
155                 }
156             }
157         }
158         */

159
160
161         // Must iterate over the list repeatedly, if it contains
162
// multiple types
163
boolean split = (type == null);
164         ListIterator JavaDoc ita = null;
165         ListIterator JavaDoc itr = null;
166         if (split) {
167             List JavaDoc allAdds = addList;
168             List JavaDoc allRems = removeList;
169             if (allAdds != null) {
170                 ita = allAdds.listIterator();
171                 addList = new ArrayList JavaDoc(allAdds.size());
172             }
173             if (allRems != null) {
174                 itr = allRems.listIterator();
175                 removeList = new ArrayList JavaDoc(allRems.size());
176             }
177         }
178         while (true) {
179
180             // Populate the list with the next homogeneous subset of the
181
// same type
182
if (split) {
183                 if ((ita != null) && (ita.hasNext())) {
184                     addList.clear(); // setSize(0); ?
185
type = null;
186                     while (ita.hasNext()) {
187                         SuggestionImpl s = (SuggestionImpl) ita.next();
188                         if (type == null) {
189                             type = s.getSType();
190                         } else if (s.getSType() != type) {
191                             ita.previous(); // undo advance
192
break;
193                         }
194                         addList.add(s);
195                     }
196                 } else {
197                     addList = null;
198                 }
199
200                 if ((itr != null) && (itr.hasNext())) {
201                     removeList.clear();
202                     type = null;
203                     while (itr.hasNext()) {
204                         SuggestionImpl s = (SuggestionImpl) itr.next();
205                         if (type == null) {
206                             type = s.getSType();
207                         } else if (s.getSType() != type) {
208                             itr.previous(); // undo advance
209
break;
210                         }
211                         removeList.add(s);
212                     }
213                 } else {
214                     removeList = null;
215                 }
216
217                 if ((addList == null) && (removeList == null)) {
218                     break;
219                 }
220             }
221
222             SuggestionImpl category = tasklist.getCategoryTask(type, false);
223
224
225             // XXX [PERFORMANCE] Later I can compute the type more quickly
226
// than this - instead of counting each time, keep a count,
227
// stored in a hashmap (I already have a type registry. Just watch
228
// out and remember that because of the Directory Scanning action,
229
// you can have multiple clients of the type registry.
230
int currnum = 0;
231             if (category != null) {
232                 currnum = category.subtasksCount();
233             } else {
234                 Iterator JavaDoc it = tasklist.getTasks().iterator();
235                 while (it.hasNext()) {
236                     SuggestionImpl s = (SuggestionImpl) it.next();
237                     if (s.getSType() == type) {
238                         currnum++;
239                     }
240                 }
241             }
242             int addnum = (addList != null) ? addList.size() : 0;
243             int remnum = (removeList != null) ? removeList.size() : 0;
244             // Assume no stupidity like overlaps in tasks between the lists
245
int newSize = currnum + addnum - remnum;
246             if ((newSize > tasklist.getGroupTreshold()) && (getUnfilteredType() == null)) {
247                 // TODO - show the first MAX_INLINE-1 "inlined", followed by the
248
// category node? Or hide all below the category node? For now,
249
// doing the latter since it's a lot easier.
250

251                 if (category == null) {
252                     // Now should have subtasks, but previously we didn't;
253
// remove the tasks from the top list
254
category = tasklist.getCategoryTask(type, true);
255                     synchronized (this) {
256                         List JavaDoc leftover = null;
257                         if (removeList != null) {
258                             tasklist.addRemove(null, removeList, true, null, null);
259                         }
260                         if (currnum - remnum > 0) {
261                             leftover = new ArrayList JavaDoc(currnum);
262                             Iterator JavaDoc it = tasklist.getTasks().iterator();
263                             while (it.hasNext()) {
264                                 SuggestionImpl s = (SuggestionImpl) it.next();
265                                 if ((s.getSType() == type) &&
266                                         (s != category)) {
267                                     leftover.add(s);
268                                 }
269                             }
270                         }
271                         if ((leftover != null) && (leftover.size() > 0)) {
272                             tasklist.addRemove(null, leftover, false, null, null);
273                             tasklist.addRemove(leftover, null, true, category, null);
274                         }
275                         tasklist.addRemove(addList, null, true, category, null);
276                     }
277                 } else {
278                     // Updating tasks within the category node
279
tasklist.addRemove(addList, removeList, false, category, null);
280                 }
281
282                 // Leave category task around? Or simply make it invisible?
283
// (Need new Task attribute and appropriate handling in filter
284
// and export methods.) By leaving it around, we don't reorder
285
// the tasks on the user.
286
//tasklist.removeCategory((SuggestionImpl)suggestions.get(0).getParent(), false);
287
updateCategoryCount(category, sizeKnown); // TODO: skip this when filtered
288
} else {
289                 SuggestionImpl after = tasklist.findAfter(type);
290                 if (category == null) {
291                     // Didn't have category nodes before and don't need to
292
// now either...
293
boolean append = (after == null);
294                     tasklist.addRemove(addList, removeList, append, null, after);
295                 } else {
296                     // Had category nodes before but don't need them anymore...
297
// remove the tasks from the top list
298
synchronized (this) {
299                         if (removeList != null) {
300                             tasklist.addRemove(null, removeList, false, category,
301                                     null);
302                         }
303                         List JavaDoc leftover = category.getSubtasks();
304                         if (addList != null) {
305                             tasklist.addRemove(addList, null, true, null, after);
306                         }
307                         if ((leftover != null) && (leftover.size() > 0)) {
308                             tasklist.addRemove(leftover, null, true, null, after);
309                         }
310                     }
311                     tasklist.removeCategory(category, true);
312                 }
313             }
314             if (!split) {
315                 break;
316             }
317
318         }
319     }
320
321     private static void updateCategoryCount(SuggestionImpl category, boolean sizeKnown) {
322         SuggestionType type = category.getSType();
323         int count = category.subtasksCount();
324         String JavaDoc summary;
325         if ((count != 0) || sizeKnown) {
326             summary = type.getLocalizedName() + " (" + // NOI18N
327
Integer.toString(count) + ")"; // NOI18N
328
} else {
329             summary = type.getLocalizedName();
330         }
331         category.setSummary(summary);
332     }
333
334     // XXX premature optimatization, kick it away or
335
// invent view-providers filter events
336
// (e.g. existing global isObserved(), isEnabled() )
337

338     /**
339      * When non null, a filter is in effect and only the unfilteredType
340      * is showing.
341      * <p>
342      * Note that such unmatching suggestions can come from
343      * "side effect" type of suggestion providers at anytime.
344      */

345     private SuggestionType unfilteredType = null;
346
347     protected final SuggestionType getUnfilteredType() {
348         return unfilteredType;
349     }
350
351     protected final void setUnfilteredType(SuggestionType unfilteredType) {
352         this.unfilteredType = unfilteredType;
353     }
354
355 }
356
Popular Tags