001: /*******************************************************************************
002: * Copyright (c) 2006, 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.statushandlers;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.runtime.CoreException;
016: import org.eclipse.core.runtime.ILogListener;
017: import org.eclipse.core.runtime.IStatus;
018: import org.eclipse.core.runtime.Platform;
019: import org.eclipse.jface.dialogs.Dialog;
020: import org.eclipse.ui.PlatformUI;
021: import org.eclipse.ui.application.WorkbenchAdvisor;
022: import org.eclipse.ui.internal.WorkbenchErrorHandlerProxy;
023: import org.eclipse.ui.internal.WorkbenchPlugin;
024: import org.eclipse.ui.internal.misc.StatusUtil;
025: import org.eclipse.ui.internal.progress.FinishedJobs;
026: import org.eclipse.ui.internal.progress.StatusAdapterHelper;
027: import org.eclipse.ui.internal.statushandlers.StatusHandlerRegistry;
028: import org.eclipse.ui.progress.IProgressConstants;
029:
030: /**
031: * <p>
032: * StatusManager is the entry point for all statuses to be reported in the
033: * user interface.
034: * </p>
035: *
036: * <p>
037: * Handlers shoudn't be used directly but through the StatusManager singleton
038: * which keeps the status handling policy and chooses handlers.
039: * <code>StatusManager.getManager().handle(IStatus)</code> and
040: * <code>handle(IStatus status, int style)</code> are the methods are the
041: * primary access points to the StatusManager.
042: * </p>
043: *
044: * <p>
045: * Acceptable styles (can be combined with logical OR)
046: * <ul>
047: * <li>NONE - a style indicating that the status should not be acted on. This
048: * is used by objects such as log listeners that do not want to report a status
049: * twice</li>
050: * <li>LOG - a style indicating that the status should be logged only</li>
051: * <li>SHOW - a style indicating that handlers should show a problem to an user
052: * without blocking the calling method while awaiting user response. This is
053: * generally done using a non modal {@link Dialog}</li>
054: * <li>BLOCK - a style indicating that the handling should block the calling
055: * method until the user has responded. This is generally done using a modal
056: * window such as a {@link Dialog}</li>
057: * </ul>
058: * </p>
059: *
060: * <p>
061: * Handlers are intended to be accessed via the status manager. The StatusManager chooses
062: * which handler should be used for a particular error. There are two ways for adding
063: * handlers to the handling flow. First using extension point
064: * <code>org.eclipse.ui.statusHandlers</code>, second by the workbench
065: * advisor and its method {@link WorkbenchAdvisor#getWorkbenchErrorHandler()}.
066: * If a handler is associated with a product, it is used instead of this defined
067: * in advisor.
068: * </p>
069: *
070: * @since 3.3
071: * @see AbstractStatusHandler
072: */
073: public class StatusManager {
074: /**
075: * A style indicating that the status should not be acted on. This is used
076: * by objects such as log listeners that do not want to report a status
077: * twice.
078: */
079: public static final int NONE = 0;
080:
081: /**
082: * A style indicating that the status should be logged only.
083: */
084: public static final int LOG = 0x01;
085:
086: /**
087: * A style indicating that handlers should show a problem to an user without
088: * blocking the calling method while awaiting user response. This is
089: * generally done using a non modal {@link Dialog}.
090: */
091: public static final int SHOW = 0x02;
092:
093: /**
094: * A style indicating that the handling should block the calling method
095: * until the user has responded. This is generally done using a modal window
096: * such as a {@link Dialog}.
097: */
098: public static final int BLOCK = 0x04;
099:
100: private static StatusManager MANAGER;
101:
102: private AbstractStatusHandler workbenchHandler;
103:
104: private List loggedStatuses = new ArrayList();
105:
106: /**
107: * Returns StatusManager singleton instance.
108: *
109: * @return the manager instance
110: */
111: public static StatusManager getManager() {
112: if (MANAGER == null) {
113: MANAGER = new StatusManager();
114: }
115: return MANAGER;
116: }
117:
118: private StatusManager() {
119: Platform.addLogListener(new StatusManagerLogListener());
120: }
121:
122: /**
123: * @return the workbench status handler
124: */
125: private AbstractStatusHandler getWorkbenchHandler() {
126: if (workbenchHandler == null) {
127: workbenchHandler = new WorkbenchErrorHandlerProxy();
128: }
129:
130: return workbenchHandler;
131: }
132:
133: /**
134: * Handles the given status adapter due to the style. Because the facility
135: * depends on Workbench, this method will log the status, if Workbench isn't
136: * initialized and the style isn't NONE. If Workbench isn't initialized and
137: * the style is NONE, the manager will do nothing.
138: *
139: * @param statusAdapter
140: * the status adapter. Both the status adapter and the wrapped
141: * status may not be <code>null</code>.
142: * @param style
143: * the style.Value can be combined with logical OR. One of
144: * {@link #NONE}, {@link #LOG}, {@link #SHOW} and {@link #BLOCK}.
145: *
146: */
147: public void handle(StatusAdapter statusAdapter, int style) {
148: try {
149: // The manager will only log the status, if Workbench isn't
150: // initialized and the style isn't NONE. If Workbench isn't
151: // initialized and the style is NONE, the manager will do nothing.
152: if (!PlatformUI.isWorkbenchRunning()) {
153: if (style != StatusManager.NONE) {
154: logError(statusAdapter.getStatus());
155: }
156: return;
157: }
158:
159: // tries to handle the problem with default (product) handler
160: if (StatusHandlerRegistry.getDefault()
161: .getDefaultHandlerDescriptor() != null) {
162: try {
163: StatusHandlerRegistry.getDefault()
164: .getDefaultHandlerDescriptor()
165: .getStatusHandler().handle(statusAdapter,
166: style);
167: // if statuses are shown, all finished jobs with error will
168: // be removed,
169: // we should remove it from the status manager, when error
170: // icon
171: // will be part of handlers not ProgressAnimationItem
172: if (((style & StatusManager.SHOW) == StatusManager.SHOW || (style & StatusManager.BLOCK) == StatusManager.BLOCK)
173: && statusAdapter
174: .getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) != Boolean.TRUE) {
175: FinishedJobs.getInstance().removeErrorJobs();
176: StatusAdapterHelper.getInstance().clear();
177: }
178: return;
179: } catch (CoreException ex) {
180: logError(
181: "Errors during the default handler creating", ex); //$NON-NLS-1$
182: }
183: }
184:
185: // delegates the problem to workbench handler
186: getWorkbenchHandler().handle(statusAdapter, style);
187:
188: // if statuses are shown, all finished jobs with error will be
189: // removed,
190: // we should remove it from the status manager, when error icon
191: // will be part of handlers not ProgressAnimationItem
192: if (((style & StatusManager.SHOW) == StatusManager.SHOW || (style & StatusManager.BLOCK) == StatusManager.BLOCK)
193: && statusAdapter
194: .getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) != Boolean.TRUE) {
195: FinishedJobs.getInstance().removeErrorJobs();
196: }
197: } catch (Throwable ex) {
198: // The used status handler failed
199: logError(statusAdapter.getStatus());
200: logError("Error occurred during status handling", ex); //$NON-NLS-1$
201: }
202: }
203:
204: /**
205: * Handles the given status adapter. The log style is used when this method
206: * is called.
207: *
208: * @param statusAdapter
209: * the status adapter. Both the status adapter and the wrapped
210: * status may not be <code>null</code>.
211: */
212: public void handle(StatusAdapter statusAdapter) {
213: handle(statusAdapter, StatusManager.LOG);
214: }
215:
216: /**
217: * Handles the given status due to the style. Because the facility depends
218: * on Workbench, this method will log the status, if Workbench isn't
219: * initialized and the style isn't NONE. If Workbench isn't initialized and
220: * the style is NONE, the manager will do nothing.
221: *
222: * @param status
223: * the status to handle. May not be <code>null</code>.
224: * @param style
225: * the style. Acceptable values are defined in
226: * {@link StatusManager} and can be combined with logical OR.
227: */
228: public void handle(IStatus status, int style) {
229: StatusAdapter statusAdapter = new StatusAdapter(status);
230: handle(statusAdapter, style);
231: }
232:
233: /**
234: * Handles the given status. The log style is used when this method is
235: * called.
236: *
237: * @param status
238: * the status to handle. May not be <code>null</code>.
239: */
240: public void handle(IStatus status) {
241: handle(status, StatusManager.LOG);
242: }
243:
244: /**
245: * This method informs the StatusManager that this IStatus is being handled
246: * by the handler and to ignore it when it shows up in our ILogListener.
247: *
248: * @param status
249: * already handled and logged status
250: */
251: public void addLoggedStatus(IStatus status) {
252: loggedStatuses.add(status);
253: }
254:
255: private void logError(String message, Throwable ex) {
256: IStatus status = StatusUtil.newStatus(
257: WorkbenchPlugin.PI_WORKBENCH, message, ex);
258: addLoggedStatus(status);
259: WorkbenchPlugin.log(status);
260: }
261:
262: private void logError(IStatus status) {
263: addLoggedStatus(status);
264: WorkbenchPlugin.log(status);
265: }
266:
267: /**
268: * This log listener handles statuses added to a plug-in's log. If our own
269: * WorkbenchErrorHandler inserts it into the log, then ignore it.
270: *
271: * @see #addLoggedStatus(IStatus)
272: * @since 3.3
273: */
274: private class StatusManagerLogListener implements ILogListener {
275:
276: /*
277: * (non-Javadoc)
278: *
279: * @see org.eclipse.core.runtime.ILogListener#logging(org.eclipse.core.runtime.IStatus,
280: * java.lang.String)
281: */
282: public void logging(IStatus status, String plugin) {
283: if (!loggedStatuses.contains(status)) {
284: handle(status, StatusManager.NONE);
285: } else {
286: loggedStatuses.remove(status);
287: }
288: }
289: }
290: }
|