Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 247818 | Differences between
and this patch

Collapse All | Expand All

(-)Eclipse UI/org/eclipse/ui/statushandlers/WorkbenchStatusDialogManager.java (-1 / +116 lines)
Lines 21-26 Link Here
21
21
22
import org.eclipse.core.runtime.Assert;
22
import org.eclipse.core.runtime.Assert;
23
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.IStatus;
24
import org.eclipse.core.runtime.ListenerList;
24
import org.eclipse.core.runtime.jobs.Job;
25
import org.eclipse.core.runtime.jobs.Job;
25
import org.eclipse.jface.action.ContributionItem;
26
import org.eclipse.jface.action.ContributionItem;
26
import org.eclipse.jface.action.IAction;
27
import org.eclipse.jface.action.IAction;
Lines 39-45 Link Here
39
import org.eclipse.jface.resource.JFaceResources;
40
import org.eclipse.jface.resource.JFaceResources;
40
import org.eclipse.jface.resource.LocalResourceManager;
41
import org.eclipse.jface.resource.LocalResourceManager;
41
import org.eclipse.jface.resource.ResourceManager;
42
import org.eclipse.jface.resource.ResourceManager;
43
import org.eclipse.jface.util.IPropertyChangeListener;
42
import org.eclipse.jface.util.Policy;
44
import org.eclipse.jface.util.Policy;
45
import org.eclipse.jface.util.PropertyChangeEvent;
43
import org.eclipse.jface.viewers.IContentProvider;
46
import org.eclipse.jface.viewers.IContentProvider;
44
import org.eclipse.jface.viewers.ILabelProviderListener;
47
import org.eclipse.jface.viewers.ILabelProviderListener;
45
import org.eclipse.jface.viewers.ISelection;
48
import org.eclipse.jface.viewers.ISelection;
Lines 221-226 Link Here
221
	 */
224
	 */
222
	private class InternalDialog extends TrayDialog {
225
	private class InternalDialog extends TrayDialog {
223
226
227
		/* (non-Javadoc)
228
		 * @see org.eclipse.jface.dialogs.TrayDialog#close()
229
		 */
230
		public boolean close() {
231
			boolean result = super.close();
232
			if (!modalitySwitch) {
233
				firePropertyChangeEvent(new PropertyChangeEvent(this,
234
						DIALOG_STATE, OPENED, CLOSED));
235
			}
236
			return result;
237
		}
238
224
		private WorkbenchStatusDialogManager statusDialog;
239
		private WorkbenchStatusDialogManager statusDialog;
225
240
226
		/**
241
		/**
Lines 721-726 Link Here
721
	 * The id of the goto action button
736
	 * The id of the goto action button
722
	 */
737
	 */
723
	private static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1;
738
	private static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1;
739
	
740
	/**
741
	 * This constant contains a name of property that indicates the state of the
742
	 * dialog. Currently only two states are taken into account: {@link #OPENED}
743
	 * and {@link #CLOSED}. This property changes can be observed using
744
	 * {@link IPropertyChangeListener}.
745
	 * <p>
746
	 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
747
	 * part of a work in progress. There is a guarantee neither that this API
748
	 * will work nor that it will remain the same. Please do not use this API
749
	 * without consulting with the Platform/UI team.
750
	 * </p>
751
	 * 
752
	 * @since 3.5
753
	 */
754
	public static final String DIALOG_STATE = "DIALOG_STATE"; //$NON-NLS-1$
755
756
	/**
757
	 * This state indicates that the dialog is closed.
758
	 * <p>
759
	 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
760
	 * part of a work in progress. There is a guarantee neither that this API
761
	 * will work nor that it will remain the same. Please do not use this API
762
	 * without consulting with the Platform/UI team.
763
	 * </p>
764
	 * 
765
	 * @since 3.5
766
	 */
767
	public static final Integer CLOSED = new Integer(0x00);
768
769
	/**
770
	 * This state indicates that the dialog is opened.
771
	 * <p>
772
	 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
773
	 * part of a work in progress. There is a guarantee neither that this API
774
	 * will work nor that it will remain the same. Please do not use this API
775
	 * without consulting with the Platform/UI team.
776
	 * </p>
777
	 * 
778
	 * @since 3.5
779
	 */
780
	public static final Integer OPENED = new Integer(0x01);
724
781
725
	/**
782
	/**
726
	 * Returns whether the given StatusAdapter object should be displayed.
783
	 * Returns whether the given StatusAdapter object should be displayed.
Lines 1000-1005 Link Here
1000
	 */
1057
	 */
1001
	private Composite titleArea;
1058
	private Composite titleArea;
1002
1059
1060
	private ListenerList listeners = new ListenerList();
1061
1003
	/**
1062
	/**
1004
	 * Creates workbench status dialog.
1063
	 * Creates workbench status dialog.
1005
	 * 
1064
	 * 
Lines 1117-1122 Link Here
1117
					dialog = new InternalDialog(getParentShell(),
1176
					dialog = new InternalDialog(getParentShell(),
1118
							WorkbenchStatusDialogManager.this, shouldBeModal());
1177
							WorkbenchStatusDialogManager.this, shouldBeModal());
1119
					setSelectedStatusAdapter(statusAdapter);
1178
					setSelectedStatusAdapter(statusAdapter);
1179
					firePropertyChangeEvent(new PropertyChangeEvent(this,
1180
							DIALOG_STATE, CLOSED, OPENED));
1120
					dialog.open();
1181
					dialog.open();
1121
					dialog.getShell().addDisposeListener(disposeListener);
1182
					dialog.getShell().addDisposeListener(disposeListener);
1122
				}
1183
				}
Lines 1653-1659 Link Here
1653
	/**
1714
	/**
1654
	 * Returns the shell of the dialog.
1715
	 * Returns the shell of the dialog.
1655
	 */
1716
	 */
1656
	Shell getShell() {
1717
	private Shell getShell() {
1657
		if (this.dialog == null) return null;
1718
		if (this.dialog == null) return null;
1658
		return this.dialog.getShell();
1719
		return this.dialog.getShell();
1659
	}
1720
	}
Lines 2190-2193 Link Here
2190
		}
2251
		}
