001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.progress;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Comparator;
015: import java.util.Date;
016: import java.util.HashMap;
017: import java.util.HashSet;
018:
019: import org.eclipse.core.commands.common.EventManager;
020: import org.eclipse.core.runtime.IStatus;
021: import org.eclipse.core.runtime.jobs.Job;
022: import org.eclipse.ui.actions.ActionFactory;
023: import org.eclipse.ui.progress.IProgressConstants;
024:
025: /**
026: * This singleton remembers all JobTreeElements that should be preserved (e.g.
027: * because their associated Jobs have the "keep" property set).
028: */
029: public class FinishedJobs extends EventManager {
030:
031: /*
032: * Interface for notify listeners.
033: */
034: static interface KeptJobsListener {
035:
036: /**
037: * A job to be kept has finished
038: *
039: * @param jte
040: */
041: void finished(JobTreeElement jte);
042:
043: /**
044: * A kept job has been removed.
045: *
046: * @param jte
047: */
048: void removed(JobTreeElement jte);
049: }
050:
051: private static FinishedJobs theInstance;
052:
053: private IJobProgressManagerListener listener;
054:
055: private HashSet keptjobinfos = new HashSet();
056:
057: private HashMap finishedTime = new HashMap();
058:
059: private static JobTreeElement[] EMPTY_INFOS;
060:
061: public static synchronized FinishedJobs getInstance() {
062: if (theInstance == null) {
063: theInstance = new FinishedJobs();
064: EMPTY_INFOS = new JobTreeElement[0];
065: }
066: return theInstance;
067: }
068:
069: private FinishedJobs() {
070: listener = new IJobProgressManagerListener() {
071: public void addJob(JobInfo info) {
072: checkForDuplicates(info);
073: }
074:
075: public void addGroup(GroupInfo info) {
076: checkForDuplicates(info);
077: }
078:
079: public void refreshJobInfo(JobInfo info) {
080: checkTasks(info);
081: }
082:
083: public void refreshGroup(GroupInfo info) {
084: }
085:
086: public void refreshAll() {
087: }
088:
089: public void removeJob(JobInfo info) {
090: if (keep(info)) {
091: checkForDuplicates(info);
092: add(info);
093: }
094: }
095:
096: public void removeGroup(GroupInfo group) {
097: }
098:
099: public boolean showsDebug() {
100: return false;
101: }
102: };
103: ProgressManager.getInstance().addListener(listener);
104: }
105:
106: /**
107: * Returns true if JobInfo indicates that it must be kept.
108: */
109: static boolean keep(JobInfo info) {
110: Job job = info.getJob();
111: if (job != null) {
112: Object prop = job
113: .getProperty(ProgressManagerUtil.KEEP_PROPERTY);
114: if (prop instanceof Boolean) {
115: if (((Boolean) prop).booleanValue()) {
116: return true;
117: }
118: }
119:
120: prop = job
121: .getProperty(ProgressManagerUtil.KEEPONE_PROPERTY);
122: if (prop instanceof Boolean) {
123: if (((Boolean) prop).booleanValue()) {
124: return true;
125: }
126: }
127:
128: IStatus status = job.getResult();
129: if (status != null && status.getSeverity() == IStatus.ERROR) {
130: return true;
131: }
132: }
133: return false;
134: }
135:
136: /**
137: * Register for notification.
138: */
139: void addListener(KeptJobsListener l) {
140: addListenerObject(l);
141: }
142:
143: /**
144: * Deregister for notification.
145: */
146: void removeListener(KeptJobsListener l) {
147: removeListenerObject(l);
148: }
149:
150: private void checkForDuplicates(GroupInfo info) {
151: Object[] objects = info.getChildren();
152: for (int i = 0; i < objects.length; i++) {
153: if (objects[i] instanceof JobInfo) {
154: checkForDuplicates((JobInfo) objects[i]);
155: }
156: }
157: }
158:
159: private void checkForDuplicates(JobTreeElement info) {
160: JobTreeElement[] toBeRemoved = findJobsToRemove(info);
161: if (toBeRemoved != null) {
162: for (int i = 0; i < toBeRemoved.length; i++) {
163: remove(toBeRemoved[i]);
164: }
165: }
166: }
167:
168: /**
169: * Add given Job to list of kept jobs.
170: */
171: private void add(JobInfo info) {
172: boolean fire = false;
173:
174: synchronized (keptjobinfos) {
175: if (!keptjobinfos.contains(info)) {
176: keptjobinfos.add(info);
177:
178: long now = System.currentTimeMillis();
179: finishedTime.put(info, new Long(now));
180:
181: Object parent = info.getParent();
182: if (parent != null && !keptjobinfos.contains(parent)) {
183: keptjobinfos.add(parent);
184: finishedTime.put(parent, new Long(now));
185: }
186:
187: fire = true;
188: }
189: }
190:
191: if (fire) {
192: Object l[] = getListeners();
193: for (int i = 0; i < l.length; i++) {
194: KeptJobsListener jv = (KeptJobsListener) l[i];
195: jv.finished(info);
196: }
197: }
198: }
199:
200: static void disposeAction(JobTreeElement jte) {
201: if (jte.isJobInfo()) {
202: JobInfo ji = (JobInfo) jte;
203: Job job = ji.getJob();
204: if (job != null) {
205: Object prop = job
206: .getProperty(IProgressConstants.ACTION_PROPERTY);
207: if (prop instanceof ActionFactory.IWorkbenchAction) {
208: ((ActionFactory.IWorkbenchAction) prop).dispose();
209: }
210: }
211: }
212: }
213:
214: private JobTreeElement[] findJobsToRemove(JobTreeElement info) {
215:
216: if (info.isJobInfo()) {
217: Job myJob = ((JobInfo) info).getJob();
218:
219: if (myJob != null) {
220:
221: Object prop = myJob
222: .getProperty(ProgressManagerUtil.KEEPONE_PROPERTY);
223: if (prop instanceof Boolean
224: && ((Boolean) prop).booleanValue()) {
225: ArrayList found = null;
226: JobTreeElement[] all;
227: synchronized (keptjobinfos) {
228: all = (JobTreeElement[]) keptjobinfos
229: .toArray(new JobTreeElement[keptjobinfos
230: .size()]);
231: }
232: for (int i = 0; i < all.length; i++) {
233: JobTreeElement jte = all[i];
234: if (jte != info && jte.isJobInfo()) {
235: Job job = ((JobInfo) jte).getJob();
236: if (job != null && job != myJob
237: && job.belongsTo(myJob)) {
238: if (found == null) {
239: found = new ArrayList();
240: }
241: found.add(jte);
242: }
243: }
244: }
245: if (found != null) {
246: return (JobTreeElement[]) found
247: .toArray(new JobTreeElement[found
248: .size()]);
249: }
250: }
251: }
252: }
253: return null;
254: }
255:
256: private void checkTasks(JobInfo info) {
257: if (keep(info)) {
258: TaskInfo tinfo = info.getTaskInfo();
259: if (tinfo != null) {
260: JobTreeElement[] toBeRemoved = null;
261: boolean fire = false;
262: JobTreeElement element = (JobTreeElement) tinfo
263: .getParent();
264: synchronized (keptjobinfos) {
265: if (element == info
266: && !keptjobinfos.contains(tinfo)) {
267: toBeRemoved = findJobsToRemove(element);
268: keptjobinfos.add(tinfo);
269: finishedTime.put(tinfo, new Long(System
270: .currentTimeMillis()));
271: }
272: }
273:
274: if (toBeRemoved != null) {
275: for (int i = 0; i < toBeRemoved.length; i++) {
276: remove(toBeRemoved[i]);
277: }
278: }
279:
280: if (fire) {
281: Object l[] = getListeners();
282: for (int i = 0; i < l.length; i++) {
283: KeptJobsListener jv = (KeptJobsListener) l[i];
284: jv.finished(info);
285: }
286: }
287: }
288: }
289: }
290:
291: public void removeErrorJobs() {
292: JobTreeElement[] infos = getJobInfos();
293: for (int i = 0; i < infos.length; i++) {
294: if (infos[i].isJobInfo()) {
295: JobInfo info1 = (JobInfo) infos[i];
296: Job job = info1.getJob();
297: if (job != null) {
298: IStatus status = job.getResult();
299: if (status != null
300: && status.getSeverity() == IStatus.ERROR) {
301: JobTreeElement topElement = (JobTreeElement) info1
302: .getParent();
303: if (topElement == null) {
304: topElement = info1;
305: }
306: FinishedJobs.getInstance().remove(topElement);
307: }
308: }
309: }
310: }
311: }
312:
313: boolean remove(JobTreeElement jte) {
314: boolean fire = false;
315: boolean removed = false;
316:
317: synchronized (keptjobinfos) {
318: if (keptjobinfos.remove(jte)) {
319: removed = true;
320: finishedTime.remove(jte);
321: disposeAction(jte);
322:
323: // delete all elements that have jte as their direct or indirect
324: // parent
325: JobTreeElement jtes[] = (JobTreeElement[]) keptjobinfos
326: .toArray(new JobTreeElement[keptjobinfos.size()]);
327: for (int i = 0; i < jtes.length; i++) {
328: JobTreeElement parent = (JobTreeElement) jtes[i]
329: .getParent();
330: if (parent != null) {
331: if (parent == jte || parent.getParent() == jte) {
332: if (keptjobinfos.remove(jtes[i])) {
333: disposeAction(jtes[i]);
334: }
335: finishedTime.remove(jtes[i]);
336: }
337: }
338: }
339: fire = true;
340: }
341: }
342:
343: if (fire) {
344: // notify listeners
345: Object l[] = getListeners();
346: for (int i = 0; i < l.length; i++) {
347: KeptJobsListener jv = (KeptJobsListener) l[i];
348: jv.removed(jte);
349: }
350: }
351: return removed;
352: }
353:
354: /**
355: * Returns all kept elements sorted by finished date.
356: */
357: JobTreeElement[] getJobInfos() {
358: JobTreeElement[] all;
359: if (keptjobinfos.isEmpty()) {
360: return EMPTY_INFOS;
361: }
362:
363: synchronized (keptjobinfos) {
364: all = (JobTreeElement[]) keptjobinfos
365: .toArray(new JobTreeElement[keptjobinfos.size()]);
366: }
367: Arrays.sort(all, new Comparator() {
368: public int compare(Object o1, Object o2) {
369: long t1 = getFinishedDateAsLong((JobTreeElement) o1);
370: long t2 = getFinishedDateAsLong((JobTreeElement) o2);
371: if (t1 < t2) {
372: return -1;
373: }
374: if (t1 > t2) {
375: return 1;
376: }
377: return 0;
378: }
379: });
380: return all;
381: }
382:
383: private long getFinishedDateAsLong(JobTreeElement jte) {
384: Object o = finishedTime.get(jte);
385: if (o instanceof Long) {
386: return ((Long) o).longValue();
387: }
388: return 0;
389: }
390:
391: /**
392: * Get the date that indicates the finish time.
393: *
394: * @param jte
395: * @return Date
396: */
397: public Date getFinishDate(JobTreeElement jte) {
398: Object o = finishedTime.get(jte);
399: if (o instanceof Long) {
400: return new Date(((Long) o).longValue());
401: }
402: return null;
403: }
404:
405: /**
406: * Return whether or not the kept infos have the element.
407: *
408: * @param element
409: * @return boolean
410: */
411: public boolean isFinished(JobTreeElement element) {
412: return keptjobinfos.contains(element);
413: }
414:
415: /**
416: * Clear all kept jobs.
417: */
418: public void clearAll() {
419: synchronized (keptjobinfos) {
420: JobTreeElement[] all = (JobTreeElement[]) keptjobinfos
421: .toArray(new JobTreeElement[keptjobinfos.size()]);
422: for (int i = 0; i < all.length; i++) {
423: disposeAction(all[i]);
424: }
425: keptjobinfos.clear();
426: finishedTime.clear();
427: }
428:
429: // notify listeners
430: Object l[] = getListeners();
431: for (int i = 0; i < l.length; i++) {
432: KeptJobsListener jv = (KeptJobsListener) l[i];
433: jv.removed(null);
434: }
435: }
436: }
|