001: /*******************************************************************************
002: * Copyright (c) 2004, 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.statushandlers;
011:
012: import java.util.Collection;
013: import java.util.Collections;
014: import java.util.Date;
015: import java.util.HashSet;
016:
017: import org.eclipse.core.runtime.IStatus;
018: import org.eclipse.core.runtime.jobs.Job;
019: import org.eclipse.jface.dialogs.ErrorDialog;
020: import org.eclipse.osgi.util.NLS;
021: import org.eclipse.swt.events.DisposeListener;
022: import org.eclipse.swt.widgets.Display;
023: import org.eclipse.ui.PlatformUI;
024: import org.eclipse.ui.internal.WorkbenchPlugin;
025: import org.eclipse.ui.internal.progress.ProgressManagerUtil;
026: import org.eclipse.ui.internal.progress.ProgressMessages;
027: import org.eclipse.ui.progress.IProgressConstants;
028: import org.eclipse.ui.statushandlers.StatusAdapter;
029:
030: import com.ibm.icu.text.DateFormat;
031:
032: /**
033: * The StatusNotificationManager is the class that manages the display of status
034: * information.
035: */
036: public class StatusNotificationManager {
037:
038: private Collection errors = Collections
039: .synchronizedSet(new HashSet());
040:
041: private StatusDialog dialog;
042:
043: private static StatusNotificationManager sharedInstance;
044:
045: private DisposeListener disposeListener = new DisposeListener() {
046: /*
047: * (non-Javadoc)
048: *
049: * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
050: */
051: public void widgetDisposed(org.eclipse.swt.events.DisposeEvent e) {
052: dialog = null;
053: errors.clear();
054: }
055: };
056:
057: /**
058: * Returns the shared instance.
059: *
060: * @return the shared instance
061: */
062: public static StatusNotificationManager getInstance() {
063: if (sharedInstance == null) {
064: sharedInstance = new StatusNotificationManager();
065: }
066: return sharedInstance;
067: }
068:
069: /**
070: * Create a new instance of the manager.
071: */
072: private StatusNotificationManager() {
073: }
074:
075: /**
076: * Add a new error to the list.
077: *
078: * @param statusInfo
079: * the error to be displayed
080: */
081: public void addError(StatusAdapter statusAdapter,
082: final boolean modal) {
083:
084: if (ErrorDialog.AUTOMATED_MODE == true) {
085: return;
086: }
087:
088: final StatusInfo statusInfo = new StatusInfo(statusAdapter);
089:
090: if (!PlatformUI.isWorkbenchRunning()) {
091: // we are shutting down, so just log
092: WorkbenchPlugin.log(statusInfo.getStatus().getStatus());
093: return;
094: }
095:
096: // Add the error in the UI thread to ensure thread safety in the
097: // dialog
098: if (dialog == null || dialog.getShell().isDisposed()) {
099:
100: errors.add(statusInfo);
101: // Delay prompting if the status adapter property is set
102: Object noPromptProperty = statusInfo
103: .getStatus()
104: .getProperty(
105: IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY);
106:
107: boolean prompt = true;
108: if (noPromptProperty instanceof Boolean) {
109: prompt = !((Boolean) noPromptProperty).booleanValue();
110: }
111:
112: if (prompt) {
113: Display.getDefault().asyncExec(new Runnable() {
114: public void run() {
115: if (dialog == null) {
116: dialog = new StatusDialog(
117: ProgressManagerUtil
118: .getDefaultParent(),
119: statusInfo, IStatus.INFO
120: | IStatus.WARNING
121: | IStatus.ERROR, modal);
122: dialog.open();
123: dialog.getShell().addDisposeListener(
124: disposeListener);
125: }
126: }
127: });
128: }
129:
130: } else {
131:
132: if (statusInfo
133: .getStatus()
134: .getProperty(
135: IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) != null) {
136: statusInfo
137: .getStatus()
138: .setProperty(
139: IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY,
140: Boolean.FALSE);
141: }
142:
143: Display.getDefault().syncExec(new Runnable() {
144: public void run() {
145: openStatusDialog(modal, statusInfo);
146: }
147: });
148: }
149: }
150:
151: /**
152: * Get the currently registered errors in the receiver.
153: *
154: * @return Collection of ErrorInfo
155: */
156: Collection getErrors() {
157: return errors;
158: }
159:
160: /**
161: * @param modal
162: * @param statusInfo
163: */
164: void openStatusDialog(final boolean modal,
165: final StatusInfo statusInfo) {
166: errors.add(statusInfo);
167: if (modal && !dialog.isModal()) {
168: dialog.getShell().removeDisposeListener(disposeListener);
169: dialog.close();
170: dialog = new StatusDialog(ProgressManagerUtil
171: .getDefaultParent(), statusInfo, IStatus.INFO
172: | IStatus.WARNING | IStatus.ERROR, modal);
173:
174: dialog.open();
175: dialog.getShell().addDisposeListener(disposeListener);
176: } else {
177: dialog.refresh();
178: }
179: }
180:
181: /**
182: * A wrapper class for statuses displayed in the dialog.
183: *
184: */
185: protected static class StatusInfo implements Comparable {
186:
187: public boolean equals(Object obj) {
188: if (obj instanceof StatusInfo) {
189: return statusAdapter.equals(((StatusInfo) obj)
190: .getStatus());
191: }
192: return super .equals(obj);
193: }
194:
195: public int hashCode() {
196: return statusAdapter.hashCode();
197: }
198:
199: private final StatusAdapter statusAdapter;
200:
201: /**
202: * Constructs a simple <code>StatusInfo</code>, without any
203: * extensions.
204: *
205: * @param status
206: * the root status for this status info
207: */
208: public StatusInfo(StatusAdapter statusAdapter) {
209: this .statusAdapter = statusAdapter;
210:
211: Object timestampProperty = statusAdapter
212: .getProperty(StatusAdapter.TIMESTAMP_PROPERTY);
213:
214: if (timestampProperty == null
215: || !(timestampProperty instanceof Long)) {
216: statusAdapter.setProperty(
217: StatusAdapter.TIMESTAMP_PROPERTY, new Long(
218: System.currentTimeMillis()));
219: }
220: }
221:
222: String getDisplayString() {
223: String text = statusAdapter.getStatus().getMessage();
224:
225: Job job = (Job) (statusAdapter.getAdapter(Job.class));
226: if (job != null) {
227: text = job.getName();
228: }
229:
230: return NLS
231: .bind(
232: ProgressMessages.JobInfo_Error,
233: (new Object[] {
234: text,
235: DateFormat.getDateTimeInstance(
236: DateFormat.LONG,
237: DateFormat.LONG).format(
238: new Date(getTimestamp())) }));
239: }
240:
241: /**
242: * Time when this status info was created.
243: *
244: * @return the time
245: */
246: public long getTimestamp() {
247: return ((Long) statusAdapter
248: .getProperty(StatusAdapter.TIMESTAMP_PROPERTY))
249: .longValue();
250: }
251:
252: /*
253: * (non-Javadoc)
254: *
255: * @see java.lang.Comparable#compareTo(T)
256: */
257: public int compareTo(Object arg0) {
258: if (arg0 instanceof StatusInfo) {
259: // Order ErrorInfo by time received
260: long otherTimestamp = ((StatusInfo) arg0)
261: .getTimestamp();
262: if (getTimestamp() < otherTimestamp) {
263: return -1;
264: } else if (getTimestamp() > otherTimestamp) {
265: return 1;
266: } else {
267: return getDisplayString().compareTo(
268: ((StatusInfo) arg0).getDisplayString());
269: }
270: }
271: return 0;
272: }
273:
274: /**
275: * @return Returns the status.
276: */
277: public StatusAdapter getStatus() {
278: return statusAdapter;
279: }
280: }
281: }
|