2191
		titleArea.layout();
2252
		titleArea.layout();
2192
	}
2253
	}
2254
2255
	/**
2256
	 * This method adds a listener to the dialog. Listener will be notified
2257
	 * about dialog state changes. {@link #DIALOG_STATE} is currently the only
2258
	 * property that can change.
2259
	 * <p>
2260
	 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
2261
	 * part of a work in progress. There is a guarantee neither that this API
2262
	 * will work nor that it will remain the same. Please do not use this API
2263
	 * without consulting with the Platform/UI team.
2264
	 * </p>
2265
	 * 
2266
	 * @see IPropertyChangeListener
2267
	 * @param listener
2268
	 *            A listener to be added.
2269
	 * @since 3.5
2270
	 */
2271
	public void addStatusDialogListener(IPropertyChangeListener listener) {
2272
		listeners.add(listener);
2273
	}
2274
2275
	/**
2276
	 * This method removes a listener from the dialog. If the listener was not
2277
	 * added before, there is no effect.
2278
	 * <p>
2279
	 * <strong>EXPERIMENTAL</strong>. This class or interface has been added as
2280
	 * part of a work in progress. There is a guarantee neither that this API
2281
	 * will work nor that it will remain the same. Please do not use this API
2282
	 * without consulting with the Platform/UI team.
2283
	 * </p>
2284
	 * 
2285
	 * @param listener
2286
	 *            A listener to be removed.
2287
	 * @since 3.5
2288
	 */
2289
	public void removeStatusDialogListener(IPropertyChangeListener listener){
2290
		listeners.remove(listener);
2291
	}
2292
	
2293
	private void firePropertyChangeEvent(PropertyChangeEvent event) {
2294
		if (listeners.size() > 0) {
2295
			final Object[] myListeners = listeners.getListeners();
2296
			for (int i = 0; i < myListeners.length; ++i) {
2297
				try {
2298
					((IPropertyChangeListener) myListeners[i])
2299
							.propertyChange(event);
2300
				} catch (Exception e) {
2301
					// no other choice. This may be potentially dangerous
2302
					// exception.
2303
					e.printStackTrace();
2304
				}
2305
			}
2306
		}
2307
	}
