001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.tasklist.impl;
043:
044: import java.util.ArrayList;
045: import java.util.Collections;
046: import java.util.Comparator;
047: import java.util.HashMap;
048: import java.util.HashSet;
049: import java.util.Iterator;
050: import java.util.LinkedList;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.Set;
054: import java.util.concurrent.locks.ReadWriteLock;
055: import java.util.concurrent.locks.ReentrantReadWriteLock;
056: import org.netbeans.modules.tasklist.filter.TaskFilter;
057: import org.netbeans.modules.tasklist.trampoline.TaskGroup;
058: import org.netbeans.spi.tasklist.FileTaskScanner;
059: import org.netbeans.spi.tasklist.PushTaskScanner;
060: import org.netbeans.spi.tasklist.Task;
061: import org.openide.filesystems.FileObject;
062: import org.openide.util.WeakSet;
063:
064: /**
065: * @author S. Aubrecht
066: */
067: public class TaskList {
068:
069: private ArrayList<Task> sortedTasks = new ArrayList<Task>(0);
070: private Set<Task> allTasks = new HashSet<Task>(0);
071:
072: private Map<PushTaskScanner, List<Task>> pushScanner2tasks = new HashMap<PushTaskScanner, List<Task>>(
073: 10);
074: private Map<FileTaskScanner, List<Task>> fileScanner2tasks = new HashMap<FileTaskScanner, List<Task>>(
075: 10);
076:
077: private Map<TaskGroup, List<Task>> group2tasks = new HashMap<TaskGroup, List<Task>>(
078: 10);
079:
080: private WeakSet<Listener> listeners = new WeakSet<Listener>(2);
081:
082: private final ReadWriteLock lock = new ReentrantReadWriteLock();
083:
084: private Comparator<Task> comparator;
085:
086: /** Creates a new instance of TaskList */
087: public TaskList() {
088: }
089:
090: void setTasks(PushTaskScanner scanner, FileObject resource,
091: List<? extends Task> tasks, TaskFilter filter) {
092: lock.writeLock().lock();
093:
094: List<Task> removed = clear(scanner, resource);
095:
096: List<Task> tasksToAdd = null;
097: int currentCount = countTasks(scanner);
098: for (Task t : tasks) {
099: if (filter.accept(t)
100: && !filter.isTaskCountLimitReached(currentCount)) {
101: currentCount++;
102:
103: if (allTasks.contains(t))
104: continue;
105:
106: if (null == tasksToAdd)
107: tasksToAdd = new ArrayList<Task>(tasks.size());
108:
109: List<Task> scannerTasks = pushScanner2tasks
110: .get(scanner);
111: if (null == scannerTasks) {
112: scannerTasks = new LinkedList<Task>();
113: pushScanner2tasks.put(scanner, scannerTasks);
114: }
115:
116: TaskGroup group = Accessor.getGroup(t);
117: List<Task> groupTasks = group2tasks.get(group);
118: if (null == groupTasks) {
119: groupTasks = new LinkedList<Task>();
120: group2tasks.put(group, groupTasks);
121: }
122:
123: tasksToAdd.add(t);
124: scannerTasks.add(t);
125: groupTasks.add(t);
126: allTasks.add(t);
127: }
128: }
129: if (null != tasksToAdd) {
130: sortedTasks.addAll(tasksToAdd);
131: Collections.sort(sortedTasks, getComparator());
132: }
133:
134: lock.writeLock().unlock();
135:
136: if (null != removed && !removed.isEmpty())
137: fireTasksRemoved(removed);
138: if (null != tasksToAdd && !tasksToAdd.isEmpty())
139: fireTasksAdded(tasksToAdd);
140: }
141:
142: void clear(PushTaskScanner scanner) {
143: lock.writeLock().lock();
144: List<Task> toRemove = pushScanner2tasks.get(scanner);
145: pushScanner2tasks.remove(scanner);
146: if (null != toRemove) {
147: for (List<Task> groupTasks : group2tasks.values()) {
148: groupTasks.removeAll(toRemove);
149: }
150: sortedTasks.removeAll(toRemove);
151: allTasks.removeAll(toRemove);
152: }
153: lock.writeLock().unlock();
154:
155: if (null != toRemove && !toRemove.isEmpty()) {
156: fireTasksRemoved(toRemove);
157: }
158: }
159:
160: private int countTasks(PushTaskScanner scanner) {
161: List<Task> tasks = pushScanner2tasks.get(scanner);
162: return null == tasks ? 0 : tasks.size();
163: }
164:
165: private List<Task> clear(PushTaskScanner scanner,
166: FileObject resource) {
167: List<Task> toRemove = null;
168: List<Task> tasks = pushScanner2tasks.get(scanner);
169: if (null != tasks) {
170: for (Task t : tasks) {
171: if (resource.equals(Accessor.getResource(t))) {
172: if (null == toRemove)
173: toRemove = new LinkedList<Task>();
174: toRemove.add(t);
175: }
176: }
177: }
178:
179: if (null != toRemove) {
180: sortedTasks.removeAll(toRemove);
181: allTasks.removeAll(toRemove);
182: tasks.removeAll(toRemove);
183: for (List<Task> groupTasks : group2tasks.values()) {
184: groupTasks.removeAll(toRemove);
185: }
186: }
187: return toRemove;
188: }
189:
190: void update(FileTaskScanner scanner, FileObject resource,
191: List<Task> newTasks, TaskFilter filter) {
192: lock.writeLock().lock();
193:
194: List<Task> removed = clear(scanner, resource);
195:
196: ArrayList<Task> tasksToAdd = new ArrayList<Task>(newTasks
197: .size());
198: for (Task t : newTasks) {
199: if (allTasks.contains(t))
200: continue;
201: if (!filter.isTaskCountLimitReached(countTasks(scanner))
202: && filter.accept(t)) {
203: List<Task> scannerTasks = fileScanner2tasks
204: .get(scanner);
205: if (null == scannerTasks) {
206: scannerTasks = new LinkedList<Task>();
207: fileScanner2tasks.put(scanner, scannerTasks);
208: }
209: TaskGroup group = Accessor.getGroup(t);
210: List<Task> groupTasks = group2tasks.get(group);
211: if (null == groupTasks) {
212: groupTasks = new LinkedList<Task>();
213: group2tasks.put(group, groupTasks);
214: }
215: scannerTasks.add(t);
216: groupTasks.add(t);
217: tasksToAdd.add(t);
218: allTasks.add(t);
219: }
220: }
221: if (!tasksToAdd.isEmpty()) {
222: sortedTasks.addAll(tasksToAdd);
223: Collections.sort(sortedTasks, getComparator());
224: }
225:
226: lock.writeLock().unlock();
227:
228: if (null != removed && !removed.isEmpty())
229: fireTasksRemoved(removed);
230: if (!tasksToAdd.isEmpty())
231: fireTasksAdded(tasksToAdd);
232: }
233:
234: public int size() {
235: int retValue = 0;
236: lock.readLock().lock();
237: retValue = sortedTasks.size();
238: lock.readLock().unlock();
239: return retValue;
240: }
241:
242: public List<? extends Task> getTasks() {
243: return new ArrayList<Task>(sortedTasks);
244: }
245:
246: int countTasks(FileTaskScanner scanner) {
247: List<Task> tasks = fileScanner2tasks.get(scanner);
248: return null == tasks ? 0 : tasks.size();
249: }
250:
251: public int countTasks(TaskGroup group) {
252: List<Task> groupTasks = group2tasks.get(group);
253: return null == groupTasks ? 0 : groupTasks.size();
254: }
255:
256: public Task getTask(int index) {
257: Task retValue = null;
258: lock.readLock().lock();
259: if (index >= 0 && index < sortedTasks.size())
260: retValue = sortedTasks.get(index);
261: lock.readLock().unlock();
262: return retValue;
263: }
264:
265: void clear(FileTaskScanner scanner) {
266: lock.writeLock().lock();
267: List<Task> toRemove = fileScanner2tasks.get(scanner);
268: fileScanner2tasks.remove(scanner);
269: if (null != toRemove) {
270: for (List<Task> groupTasks : group2tasks.values()) {
271: groupTasks.removeAll(toRemove);
272: }
273: sortedTasks.removeAll(toRemove);
274: allTasks.removeAll(toRemove);
275: }
276: lock.writeLock().unlock();
277:
278: if (null != toRemove && !toRemove.isEmpty()) {
279: fireTasksRemoved(toRemove);
280: }
281: }
282:
283: void clear(FileTaskScanner scanner, FileObject... resources) {
284: lock.readLock().lock();
285: ArrayList<Task> toRemove = null;
286: List<Task> tasks = fileScanner2tasks.get(scanner);
287: if (null != tasks) {
288: for (Task t : tasks) {
289: for (FileObject rc : resources) {
290: if (rc.equals(Accessor.getResource(t))) {
291: if (null == toRemove)
292: toRemove = new ArrayList<Task>(
293: resources.length);
294: toRemove.add(t);
295: }
296: }
297: }
298: }
299: lock.readLock().unlock();
300:
301: if (null != toRemove && !toRemove.isEmpty()) {
302: lock.writeLock().lock();
303: sortedTasks.removeAll(toRemove);
304: allTasks.removeAll(toRemove);
305: tasks.removeAll(toRemove);
306: for (List<Task> groupTasks : group2tasks.values()) {
307: groupTasks.removeAll(toRemove);
308: }
309: lock.writeLock().unlock();
310:
311: fireTasksRemoved(toRemove);
312: }
313: }
314:
315: private List<Task> clear(FileTaskScanner scanner,
316: FileObject resource) {
317: List<Task> tasks = fileScanner2tasks.get(scanner);
318: if (null == tasks)
319: return null;
320: List<Task> toRemove = null;
321: for (Task t : tasks) {
322: if (resource.equals(Accessor.getResource(t))) {
323: if (null == toRemove)
324: toRemove = new LinkedList<Task>();
325: toRemove.add(t);
326: }
327: }
328:
329: if (null != toRemove) {
330: sortedTasks.removeAll(toRemove);
331: allTasks.removeAll(toRemove);
332: tasks.removeAll(toRemove);
333: for (List<Task> groupTasks : group2tasks.values()) {
334: groupTasks.removeAll(toRemove);
335: }
336: }
337: return toRemove;
338: }
339:
340: void clear(FileObject resource) {
341: List<Task> toRemove = null;
342:
343: lock.writeLock().lock();
344:
345: for (List<Task> scannerTasks : fileScanner2tasks.values()) {
346: for (Task t : scannerTasks) {
347: if (resource.equals(Accessor.getResource(t))) {
348: if (null == toRemove)
349: toRemove = new LinkedList<Task>();
350: toRemove.add(t);
351: }
352: }
353: }
354:
355: if (null != toRemove) {
356:
357: sortedTasks.removeAll(toRemove);
358: allTasks.removeAll(toRemove);
359: for (List<Task> scannerTasks : fileScanner2tasks.values()) {
360: scannerTasks.removeAll(toRemove);
361: }
362: for (List<Task> groupTasks : group2tasks.values()) {
363: groupTasks.removeAll(toRemove);
364: }
365: }
366:
367: lock.writeLock().unlock();
368:
369: if (null != toRemove) {
370: fireTasksRemoved(toRemove);
371: }
372: }
373:
374: void clear() {
375: lock.writeLock().lock();
376: sortedTasks.clear();
377: allTasks.clear();
378: fileScanner2tasks.clear();
379: pushScanner2tasks.clear();
380: group2tasks.clear();
381: lock.writeLock().unlock();
382: fireCleared();
383: }
384:
385: public void addListener(Listener l) {
386: listeners.add(l);
387: }
388:
389: public void removeListener(Listener l) {
390: listeners.remove(l);
391: }
392:
393: public int indexOf(Task t) {
394: return sortedTasks.indexOf(t);
395: }
396:
397: private Comparator<Task> getComparator() {
398: if (null == comparator)
399: comparator = TaskComparator.getDefault();
400: return comparator;
401: }
402:
403: public void setComparator(Comparator<Task> comparator) {
404: if (getComparator().equals(comparator)) {
405: return;
406: }
407:
408: lock.writeLock().lock();
409:
410: this .comparator = comparator;
411: Collections.sort(sortedTasks, getComparator());
412:
413: lock.writeLock().unlock();
414: }
415:
416: private void fireTasksAdded(List<Task> tasks) {
417: ArrayList<Listener> tmp = new ArrayList<TaskList.Listener>(
418: listeners);
419: for (Iterator<Listener> i = tmp.iterator(); i.hasNext();) {
420: i.next().tasksAdded(tasks);
421: }
422: }
423:
424: private void fireTasksRemoved(List<Task> tasks) {
425: ArrayList<Listener> tmp = new ArrayList<TaskList.Listener>(
426: listeners);
427: for (Iterator<Listener> i = tmp.iterator(); i.hasNext();) {
428: i.next().tasksRemoved(tasks);
429: }
430: }
431:
432: private void fireCleared() {
433: ArrayList<Listener> tmp = new ArrayList<TaskList.Listener>(
434: listeners);
435: for (Iterator<Listener> i = tmp.iterator(); i.hasNext();) {
436: i.next().cleared();
437: }
438: }
439:
440: public static interface Listener {
441: void tasksAdded(List<? extends Task> tasks);
442:
443: void tasksRemoved(List<? extends Task> tasks);
444:
445: void cleared();
446: }
447: }
|