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: * Brock Janiczak <brockj@tpg.com.au> - Fix for Bug 123169 [Progress] NPE from JobInfo
011: *******************************************************************************/package org.eclipse.ui.internal.progress;
012:
013: import java.util.ArrayList;
014: import java.util.Collections;
015: import java.util.List;
016:
017: import org.eclipse.core.runtime.IProgressMonitor;
018: import org.eclipse.core.runtime.IStatus;
019: import org.eclipse.core.runtime.jobs.Job;
020: import org.eclipse.jface.resource.JFaceResources;
021: import org.eclipse.osgi.util.NLS;
022: import org.eclipse.swt.graphics.Image;
023:
024: /**
025: * JobInfo is the class that keeps track of the tree structure for objects that
026: * display job status in a tree.
027: */
028: class JobInfo extends JobTreeElement {
029:
030: private IStatus blockedStatus;
031:
032: private volatile boolean canceled = false;
033: private List children = Collections
034: .synchronizedList(new ArrayList());
035:
036: private Job job;
037:
038: private GroupInfo parent;
039:
040: private TaskInfo taskInfo;
041:
042: //Default to no progress
043: private int ticks = -1;
044:
045: /**
046: * Create a top level JobInfo.
047: *
048: * @param enclosingJob
049: */
050: JobInfo(Job enclosingJob) {
051: this .job = enclosingJob;
052: }
053:
054: /**
055: * Add the subtask to the receiver.
056: *
057: * @param subTaskName
058: */
059: void addSubTask(String subTaskName) {
060: children.add(new SubTaskInfo(this , subTaskName));
061: }
062:
063: /**
064: * Add the amount of work to the job info.
065: *
066: * @param workIncrement
067: */
068: void addWork(double workIncrement) {
069: if (taskInfo == null) {
070: return;
071: }
072: if (parent == null || ticks < 1) {
073: taskInfo.addWork(workIncrement);
074: } else {
075: taskInfo.addWork(workIncrement, parent, ticks);
076: }
077: }
078:
079: /**
080: * Begin the task called taskName with the supplied work.
081: *
082: * @param taskName
083: * @param work
084: */
085: void beginTask(String taskName, int work) {
086: taskInfo = new TaskInfo(this , taskName, work);
087: }
088:
089: /*
090: * (non-Javadoc)
091: *
092: * @see org.eclipse.ui.internal.progress.JobTreeElement#cancel()
093: */
094: public void cancel() {
095: this .canceled = true;
096: this .job.cancel();
097: //Call the refresh so that this is updated immediately
098: ProgressManager.getInstance().refreshJobInfo(this );
099: }
100:
101: /**
102: * Clear the collection of subtasks an the task info.
103: */
104: void clearChildren() {
105: children.clear();
106: }
107:
108: /*
109: * (non-Javadoc)
110: *
111: * @see org.eclipse.ui.internal.progress.JobTreeElement#isJobInfo()
112: */
113: void clearTaskInfo() {
114: taskInfo = null;
115: }
116:
117: /**
118: * Compare the the job of the receiver to job2.
119: *
120: * @param jobInfo
121: * The info we are comparing to
122: * @return @see Comparable#compareTo(java.lang.Object)
123: */
124: private int compareJobs(JobInfo jobInfo) {
125:
126: Job job2 = jobInfo.getJob();
127:
128: //User jobs have top priority
129: if (job.isUser()) {
130: if (!job2.isUser()) {
131: return -1;
132: }
133: } else {
134: if (job2.isUser()) {
135: return 1;
136: }
137: }
138:
139: //Show the blocked ones last
140: if (isBlocked()) {
141: if (!jobInfo.isBlocked()) {
142: return 1;
143: }
144: } else {
145: if (jobInfo.isBlocked()) {
146: return -1;
147: }
148: }
149:
150: if (job.getPriority() == job2.getPriority()) {
151: return job.getName().compareTo(job2.getName());
152: }
153:
154: if (job.getPriority() > job2.getPriority()) {
155: return -1;
156: }
157: return 1;
158: }
159:
160: /*
161: * (non-Javadoc)
162: *
163: * @see java.lang.Comparable#compareTo(java.lang.Object)
164: */
165: public int compareTo(Object arg0) {
166:
167: if (!(arg0 instanceof JobInfo)) {
168: return super .compareTo(arg0);
169: }
170: JobInfo element = (JobInfo) arg0;
171:
172: //If the receiver is cancelled then it is lowest priority
173: if (isCanceled() && !element.isCanceled()) {
174: return 1;
175: }
176:
177: if (element.getJob().getState() == getJob().getState()) {
178: return compareJobs(element);
179: }
180:
181: if (getJob().getState() == Job.RUNNING) {
182: return -1;
183: }
184: return 1;
185:
186: }
187:
188: /**
189: * Dispose of the receiver.
190: */
191: void dispose() {
192: if (parent != null) {
193: parent.removeJobInfo(this );
194: }
195: }
196:
197: /**
198: * Return the blocked status or <code>null</code> if there isn't one.
199: *
200: * @return Returns the blockedStatus.
201: */
202: public IStatus getBlockedStatus() {
203: return blockedStatus;
204: }
205:
206: /*
207: * (non-Javadoc)
208: *
209: * @see org.eclipse.ui.internal.progress.JobTreeElement#getChildren()
210: */
211: Object[] getChildren() {
212: return children.toArray();
213: }
214:
215: /*
216: * (non-Javadoc)
217: *
218: * @see org.eclipse.ui.internal.progress.JobTreeElement#getCondensedDisplayString()
219: */
220: String getCondensedDisplayString() {
221: TaskInfo info = getTaskInfo();
222: if (info != null) {
223: return info.getDisplayStringWithoutTask(true);
224: }
225: return getJob().getName();
226: }
227:
228: /*
229: * (non-Javadoc)
230: *
231: * @see org.eclipse.ui.internal.progress.JobTreeElement#getDisplayImage()
232: */
233: public Image getDisplayImage() {
234: int done = getPercentDone();
235: if (done > 0) {
236: return super .getDisplayImage();
237: }
238: if (isBlocked()) {
239: return JFaceResources
240: .getImage(ProgressManager.BLOCKED_JOB_KEY);
241: }
242: int state = getJob().getState();
243: if (state == Job.SLEEPING) {
244: return JFaceResources
245: .getImage(ProgressManager.SLEEPING_JOB_KEY);
246: }
247: if (state == Job.WAITING) {
248: return JFaceResources
249: .getImage(ProgressManager.WAITING_JOB_KEY);
250: }
251: //By default return the first progress image
252: return super .getDisplayImage();
253:
254: }
255:
256: /* (non-Javadoc)
257: * @see org.eclipse.ui.internal.progress.JobTreeElement#getDisplayString()
258: */
259: String getDisplayString() {
260: return getDisplayString(true);
261: }
262:
263: /* (non-Javadoc)
264: * @see org.eclipse.ui.internal.progress.JobTreeElement#getDisplayString(boolean)
265: */
266: String getDisplayString(boolean showProgress) {
267: String name = getDisplayStringWithStatus(showProgress);
268: if (job.isSystem()) {
269: return NLS.bind(ProgressMessages.JobInfo_System,
270: (new Object[] { name }));
271: }
272: return name;
273: }
274:
275: /**
276: * Get the display string based on the current status and the name of the
277: * job.
278: * @param showProgress a boolean to indicate if we should
279: * show progress or not.
280: *
281: * @return String
282: */
283: private String getDisplayStringWithStatus(boolean showProgress) {
284: if (isCanceled()) {
285: return NLS.bind(ProgressMessages.JobInfo_Cancelled,
286: (new Object[] { getJob().getName() }));
287: }
288: if (isBlocked()) {
289: return NLS.bind(ProgressMessages.JobInfo_Blocked,
290: (new Object[] { getJob().getName(),
291: blockedStatus.getMessage() }));
292: }
293: if (getJob().getState() == Job.RUNNING) {
294: TaskInfo info = getTaskInfo();
295: if (info == null) {
296: return getJob().getName();
297: }
298: return info.getDisplayString(showProgress);
299: }
300: if (getJob().getState() == Job.SLEEPING) {
301: return NLS.bind(ProgressMessages.JobInfo_Sleeping,
302: (new Object[] { getJob().getName() }));
303: }
304:
305: return NLS.bind(ProgressMessages.JobInfo_Waiting,
306: (new Object[] { getJob().getName() }));
307:
308: }
309:
310: /**
311: * Return the GroupInfo for the receiver if it' is active.
312: *
313: * @return GroupInfo or <code>null</code>.
314: */
315: GroupInfo getGroupInfo() {
316: if (parent != null && parent.isActive()) {
317: return parent;
318: }
319: return null;
320: }
321:
322: /**
323: * Return the job that the receiver is collecting data on.
324: *
325: * @return Job
326: */
327: Job getJob() {
328: return job;
329: }
330:
331: /*
332: * (non-Javadoc)
333: *
334: * @see org.eclipse.ui.internal.progress.JobTreeElement#getParent()
335: */
336: Object getParent() {
337: return parent;
338: }
339:
340: /**
341: * Return the amount of progress we have had as a percentage. If there is no
342: * progress or it is indeterminate return IProgressMonitor.UNKNOWN.
343: *
344: * @return int
345: */
346: int getPercentDone() {
347: TaskInfo info = getTaskInfo();
348: if (info != null) {
349: if (info.totalWork == IProgressMonitor.UNKNOWN) {
350: return IProgressMonitor.UNKNOWN;
351: }
352: if (info.totalWork == 0) {
353: return 0;
354: }
355: return (int) info.preWork * 100 / info.totalWork;
356: }
357: return IProgressMonitor.UNKNOWN;
358: }
359:
360: /**
361: * @return Returns the taskInfo.
362: */
363: TaskInfo getTaskInfo() {
364: return taskInfo;
365: }
366:
367: /*
368: * (non-Javadoc)
369: *
370: * @see org.eclipse.ui.internal.progress.JobTreeElement#hasChildren()
371: */
372: boolean hasChildren() {
373: return children.size() > 0;
374: }
375:
376: /**
377: * Return whether or not there is a task.
378: *
379: * @return boolean
380: */
381: boolean hasTaskInfo() {
382: return taskInfo != null;
383: }
384:
385: /*
386: * (non-Javadoc)
387: *
388: * @see org.eclipse.ui.internal.progress.JobTreeElement#isActive()
389: */
390: boolean isActive() {
391: return getJob().getState() != Job.NONE;
392: }
393:
394: /**
395: * Return whether or not the receiver is blocked.
396: *
397: * @return boolean <code>true</code> if this is a currently
398: * blocked job.
399: */
400: public boolean isBlocked() {
401: return getBlockedStatus() != null;
402: }
403:
404: /**
405: * Return whether or not the job was cancelled in the UI.
406: *
407: * @return boolean
408: */
409: public boolean isCanceled() {
410: return canceled;
411: }
412:
413: /*
414: * (non-Javadoc)
415: *
416: * @see org.eclipse.ui.internal.progress.JobTreeElement#isCancellable()
417: */
418: public boolean isCancellable() {
419: return super .isCancellable();
420: }
421:
422: /*
423: * (non-Javadoc)
424: *
425: * @see org.eclipse.ui.internal.progress.JobTreeElement#isJobInfo()
426: */
427: boolean isJobInfo() {
428: return true;
429: }
430:
431: /**
432: * Set the description of the blocking status.
433: *
434: * @param blockedStatus
435: * The IStatus that describes the blockage or <code>null</code>
436: */
437: public void setBlockedStatus(IStatus blockedStatus) {
438: this .blockedStatus = blockedStatus;
439: }
440:
441: /**
442: * Set the GroupInfo to be the group.
443: *
444: * @param group
445: */
446: void setGroupInfo(GroupInfo group) {
447: parent = group;
448: }
449:
450: /**
451: * Set the name of the taskInfo.
452: *
453: * @param name
454: */
455: void setTaskName(String name) {
456: taskInfo.setTaskName(name);
457: }
458:
459: /**
460: * Set the number of ticks this job represents. Default is indeterminate
461: * (-1).
462: *
463: * @param ticks
464: * The ticks to set.
465: */
466: public void setTicks(int ticks) {
467: this.ticks = ticks;
468: }
469:
470: }
|