2193
}
2308
}
(-)Eclipse UI/org/eclipse/ui/statushandlers/WorkbenchErrorHandler.java (-5 / +25 lines)
Lines 13-20 Link Here
13
13
14
import org.eclipse.core.runtime.IStatus;
14
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.core.runtime.Status;
15
import org.eclipse.core.runtime.Status;
16
import org.eclipse.jface.util.IPropertyChangeListener;
17
import org.eclipse.jface.util.PropertyChangeEvent;
16
import org.eclipse.swt.widgets.Display;
18
import org.eclipse.swt.widgets.Display;
17
import org.eclipse.swt.widgets.Shell;
18
import org.eclipse.ui.PlatformUI;
19
import org.eclipse.ui.PlatformUI;
19
import org.eclipse.ui.application.WorkbenchAdvisor;
20
import org.eclipse.ui.application.WorkbenchAdvisor;
20
import org.eclipse.ui.internal.WorkbenchPlugin;
21
import org.eclipse.ui.internal.WorkbenchPlugin;
Lines 26-31 Link Here
26
 * @since 3.3
27
 * @since 3.3
27
 */
28
 */
28
public class WorkbenchErrorHandler extends AbstractStatusHandler {
29
public class WorkbenchErrorHandler extends AbstractStatusHandler {
30
	
31
	private boolean dialogClosed = false;
32
	private IPropertyChangeListener listener = new IPropertyChangeListener(){
33
34
		public void propertyChange(PropertyChangeEvent event) {
35
			//check if this is really OPENED -> CLOSED transition
36
			if (WorkbenchStatusDialogManager.DIALOG_STATE.equals(event
37
					.getProperty())
38
					&& WorkbenchStatusDialogManager.OPENED.equals(event
39
							.getOldValue())
40
					&& WorkbenchStatusDialogManager.CLOSED.equals(event
41
							.getNewValue())) {
42
				dialogClosed = true;
43
			}
44
		}
45
		
46
	};
29
47
30
	private WorkbenchStatusDialogManager statusDialogManager;
48
	private WorkbenchStatusDialogManager statusDialogManager;
31
49
Lines 110-119 Link Here
110
		getStatusDialogManager().addStatusAdapter(statusAdapter, block);
128
		getStatusDialogManager().addStatusAdapter(statusAdapter, block);
111
129
112
		if (block) {
130
		if (block) {
113
			Shell shell;
131
			// this variable will be set to true if and only if user closes the
114
			while ((shell = getStatusDialogManager().getShell()) != null
132
			// dialog
115
					&& !getStatusDialogManager().getShell().isDisposed()) {
133
			dialogClosed = false;
116
				if (!shell.getDisplay().readAndDispatch()) {
134
			while (!dialogClosed) {
135
				if (!Display.getDefault().readAndDispatch()) {
117
					Display.getDefault().sleep();
136
					Display.getDefault().sleep();
118
				}
137
				}
119
			}
138
			}
Lines 155-159 Link Here
155
	protected void configureStatusDialog(
174
	protected void configureStatusDialog(
156
			final WorkbenchStatusDialogManager statusDialog) {
175
			final WorkbenchStatusDialogManager statusDialog) {
157
		// default configuration does nothing
176
		// default configuration does nothing
177
		statusDialog.addStatusDialogListener(listener);
158
	}
178
	}
159
}
179
}
(-)Eclipse UI Tests/org/eclipse/ui/tests/statushandlers/StatusDialogManagerTest.java (+158 lines)
Lines 20-26 Link Here
20
import org.eclipse.jface.action.Action;
20
import org.eclipse.jface.action.Action;
21
import org.eclipse.jface.dialogs.ErrorDialog;
21
import org.eclipse.jface.dialogs.ErrorDialog;
22
import org.eclipse.jface.dialogs.IDialogConstants;
22
import org.eclipse.jface.dialogs.IDialogConstants;
23
import org.eclipse.jface.util.IPropertyChangeListener;
23
import org.eclipse.jface.util.Policy;
24
import org.eclipse.jface.util.Policy;
25
import org.eclipse.jface.util.PropertyChangeEvent;
24
import org.eclipse.jface.viewers.ILabelProviderListener;
26
import org.eclipse.jface.viewers.ILabelProviderListener;
25
import org.eclipse.jface.viewers.ITableLabelProvider;
27
import org.eclipse.jface.viewers.ITableLabelProvider;
26
import org.eclipse.osgi.util.NLS;
28
import org.eclipse.osgi.util.NLS;
Lines 31-36 Link Here
31
import org.eclipse.swt.widgets.Button;
33
import org.eclipse.swt.widgets.Button;
32
import org.eclipse.swt.widgets.Composite;
34
import org.eclipse.swt.widgets.Composite;
33
import org.eclipse.swt.widgets.Control;
35
import org.eclipse.swt.widgets.Control;
36
import org.eclipse.swt.widgets.Display;
34
import org.eclipse.swt.widgets.Event;
37
import org.eclipse.swt.widgets.Event;
35
import org.eclipse.swt.widgets.Label;
38
import org.eclipse.swt.widgets.Label;
36
import org.eclipse.swt.widgets.Shell;
39
import org.eclipse.swt.widgets.Shell;
Lines 42-47 Link Here
42
import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
45
import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
43
import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
46
import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
44
import org.eclipse.ui.statushandlers.StatusAdapter;
47
import org.eclipse.ui.statushandlers.StatusAdapter;
48
import org.eclipse.ui.statushandlers.StatusManager;
49
import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;
45
import org.eclipse.ui.statushandlers.WorkbenchStatusDialogManager;
50
import org.eclipse.ui.statushandlers.WorkbenchStatusDialogManager;
46
51
47
public class StatusDialogManagerTest extends TestCase {
52
public class StatusDialogManagerTest extends TestCase {
Lines 51-56 Link Here
51
	private static final String THROWABLE = "throwable";
56
	private static final String THROWABLE = "throwable";
52
	private final static String MESSAGE_1 = "TEST_MESSAGE_1";
57
	private final static String MESSAGE_1 = "TEST_MESSAGE_1";
53
	private final static String MESSAGE_2 = "TEST_MESSAGE_2";
58
	private final static String MESSAGE_2 = "TEST_MESSAGE_2";
59
	private final static String MESSAGE_3 = "TEST_MESSAGE_2";
54
	private final static String TITLE = "TEST_TITLE";
60
	private final static String TITLE = "TEST_TITLE";
55
	private final static NullPointerException NPE = new NullPointerException();
61
	private final static NullPointerException NPE = new NullPointerException();
56
	private final static NullPointerException NPE_WITH_MESSAGE = new NullPointerException(
62
	private final static NullPointerException NPE_WITH_MESSAGE = new NullPointerException(
Lines 73-78 Link Here
73
		assertNotNull(shell);
79
		assertNotNull(shell);
74
		assertTrue((shell.getStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL);
80
		assertTrue((shell.getStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL);
75
	}
81
	}
82
	
83
	/**
84
	 * This test checks if the calling thread is really blocked. It opens a
85
	 * dialog with the BLOCK flag in UI thread, and then monitors in the
86
	 * background thread that the dialog really appears (in 50 tries, 50
87
	 * milliseconds each). After the dialog appears, "OK" selection is emulated,
88
	 * the dialog is closed and the handle method returns. At this point there
89
	 * can be no shell.
90
	 */
91
	public void testBlockingBehavior1() {
92
		WorkbenchErrorHandler weh = new WorkbenchErrorHandler();
93
		Thread thread = new Thread(new Runnable(){
94
			public void run() {
95
				int count = 50;
96
				final boolean opened[] = new boolean[]{false};
97
				while (!opened[0] && count-- != 0) {
98
					try {
99
						Thread.sleep(50);
100
					} catch (InterruptedException e) {
101
						e.printStackTrace();
102
					}
103
					Display.getDefault().syncExec(new Runnable() {
104
						public void run() {
105
							opened[0] = StatusDialogUtil.getStatusShell() != null;
106
							if(opened[0]){
107
								selectWidget(StatusDialogUtil.getOkButton());
108
							}
109
						}
110
					});
111
				}
112
				assertTrue("Dialog should appear!", count > 0);
113
				
114
			}
115
		});
116
		thread.start();
117
		weh.handle(createStatusAdapter(MESSAGE_1), StatusManager.BLOCK);
118
		assertNull("Dialog should block the calling thread!", StatusDialogUtil
119
				.getStatusShell());
120
	}
121
122
	/**
123
	 * This is more advanced version of testBlockingBehavior1. We have 2
124
	 * background threads that raise statuses. UI thread also raises one. No
125
	 * thread can proceed until "OK" is emulated (and this will happen if the
126
	 * dialog is opened and three statuses were reported).
127
	 */
128
	public void testBlockingBehavior2() {
129
		final WorkbenchErrorHandler weh = new WorkbenchErrorHandler();
130
		Thread thread1 = new Thread(new Runnable() {
131
			public void run() {
132
				weh.handle(createStatusAdapter(MESSAGE_1), StatusManager.BLOCK);
133
				Display.getDefault().syncExec(new Runnable() {
134
					public void run() {
135
						assertNull("Dialog should block the calling thread!",
136
								StatusDialogUtil.getStatusShell());
137
					}
138
				});
139
			}
140
141
		});
142
		thread1.start();
143
		Thread thread2 = new Thread(new Runnable() {
144
			public void run() {
145
				weh.handle(createStatusAdapter(MESSAGE_2), StatusManager.BLOCK);
146
				Display.getDefault().syncExec(new Runnable() {
147
					public void run() {
148
						assertNull("Dialog should block the calling thread!",
149
								StatusDialogUtil.getStatusShell());
150
					}
151
				});
152
			}
153
		});
154
		thread2.start();
155
		Thread checker = new Thread(new Runnable() {
156
			public void run() {
157
				int count = 50;
158
				final boolean statusesShown[] = new boolean[] { false };
159
				while (!statusesShown[0] && count-- != 0) {
160
					try {
161
						Thread.sleep(50);
162
					} catch (InterruptedException e) {
163
						e.printStackTrace();
164
					}
165
					Display.getDefault().syncExec(new Runnable() {
166
						public void run() {
167
							boolean dialogVisible = StatusDialogUtil
168
									.getStatusShell() != null;
169
							statusesShown[0] = dialogVisible
170
									&& StatusDialogUtil.getTable()
171
											.getItemCount() == 3;
172
							if (statusesShown[0]) {
173
								selectWidget(StatusDialogUtil.getOkButton());
174
							}
175
						}
176
					});
177
				}
178
				assertTrue(
179
						"Dialog should appear and all statuses should be shown",
180
						count > 0);
181
			}
182
		});
183
		checker.start();
184
		weh.handle(createStatusAdapter(MESSAGE_3), StatusManager.BLOCK);
185
		assertNull("Dialog should block the calling thread!", StatusDialogUtil
186
				.getStatusShell());
187
	}
76
188
77
	public void testNonBlockingAppearance() {
189
	public void testNonBlockingAppearance() {
78
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);
190
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);
Lines 80-85 Link Here
80
		assertNotNull(shell);
192
		assertNotNull(shell);
81
		assertFalse((shell.getStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL);
193
		assertFalse((shell.getStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL);
82
	}
194
	}
195
	
196
	/**
197
	 * Check that listener is notified about dialog closure when the dialog is
198
	 * closed by the user.
199
	 */
200
	public void testListener1() {
201
		final PropertyChangeEvent[] events = new PropertyChangeEvent[1];
202
		wsdm.addStatusDialogListener(new IPropertyChangeListener() {
203
204
			public void propertyChange(PropertyChangeEvent event) {
205
				events[0] = event;
206
			}
207
208
		});
209
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);
210
		selectWidget(StatusDialogUtil.getOkButton());
211
		assertNotNull(events[0]);
212
		assertTrue(WorkbenchStatusDialogManager.CLOSED.equals(events[0]
213
				.getNewValue()));
214
	}
215
	
216
	/**
217
	 * Check that listener is notified about dialog opening.
218
	 * Check that listener is not notified about dialog closure when the
219
	 * modality is switched.
220
	 */
221
	public void testListener2(){
222
		final PropertyChangeEvent[] events = new PropertyChangeEvent[1];
223
		wsdm.addStatusDialogListener(new IPropertyChangeListener() {
224
225
			public void propertyChange(PropertyChangeEvent event) {
226
				events[0] = event;
227
			}
228
229
		});
230
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);
231
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), true);
232
		assertNotNull(events[0]);
233
		assertTrue(WorkbenchStatusDialogManager.OPENED.equals(events[0]
234
				.getNewValue()));
235
		selectWidget(StatusDialogUtil.getOkButton());
236
		// now should be notified
237
		assertNotNull(events[0]);
238
		assertTrue(WorkbenchStatusDialogManager.CLOSED.equals(events[0]
239
				.getNewValue()));
240
	}
83
241
84
	public void testModalitySwitch1() {
242
	public void testModalitySwitch1() {
85
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);
243
		wsdm.addStatusAdapter(createStatusAdapter(MESSAGE_1), false);

Return to bug 247818