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 76726 | Differences between
and this patch

Collapse All | Expand All

(-)Eclipse UI/org/eclipse/ui/internal/progress/ErrorInfo.java (-6 / +40 lines)
Lines 10-16 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.progress;
11
package org.eclipse.ui.internal.progress;
12
12
13
import java.util.Date;
14
13
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.core.runtime.IStatus;
16
import org.eclipse.core.runtime.jobs.Job;
14
import org.eclipse.jface.resource.JFaceResources;
17
import org.eclipse.jface.resource.JFaceResources;
15
import org.eclipse.swt.graphics.Image;
18
import org.eclipse.swt.graphics.Image;
16
19
Lines 19-35 Link Here
19
 */
22
 */
20
public class ErrorInfo extends JobTreeElement {
23
public class ErrorInfo extends JobTreeElement {
21
24
22
    private IStatus errorStatus;
25
    private final IStatus errorStatus;
23
26
    private final Job job;
24
    private String jobName;
27
    private final long timestamp;
25
28
26
    /**
29
    /**
27
     * Create a new instance of the receiver.
30
     * Create a new instance of the receiver.
28
     * @param status
31
     * @param status
29
     */
32
     */
30
    public ErrorInfo(IStatus status, String name) {
33
    public ErrorInfo(IStatus status, Job job) {
31
        errorStatus = status;
34
        errorStatus = status;
32
        jobName = name;
35
        this.job = job;
36
        timestamp = System.currentTimeMillis();
33
    }
37
    }
34
38
35
    /* (non-Javadoc)
39
    /* (non-Javadoc)
Lines 58-64 Link Here
58
     */
62
     */
59
    String getDisplayString() {
63
    String getDisplayString() {
60
        return ProgressMessages.format("JobInfo.Error", //$NON-NLS-1$
64
        return ProgressMessages.format("JobInfo.Error", //$NON-NLS-1$
61
                new Object[] { jobName, errorStatus.getMessage() });
65
                new Object[] { job.getName(), new Date(timestamp) });
62
    }
66
    }
63
67
64
    /**
68
    /**
Lines 89-93 Link Here
89
     */
93
     */
90
    boolean isActive() {
94
    boolean isActive() {
91
        return true;
95
        return true;
96
    }
97
    
98
    /**
99
     * Return the job that generated the error.
100
     * @return the job that generated the error
101
     */
102
    public Job getJob() {
103
        return job;
104
    }
105
    
106
    public long getTimestamp() {
107
        return timestamp;
108
    }
109
    
110
    /* (non-Javadoc)
111
     * @see org.eclipse.ui.internal.progress.JobTreeElement#compareTo(java.lang.Object)
112
     */
113
    public int compareTo(Object arg0) {
114
        if (arg0 instanceof ErrorInfo) {
115
            // Order ErrorInfo by time received
116
            long otherTimestamp = ((ErrorInfo)arg0).timestamp;
117
            if (timestamp < otherTimestamp) {
118
                return -1;
119
            } else if (timestamp > otherTimestamp) {
120
                return 1;
121
            } else {
122
                return 0;
123
            }
124
        }
125
        return super.compareTo(arg0);
92
    }
126
    }
93
}
127
}
(-)Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationDialog.java (-526 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.progress;
12
13
import java.util.ArrayList;
14
import java.util.Collection;
15
16
import org.eclipse.core.runtime.IStatus;
17
import org.eclipse.jface.dialogs.Dialog;
18
import org.eclipse.jface.dialogs.ErrorDialog;
19
import org.eclipse.jface.dialogs.IDialogConstants;
20
import org.eclipse.jface.resource.JFaceResources;
21
import org.eclipse.jface.viewers.IContentProvider;
22
import org.eclipse.jface.viewers.ILabelProviderListener;
23
import org.eclipse.jface.viewers.ISelection;
24
import org.eclipse.jface.viewers.ISelectionChangedListener;
25
import org.eclipse.jface.viewers.IStructuredContentProvider;
26
import org.eclipse.jface.viewers.IStructuredSelection;
27
import org.eclipse.jface.viewers.ITableLabelProvider;
28
import org.eclipse.jface.viewers.SelectionChangedEvent;
29
import org.eclipse.jface.viewers.TableViewer;
30
import org.eclipse.jface.viewers.Viewer;
31
import org.eclipse.jface.viewers.ViewerSorter;
32
import org.eclipse.swt.SWT;
33
import org.eclipse.swt.dnd.Clipboard;
34
import org.eclipse.swt.dnd.TextTransfer;
35
import org.eclipse.swt.dnd.Transfer;
36
import org.eclipse.swt.events.DisposeEvent;
37
import org.eclipse.swt.events.DisposeListener;
38
import org.eclipse.swt.events.MouseAdapter;
39
import org.eclipse.swt.events.MouseEvent;
40
import org.eclipse.swt.events.SelectionAdapter;
41
import org.eclipse.swt.events.SelectionEvent;
42
import org.eclipse.swt.events.SelectionListener;
43
import org.eclipse.swt.graphics.Image;
44
import org.eclipse.swt.graphics.Rectangle;
45
import org.eclipse.swt.layout.GridData;
46
import org.eclipse.swt.widgets.Button;
47
import org.eclipse.swt.widgets.Composite;
48
import org.eclipse.swt.widgets.Control;
49
import org.eclipse.swt.widgets.List;
50
import org.eclipse.swt.widgets.Menu;
51
import org.eclipse.swt.widgets.MenuItem;
52
import org.eclipse.swt.widgets.Shell;
53
54
/**
55
 * The ErrorNotificationDialog is is the dialog that comes up when an error has
56
 * occured.
57
 */
58
public class ErrorNotificationDialog extends Dialog {
59
    TableViewer errorViewer;
60
61
    Button clearButton;
62
63
    List detailsList;
64
65
    private Clipboard clipboard;
66
67
    private ErrorInfo selectedError = null;
68
69
    /**
70
     * Reserve room for this many details list items.
71
     */
72
    private static final int DETAILS_LIST_ITEM_COUNT = 7;
73
74
    /**
75
     * The nesting indent.
76
     */
77
    private static final String NESTING_INDENT = "  "; //$NON-NLS-1$
78
79
    /**
80
     * Create a new instance of the receiver.
81
     * 
82
     * @param parentShell
83
     */
84
    public ErrorNotificationDialog(Shell parentShell) {
85
        super(parentShell == null ? ProgressManagerUtil.getDefaultParent()
86
                : parentShell);
87
        setBlockOnOpen(false);
88
        setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE
89
                | SWT.RESIZE | getDefaultOrientation());
90
    }
91
92
    /*
93
     * (non-Javadoc)
94
     * 
95
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
96
     */
97
    protected void configureShell(Shell newShell) {
98
        super.configureShell(newShell);
99
        newShell.setText(ProgressMessages
100
                .getString("ErrorNotificationDialog.ErrorNotificationTitle")); //$NON-NLS-1$
101
        newShell.addDisposeListener(new DisposeListener() {
102
            /*
103
             * (non-Javadoc)
104
             * 
105
             * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
106
             */
107
            public void widgetDisposed(DisposeEvent e) {
108
                getManager().clearDialog();
109
            }
110
        });
111
    }
112
113
    /*
114
     * (non-Javadoc)
115
     * 
116
     * @see org.eclipse.jface.window.Window#getShellStyle()
117
     */
118
    protected int getShellStyle() {
119
        return super.getShellStyle() | SWT.MIN;
120
    }
121
122
    /*
123
     * (non-Javadoc)
124
     * 
125
     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
126
     */
127
    protected Control createDialogArea(Composite parent) {
128
        initializeDialogUnits(parent);
129
        Composite topArea = (Composite) super.createDialogArea(parent);
130
        errorViewer = new TableViewer(topArea, SWT.MULTI | SWT.H_SCROLL
131
                | SWT.V_SCROLL | SWT.BORDER);
132
        errorViewer.setSorter(getViewerSorter());
133
        errorViewer.getControl().addMouseListener(new MouseAdapter() {
134
            /*
135
             * (non-Javadoc)
136
             * 
137
             * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
138
             */
139
            public void mouseDoubleClick(MouseEvent e) {
140
                openErrorDialog();
141
            }
142
        });
143
        errorViewer
144
                .addSelectionChangedListener(new ISelectionChangedListener() {
145
                    public void selectionChanged(SelectionChangedEvent event) {
146
147
                        clearButton.setEnabled(!errorViewer.getSelection()
148
                                .isEmpty());
149
                        setDetailsContents();
150
                    }
151
                });
152
        Control control = errorViewer.getControl();
153
        GridData data = new GridData(GridData.FILL_BOTH
154
                | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
155
        data.widthHint = convertWidthInCharsToPixels(60);
156
        data.heightHint = convertHeightInCharsToPixels(10);
157
        control.setLayoutData(data);
158
        initContentProvider();
159
        initLabelProvider();
160
        applyDialogFont(parent);
161
162
        createDetailsList(topArea);
163
        return topArea;
164
    }
165
166
    /*
167
     * (non-Javadoc)
168
     * 
169
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
170
     */
171
    protected void createButtonsForButtonBar(Composite parent) {
172
173
        clearButton = createButton(
174
                parent,
175
                IDialogConstants.CLIENT_ID + 2,
176
                ProgressMessages
177
                        .getString("ErrorNotificationDialog.ClearButtonTitle"), false); //$NON-NLS-1$
178
        clearButton.setEnabled(false);
179
        clearButton.addSelectionListener(new SelectionAdapter() {
180
            public void widgetSelected(SelectionEvent e) {
181
                ISelection rawSelection = errorViewer.getSelection();
182
                if (rawSelection != null
183
                        && rawSelection instanceof IStructuredSelection) {
184
                    IStructuredSelection selection = (IStructuredSelection) rawSelection;
185
                    getManager().removeErrors(selection.toList());
186
                }
187
                refresh();
188
            }
189
        });
190
        Button button = createButton(parent, IDialogConstants.CLOSE_ID,
191
                IDialogConstants.CLOSE_LABEL, true);
192
        button.addSelectionListener(new SelectionListener() {
193
            /*
194
             * (non-Javadoc)
195
             * 
196
             * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
197
             */
198
            public void widgetSelected(SelectionEvent e) {
199
                close();
200
            }
201
202
            /*
203
             * (non-Javadoc)
204
             * 
205
             * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
206
             */
207
            public void widgetDefaultSelected(SelectionEvent e) {
208
                close();
209
            }
210
        });
211
    }
212
213
    /**
214
     * Return a viewer sorter for looking at the jobs.
215
     * 
216
     * @return
217
     */
218
    private ViewerSorter getViewerSorter() {
219
        return new ViewerSorter() {
220
            /*
221
             * (non-Javadoc)
222
             * 
223
             * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer,
224
             *      java.lang.Object, java.lang.Object)
225
             */
226
            public int compare(Viewer testViewer, Object e1, Object e2) {
227
                return ((Comparable) e1).compareTo(e2);
228
            }
229
        };
230
    }
231
232
    /**
233
     * Sets the content provider for the viewer.
234
     */
235
    protected void initContentProvider() {
236
        IContentProvider provider = new IStructuredContentProvider() {
237
            /*
238
             * (non-Javadoc)
239
             * 
240
             * @see org.eclipse.jface.viewers.IContentProvider#dispose()
241
             */
242
            public void dispose() {
243
                //Nothing of interest here
244
            }
245
246
            /*
247
             * (non-Javadoc)
248
             * 
249
             * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
250
             */
251
            public Object[] getElements(Object inputElement) {
252
                return getManager().getErrors().toArray();
253
            }
254
255
            /*
256
             * (non-Javadoc)
257
             * 
258
             * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
259
             *      java.lang.Object, java.lang.Object)
260
             */
261
            public void inputChanged(Viewer viewer, Object oldInput,
262
                    Object newInput) {
263
                if (newInput != null)
264
                    refresh();
265
            }
266
        };
267
        errorViewer.setContentProvider(provider);
268
        errorViewer.setInput(getManager());
269
    }
270
271
    /**
272
     * Get the notificationManager that this is being created for.
273
     * 
274
     * @return
275
     */
276
    private ErrorNotificationManager getManager() {
277
        return ProgressManager.getInstance().errorManager;
278
    }
279
280
    /**
281
     * Refresh the contents of the viewer.
282
     */
283
    void refresh() {
284
        errorViewer.refresh();
285
    }
286
287
    private void initLabelProvider() {
288
        ITableLabelProvider provider = new ITableLabelProvider() {
289
            /*
290
             * (non-Javadoc)
291
             * 
292
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
293
             */
294
            public void addListener(ILabelProviderListener listener) {
295
                //Do nothing
296
            }
297
298
            /*
299
             * (non-Javadoc)
300
             * 
301
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
302
             */
303
            public void dispose() {
304
                //Do nothing
305
            }
306
307
            /*
308
             * (non-Javadoc)
309
             * 
310
             * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object,
311
             *      int)
312
             */
313
            public Image getColumnImage(Object element, int columnIndex) {
314
                return JFaceResources.getImageRegistry().get(
315
                        ErrorNotificationManager.ERROR_JOB_KEY);
316
            }
317
318
            /*
319
             * (non-Javadoc)
320
             * 
321
             * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object,
322
             *      int)
323
             */
324
            public String getColumnText(Object element, int columnIndex) {
325
                return ((ErrorInfo) element).getDisplayString();
326
            }
327
328
            /*
329
             * (non-Javadoc)
330
             * 
331
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
332
             *      java.lang.String)
333
             */
334
            public boolean isLabelProperty(Object element, String property) {
335
                return false;
336
            }
337
338
            /*
339
             * (non-Javadoc)
340
             * 
341
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
342
             */
343
            public void removeListener(ILabelProviderListener listener) {
344
                //Do nothing
345
            }
346
        };
347
        errorViewer.setLabelProvider(provider);
348
    }
349
350
    /**
351
     * Open the error dialog on the current selection.
352
     */
353
    private void openErrorDialog() {
354
        ErrorInfo element = getSingleSelection();
355
        if (element == null)
356
            return;
357
        ErrorDialog.openError(getShell(), element.getDisplayString(), null,
358
                element.getErrorStatus());
359
    }
360
361
    /**
362
     * Get the single selection. Return null if the selection is not just one
363
     * element.
364
     * 
365
     * @return ErrorInfo or <code>null</code>.
366
     */
367
    private ErrorInfo getSingleSelection() {
368
        ISelection rawSelection = errorViewer.getSelection();
369
        if (rawSelection != null
370
                && rawSelection instanceof IStructuredSelection) {
371
            IStructuredSelection selection = (IStructuredSelection) rawSelection;
372
            if (selection.size() == 1)
373
                return (ErrorInfo) selection.getFirstElement();
374
        }
375
        return null;
376
    }
377
378
    /*
379
     * (non-Javadoc)
380
     * 
381
     * @see org.eclipse.jface.dialogs.Dialog#close()
382
     */
383
    public boolean close() {
384
        getManager().clearAllErrors();
385
        Rectangle shellPosition = getShell().getBounds();
386
        boolean result = super.close();
387
        ProgressManagerUtil.animateDown(shellPosition);
388
        return result;
389
    }
390
391
    /*
392
     * (non-Javadoc)
393
     * 
394
     * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
395
     */
396
    protected void initializeBounds() {
397
        super.initializeBounds();
398
        Rectangle shellPosition = getShell().getBounds();
399
        ProgressManagerUtil.animateUp(shellPosition);
400
    }
401
402
    /**
403
     * Create this dialog's drop-down list component.
404
     * 
405
     * @param detailsParent
406
     *            the parent composite
407
     */
408
    private void createDetailsList(Composite detailsParent) {
409
        // create the list
410
        detailsList = new List(detailsParent, SWT.BORDER | SWT.H_SCROLL
411
                | SWT.V_SCROLL | SWT.MULTI);
412
413
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
414
                | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL
415
                | GridData.GRAB_VERTICAL);
416
        data.heightHint = detailsList.getItemHeight() * DETAILS_LIST_ITEM_COUNT;
417
        data.horizontalSpan = 2;
418
        detailsList.setLayoutData(data);
419
        Menu copyMenu = new Menu(detailsList);
420
        MenuItem copyItem = new MenuItem(copyMenu, SWT.NONE);
421
        copyItem.addSelectionListener(new SelectionListener() {
422
            /*
423
             * @see SelectionListener.widgetSelected (SelectionEvent)
424
             */
425
            public void widgetSelected(SelectionEvent e) {
426
                copyToClipboard();
427
            }
428
429
            /*
430
             * @see SelectionListener.widgetDefaultSelected(SelectionEvent)
431
             */
432
            public void widgetDefaultSelected(SelectionEvent e) {
433
                copyToClipboard();
434
            }
435
        });
436
        copyItem.setText(JFaceResources.getString("copy")); //$NON-NLS-1$
437
        detailsList.setMenu(copyMenu);
438
    }
439
440
    /**
441
     * Set the contents of the details list to be the status from the selected
442
     * error.
443
     */
444
    private void setDetailsContents() {
445
446
        Collection statusList = new ArrayList();
447
448
        ErrorInfo info = getSingleSelection();
449
450
        if (info != null) {
451
            selectedError = info;
452
            statusList.add(selectedError.getErrorStatus().getMessage());
453
            if (selectedError.getErrorStatus().getException() != null) {
454
                Throwable exception = selectedError.getErrorStatus()
455
                        .getException();
456
                statusList.add(exception.toString());
457
                StackTraceElement[] elements = exception.getStackTrace();
458
                for (int i = 0; i < elements.length; i++) {
459
                    statusList.add(elements[i].toString());
460
                }
461
            }
462
            IStatus[] statuses = (selectedError.getErrorStatus().getChildren());
463
            for (int i = 0; i < statuses.length; i++) {
464
                statusList.add(NESTING_INDENT + statuses[i].getMessage());
465
            }
466
        }
467
468
        String[] items = new String[statusList.size()];
469
        statusList.toArray(items);
470
471
        detailsList.setItems(items);
472
473
    }
474
475
    /**
476
     * Copy the contents of the statuses to the clipboard.
477
     */
478
    private void copyToClipboard() {
479
480
        if (selectedError == null)
481
            return;
482
483
        if (clipboard != null)
484
            clipboard.dispose();
485
486
        StringBuffer statusBuffer = new StringBuffer();
487
        populateCopyBuffer(selectedError.getErrorStatus(), statusBuffer, 0);
488
        clipboard = new Clipboard(detailsList.getDisplay());
489
        clipboard.setContents(new Object[] { statusBuffer.toString() },
490
                new Transfer[] { TextTransfer.getInstance() });
491
    }
492
493
    /**
494
     * Put the details of the status of the error onto the stream.
495
     * 
496
     * @param buildingStatus
497
     * @param buffer
498
     * @param nesting
499
     */
500
    private void populateCopyBuffer(IStatus buildingStatus,
501
            StringBuffer buffer, int nesting) {
502
503
        for (int i = 0; i < nesting; i++) {
504
            buffer.append(NESTING_INDENT); //$NON-NLS-1$
505
        }
506
        buffer.append(buildingStatus.getMessage());
507
508
        if (buildingStatus.getException() != null) {
509
            Throwable exception = buildingStatus.getException();
510
            buffer.append("\n"); //$NON-NLS-1$
511
            buffer.append(exception.toString());
512
            StackTraceElement[] elements = exception.getStackTrace();
513
            for (int i = 0; i < elements.length; i++) {
514
                buffer.append("\n"); //$NON-NLS-1$
515
                buffer.append(elements[i].toString());
516
517
            }
518
        }
519
520
        buffer.append("\n"); //$NON-NLS-1$
521
        IStatus[] children = buildingStatus.getChildren();
522
        for (int i = 0; i < children.length; i++) {
523
            populateCopyBuffer(children[i], buffer, nesting + 1);
524
        }
525
    }
526
}
(-)Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationManager.java (-75 / +124 lines)
Lines 12-35 Link Here
12
12
13
import java.net.MalformedURLException;
13
import java.net.MalformedURLException;
14
import java.net.URL;
14
import java.net.URL;
15
import java.util.Collection;
15
import java.util.*;
16
import java.util.Collections;
16
17
import java.util.HashSet;
17
import org.eclipse.core.runtime.*;
18
import java.util.Iterator;
18
import org.eclipse.core.runtime.jobs.Job;
19
import java.util.Set;
20
21
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.Status;
24
import org.eclipse.jface.resource.ImageDescriptor;
19
import org.eclipse.jface.resource.ImageDescriptor;
25
import org.eclipse.jface.resource.JFaceResources;
20
import org.eclipse.jface.resource.JFaceResources;
26
import org.eclipse.ui.IWorkbench;
21
import org.eclipse.swt.widgets.Shell;
27
import org.eclipse.ui.IWorkbenchWindow;
22
import org.eclipse.ui.*;
28
import org.eclipse.ui.PlatformUI;
23
import org.eclipse.ui.internal.*;
29
import org.eclipse.ui.internal.ExceptionHandler;
24
import org.eclipse.ui.progress.IProgressConstants;
30
import org.eclipse.ui.internal.Workbench;
31
import org.eclipse.ui.internal.WorkbenchPlugin;
32
import org.eclipse.ui.progress.UIJob;
33
import org.eclipse.ui.progress.WorkbenchJob;
25
import org.eclipse.ui.progress.WorkbenchJob;
34
26
35
/**
27
/**
Lines 44-52 Link Here
44
36
45
    private Collection errors = Collections.synchronizedSet(new HashSet());
37
    private Collection errors = Collections.synchronizedSet(new HashSet());
46
38
47
    private ErrorNotificationDialog dialog;
39
    private JobErrorDialog dialog;
48
49
    private boolean dialogActive = false;
50
40
51
    /**
41
    /**
52
     * Create a new instance of the receiver.
42
     * Create a new instance of the receiver.
Lines 70-76 Link Here
70
     * @param status
60
     * @param status
71
     * @param jobName
61
     * @param jobName
72
     */
62
     */
73
    void addError(IStatus status, String jobName) {
63
    void addError(IStatus status, Job job) {
74
64
75
        //Handle out of memory errors via the workbench
65
        //Handle out of memory errors via the workbench
76
        final Throwable exception = status.getException();
66
        final Throwable exception = status.getException();
Lines 86-118 Link Here
86
76
87
            return;
77
            return;
88
        }
78
        }
89
        errors.add(new ErrorInfo(status, jobName));
79
        ErrorInfo errorInfo = new ErrorInfo(status, job);
90
        if (dialogActive) {
80
        showError(errorInfo);
91
            if (dialog != null)
92
                refreshDialog();
93
        } else
94
            openErrorDialog(jobName, status);
95
    }
81
    }
96
82
97
    /**
83
    /**
98
     * 
84
     * Show the error in the error dialog. This is done from the UI thread to
85
     * ensure that no errors are dropped.
86
     * @param errorInfo the error to be displayed
99
     */
87
     */
100
    private void refreshDialog() {
88
    private void showError(final ErrorInfo errorInfo) {
89
        
90
        if (!PlatformUI.isWorkbenchRunning()) {
91
            //We are shutdown so just log
92
            WorkbenchPlugin.log(errorInfo.getJob().getName(), errorInfo.getErrorStatus());
93
            return;
94
        }
101
95
102
        UIJob refreshJob = new UIJob(ProgressMessages
96
        // We must open or update the error dialog in the UI thread to ensure that
103
                .getString("ErrorNotificationManager.RefreshErrorDialogJob")) { //$NON-NLS-1$
97
        // errors are not dropped
104
            /* (non-Javadoc)
98
        WorkbenchJob job = new WorkbenchJob(ProgressMessages
105
             * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
99
                .getString("ErrorNotificationManager.OpenErrorDialogJob")) { //$NON-NLS-1$
106
             */
107
            public IStatus runInUIThread(IProgressMonitor monitor) {
100
            public IStatus runInUIThread(IProgressMonitor monitor) {
108
                dialog.refresh();
101
                // Add the error in the UI thread to ensure thread safety in the dialog
102
                errors.add(errorInfo);
103
                if (dialog != null) {
104
                    dialog.refresh();
105
                } else if (Platform.isRunning()) {
106
                    // Delay prompting if the job property is set
107
                    Object noPromptProperty = errorInfo.getJob().getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY);
108
                    boolean prompt;
109
                    if (noPromptProperty instanceof Boolean) {
110
                        prompt = !((Boolean)noPromptProperty).booleanValue();
111
                    } else {
112
                        prompt = true;
113
                    }
114
                    if (prompt) {
115
                        return openErrorDialog(null /* use default title */, null /* use default message */, errorInfo);
116
                    }
117
                }
109
                return Status.OK_STATUS;
118
                return Status.OK_STATUS;
110
            }
119
            }
111
        };
120
        };
112
121
        job.setSystem(true);
113
        refreshJob.setSystem(true);
122
        job.schedule();
114
        refreshJob.schedule();
115
116
    }
123
    }
117
124
118
    /**
125
    /**
Lines 126-168 Link Here
126
    /**
133
    /**
127
     * The job caleed jobName has just failed with status status.
134
     * The job caleed jobName has just failed with status status.
128
     * Open the error dialog if possible - otherwise log the error.
135
     * Open the error dialog if possible - otherwise log the error.
136
     * @param title the title of the dialog or <code>null</code>
137
     * @param msg the message for the dialog oe <code>null</code>
129
     * @param jobName String. The name of the Job
138
     * @param jobName String. The name of the Job
130
     * @param status IStatus The status of the failure.
139
     * @param status IStatus The status of the failure.
131
     */
140
     */
132
    private void openErrorDialog(String jobName, IStatus status) {
141
    private IStatus openErrorDialog(String title, String msg, final ErrorInfo errorInfo) {
142
        IWorkbench workbench = PlatformUI.getWorkbench();
133
143
134
        if (!PlatformUI.isWorkbenchRunning()) {
144
        //Abort on shutdown
135
            //We are shutdown so just log
145
        if (workbench instanceof Workbench
136
            WorkbenchPlugin.log(jobName, status);
146
                && ((Workbench) workbench).isClosing())
137
            return;
147
            return Status.CANCEL_STATUS;
148
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
149
150
        if (window == null)
151
            return Status.CANCEL_STATUS;
152
        dialog = new JobErrorDialog(window.getShell(), title, msg, errorInfo, IStatus.OK
153
                | IStatus.INFO | IStatus.WARNING | IStatus.ERROR);
154
        try {
155
	        dialog.open();
156
        } finally {
157
            dialog = null;
158
            clearAllErrors();
138
        }
159
        }
139
160
        return Status.OK_STATUS;
140
        dialogActive = true;
141
        WorkbenchJob job = new WorkbenchJob(ProgressMessages
142
                .getString("ErrorNotificationManager.OpenErrorDialogJob")) { //$NON-NLS-1$
143
            /*
144
             * (non-Javadoc)
145
             * 
146
             * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
147
             */
148
            public IStatus runInUIThread(IProgressMonitor monitor) {
149
                IWorkbench workbench = PlatformUI.getWorkbench();
150
151
                //Abort on shutdown
152
                if (workbench instanceof Workbench
153
                        && ((Workbench) workbench).isClosing())
154
                    return Status.CANCEL_STATUS;
155
                IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
156
157
                if (window == null)
158
                    return Status.CANCEL_STATUS;
159
                dialog = new ErrorNotificationDialog(window.getShell());
160
                dialog.open();
161
                return Status.OK_STATUS;
162
            }
163
        };
164
        job.setSystem(true);
165
        job.schedule();
166
    }
161
    }
167
162
168
    /**
163
    /**
Lines 200-215 Link Here
200
	/**
195
	/**
201
     * Clear all of the errors held onto by the receiver.
196
     * Clear all of the errors held onto by the receiver.
202
     */
197
     */
203
    void clearAllErrors() {
198
    private void clearAllErrors() {
204
    	removeFromFinishedJobs(errors);
199
    	removeFromFinishedJobs(errors);
205
        errors.clear();
200
        errors.clear();
206
    }
201
    }
207
202
208
    /**
203
    /**
209
     * Remove the reference to the errors dialog.
204
     * Display the error for the given job and any other errors
205
     * that have been accumulated. This method must be invoked
206
     * from the UI thread.
207
     * @param shell the shell used to parent the dialog
208
     * @param job the job whose error should be displayed
209
     * @return <code>true</code> if the info for the job was found and the error
210
     * displayed and <code>false</code> otherwise.
211
     */
212
    public boolean showErrorFor(Shell shell, Job job, String title, String msg) {
213
        if (dialog != null) {
214
            // The dialog is already open so the error is being displayed
215
            return true;
216
        }
217
        ErrorInfo info = getErrorInfo(job);
218
        if (job == null) {
219
            info = getMostRecentError();
220
        } else {
221
            info = getErrorInfo(job);
222
        }
223
        if (info != null) {
224
	        openErrorDialog(title, msg, info);
225
	        return true;
226
        }
227
        return false;
228
    }
229
230
    /*
231
     * Return the most recent error.
232
     */
233
    private ErrorInfo getMostRecentError() {
234
        ErrorInfo mostRecentInfo = null;
235
        for (Iterator iter = errors.iterator(); iter.hasNext();) {
236
            ErrorInfo info = (ErrorInfo) iter.next();
237
            if (mostRecentInfo == null || info.getTimestamp() > mostRecentInfo.getTimestamp()) {
238
                mostRecentInfo = info;
239
            }
240
        }
241
        return mostRecentInfo;
242
    }
243
244
    /*
245
     * Return the error info for the given job
246
     */
247
    private ErrorInfo getErrorInfo(Job job) {
248
        for (Iterator iter = errors.iterator(); iter.hasNext();) {
249
            ErrorInfo info = (ErrorInfo) iter.next();
250
            if (info.getJob() == job) {
251
                return info;
252
            }
253
        }
254
        return null;
255
    }
256
257
    /**
258
     * Return whether the manager has errors to report.
259
     * @return whether the manager has errors to report
210
     */
260
     */
211
    void clearDialog() {
261
    public boolean hasErrors() {
212
        dialog = null;
262
        return !errors.isEmpty();
213
        dialogActive = false;
214
    }
263
    }
215
}
264
}
(-)Eclipse UI/org/eclipse/ui/internal/progress/FinishedJobs.java (-1 / +4 lines)
Lines 288-298 Link Here
288
        }
288
        }
289
    }
289
    }
290
290
291
    void remove(JobTreeElement jte) {
291
    boolean remove(JobTreeElement jte) {
292
        boolean fire = false;
292
        boolean fire = false;
293
        boolean removed = false;
293
294
294
        synchronized (keptjobinfos) {
295
        synchronized (keptjobinfos) {
295
            if (keptjobinfos.remove(jte)) {
296
            if (keptjobinfos.remove(jte)) {
297
                removed = true;
296
                finishedTime.remove(jte);
298
                finishedTime.remove(jte);
297
                disposeAction(jte);
299
                disposeAction(jte);
298
                if (NewProgressViewer.DEBUG)
300
                if (NewProgressViewer.DEBUG)
Lines 324-329 Link Here
324
                jv.removed(jte);
326
                jv.removed(jte);
325
            }
327
            }
326
        }
328
        }
329
        return removed;
327
    }
330
    }
328
331
329
    /**
332
    /**
(-)Eclipse UI/org/eclipse/ui/internal/progress/NewProgressViewer.java (-56 / +37 lines)
Lines 12-21 Link Here
12
12
13
import java.net.URL;
13
import java.net.URL;
14
import java.text.DateFormat;
14
import java.text.DateFormat;
15
import java.util.ArrayList;
15
import java.util.*;
16
import java.util.Date;
17
import java.util.HashMap;
18
import java.util.HashSet;
19
import java.util.List;
16
import java.util.List;
20
17
21
import org.eclipse.core.runtime.IStatus;
18
import org.eclipse.core.runtime.IStatus;
Lines 24-70 Link Here
24
import org.eclipse.jface.action.Action;
21
import org.eclipse.jface.action.Action;
25
import org.eclipse.jface.action.IAction;
22
import org.eclipse.jface.action.IAction;
26
import org.eclipse.jface.dialogs.ErrorDialog;
23
import org.eclipse.jface.dialogs.ErrorDialog;
27
import org.eclipse.jface.resource.ImageDescriptor;
24
import org.eclipse.jface.resource.*;
28
import org.eclipse.jface.resource.JFaceColors;
29
import org.eclipse.jface.resource.JFaceResources;
30
import org.eclipse.jface.util.IPropertyChangeListener;
25
import org.eclipse.jface.util.IPropertyChangeListener;
31
import org.eclipse.jface.util.PropertyChangeEvent;
26
import org.eclipse.jface.util.PropertyChangeEvent;
32
import org.eclipse.jface.viewers.IContentProvider;
27
import org.eclipse.jface.viewers.*;
33
import org.eclipse.jface.viewers.ISelection;
34
import org.eclipse.jface.viewers.ITreeContentProvider;
35
import org.eclipse.jface.viewers.StructuredSelection;
36
import org.eclipse.jface.viewers.TreeViewer;
37
import org.eclipse.jface.viewers.ViewerSorter;
38
import org.eclipse.swt.SWT;
28
import org.eclipse.swt.SWT;
39
import org.eclipse.swt.custom.ScrolledComposite;
29
import org.eclipse.swt.custom.ScrolledComposite;
40
import org.eclipse.swt.events.ControlAdapter;
30
import org.eclipse.swt.events.*;
41
import org.eclipse.swt.events.ControlEvent;
31
import org.eclipse.swt.graphics.*;
42
import org.eclipse.swt.events.SelectionAdapter;
32
import org.eclipse.swt.widgets.*;
43
import org.eclipse.swt.events.SelectionEvent;
44
import org.eclipse.swt.events.TreeListener;
45
import org.eclipse.swt.graphics.Color;
46
import org.eclipse.swt.graphics.Cursor;
47
import org.eclipse.swt.graphics.Font;
48
import org.eclipse.swt.graphics.FontData;
49
import org.eclipse.swt.graphics.FontMetrics;
50
import org.eclipse.swt.graphics.GC;
51
import org.eclipse.swt.graphics.Image;
52
import org.eclipse.swt.graphics.Point;
53
import org.eclipse.swt.graphics.Rectangle;
54
import org.eclipse.swt.widgets.Canvas;
55
import org.eclipse.swt.widgets.Composite;
56
import org.eclipse.swt.widgets.Control;
57
import org.eclipse.swt.widgets.Display;
58
import org.eclipse.swt.widgets.Event;
59
import org.eclipse.swt.widgets.Item;
60
import org.eclipse.swt.widgets.Label;
61
import org.eclipse.swt.widgets.Layout;
62
import org.eclipse.swt.widgets.Listener;
63
import org.eclipse.swt.widgets.ProgressBar;
64
import org.eclipse.swt.widgets.ToolBar;
65
import org.eclipse.swt.widgets.ToolItem;
66
import org.eclipse.swt.widgets.Tree;
67
import org.eclipse.swt.widgets.Widget;
68
import org.eclipse.ui.internal.misc.Assert;
33
import org.eclipse.ui.internal.misc.Assert;
69
import org.eclipse.ui.internal.util.ImageSupport;
34
import org.eclipse.ui.internal.util.ImageSupport;
70
import org.eclipse.ui.progress.IProgressConstants;
35
import org.eclipse.ui.progress.IProgressConstants;
Lines 234-240 Link Here
234
            return null;
199
            return null;
235
        }
200
        }
236
201
237
        public boolean kill(boolean refresh, boolean broadcast) {
202
        public boolean kill() {
238
            return true;
203
            return true;
239
        }
204
        }
240
205
Lines 509-515 Link Here
509
                jobitem.locked = true;
474
                jobitem.locked = true;
510
                gotoAction.run();
475
                gotoAction.run();
511
                if (jobitem.jobTerminated)
476
                if (jobitem.jobTerminated)
512
                    jobitem.kill(true, true);
477
                    jobitem.kill();
513
                return true;
478
                return true;
514
            }
479
            }
515
            return false;
480
            return false;
Lines 520-526 Link Here
520
            if (jobTreeElement == null) // shouldn't happen
485
            if (jobTreeElement == null) // shouldn't happen
521
                return false;
486
                return false;
522
487
523
            Job job = getJob();
488
            final Job job = getJob();
524
            if (job != null) {
489
            if (job != null) {
525
                // check for icon property and propagate to parent
490
                // check for icon property and propagate to parent
526
                if (jobitem.image == null)
491
                if (jobitem.image == null)
Lines 542-552 Link Here
542
                        setAction(new Action() {
507
                        setAction(new Action() {
543
                            public void run() {
508
                            public void run() {
544
                                String title = ProgressMessages
509
                                String title = ProgressMessages
545
                                        .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$
510
	                                    .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$
546
                                String msg = ProgressMessages
511
	                            String msg = ProgressMessages
547
                                        .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$
512
	                                    .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$
548
                                ErrorDialog.openError(getShell(), title, msg,
513
                                if (!getManager().showErrorFor(getShell(), job, title, msg)) {
549
                                        result);
514
                                    // The error is missing from the error manager.
515
                                    // This should only occur if what the progress view is showing is
516
                                    // out-of-sync with the ErrorNotificationManager and/or FinishedJobs
517
                                    // manager. In other words, it shouldn't happen but may so it is
518
                                    // better to show the user something than fail silently
519
		                            ErrorDialog.openError(getShell(), title, msg,
520
		                                    result);
521
                                }
522
                            }
523
                            /*
524
                             * Get the notificationManager that this is being created for.
525
                             */
526
                            private ErrorNotificationManager getManager() {
527
                                return ProgressManager.getInstance().errorManager;
550
                            }
528
                            }
551
                        });
529
                        });
552
                    }
530
                    }
Lines 786-792 Link Here
786
764
787
        boolean cancelOrRemove() {
765
        boolean cancelOrRemove() {
788
            if (jobTerminated)
766
            if (jobTerminated)
789
                return kill(true, true);
767
                return kill();
790
            jobTreeElement.cancel();
768
            jobTreeElement.cancel();
791
            return false;
769
            return false;
792
        }
770
        }
Lines 879-892 Link Here
879
            return changed;
857
            return changed;
880
        }
858
        }
881
859
882
        public boolean kill(boolean refresh, boolean broadcast) {
860
        public boolean kill() {
883
            if (jobTerminated) {
861
            if (jobTerminated) {
884
862
                // Removing the job from the list of jobs will 
885
                if (broadcast)
863
                // remove the job from the view using a callback
886
                    finishedJobs.remove(jobTreeElement);
864
                if (!finishedJobs.remove(jobTreeElement)) {
887
                else {
865
                    // The terminated job has already been removed
866
                    // from the list of finished jobs but was somehow
867
                    // left in the view. Dispose of the item and refresh 
868
                    // the view
888
                    dispose();
869
                    dispose();
889
                    relayout(refresh, refresh);
870
                    relayout(true, true);
890
                    return true;
871
                    return true;
891
                }
872
                }
892
            }
873
            }
(-)Eclipse UI/org/eclipse/ui/internal/progress/ProgressAnimationItem.java (-24 / +52 lines)
Lines 10-37 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.progress;
11
package org.eclipse.ui.internal.progress;
12
12
13
import java.util.Collection;
14
import java.util.Iterator;
15
13
import org.eclipse.core.runtime.IStatus;
16
import org.eclipse.core.runtime.IStatus;
14
import org.eclipse.core.runtime.jobs.Job;
17
import org.eclipse.core.runtime.jobs.Job;
15
import org.eclipse.jface.action.IAction;
18
import org.eclipse.jface.action.IAction;
16
import org.eclipse.jface.dialogs.ErrorDialog;
19
import org.eclipse.jface.dialogs.ErrorDialog;
17
import org.eclipse.swt.SWT;
20
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.DisposeEvent;
21
import org.eclipse.swt.events.*;
19
import org.eclipse.swt.events.DisposeListener;
20
import org.eclipse.swt.events.MouseAdapter;
21
import org.eclipse.swt.events.MouseEvent;
22
import org.eclipse.swt.events.MouseListener;
23
import org.eclipse.swt.events.SelectionAdapter;
24
import org.eclipse.swt.events.SelectionEvent;
25
import org.eclipse.swt.graphics.Image;
22
import org.eclipse.swt.graphics.Image;
26
import org.eclipse.swt.layout.GridData;
23
import org.eclipse.swt.layout.GridData;
27
import org.eclipse.swt.layout.GridLayout;
24
import org.eclipse.swt.layout.GridLayout;
28
import org.eclipse.swt.widgets.Composite;
25
import org.eclipse.swt.widgets.*;
29
import org.eclipse.swt.widgets.Control;
30
import org.eclipse.swt.widgets.Display;
31
import org.eclipse.swt.widgets.Label;
32
import org.eclipse.swt.widgets.ProgressBar;
33
import org.eclipse.swt.widgets.ToolBar;
34
import org.eclipse.swt.widgets.ToolItem;
35
import org.eclipse.ui.PlatformUI;
26
import org.eclipse.ui.PlatformUI;
36
import org.eclipse.ui.internal.util.ImageSupport;
27
import org.eclipse.ui.internal.util.ImageSupport;
37
import org.eclipse.ui.progress.IProgressConstants;
28
import org.eclipse.ui.progress.IProgressConstants;
Lines 92-108 Link Here
92
83
93
                    IStatus status = job.getResult();
84
                    IStatus status = job.getResult();
94
                    if (status != null && status.getSeverity() == IStatus.ERROR) {
85
                    if (status != null && status.getSeverity() == IStatus.ERROR) {
86
                        // The showErrorFor method will show the user all the accumulated errors
87
                        // and clear then when done
95
                        String title = ProgressMessages
88
                        String title = ProgressMessages
96
                                .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$
89
	                            .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$
97
                        String msg = ProgressMessages
90
	                    String msg = ProgressMessages
98
                                .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$
91
	                            .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$
99
                        ErrorDialog.openError(toolbar.getShell(), title, msg,
92
                        if (!getManager().showErrorFor(toolbar.getShell(), job, title, msg)) {
100
                                status);
93
                            // The error is missing from the error manager.
101
                        JobTreeElement topElement = (JobTreeElement) ji
94
                            // This should only occur if what the progress view is showing is
102
                                .getParent();
95
                            // out-of-sync with the ErrorNotificationManager
103
                        if (topElement == null)
96
                            // In other words, it shouldn't happen but may so it is
104
                            topElement = ji;
97
                            // better to show the user something and clean up
105
                        FinishedJobs.getInstance().remove(topElement);
98
                            // than fail silently.
99
		                    ErrorDialog.openError(toolbar.getShell(), title, msg,
100
		                            status);
101
		                    JobTreeElement topElement = (JobTreeElement) ji
102
		                            .getParent();
103
		                    if (topElement == null)
104
		                        topElement = ji;
105
		                    FinishedJobs.getInstance().remove(topElement);
106
                        }
106
                        return;
107
                        return;
107
                    }
108
                    }
108
109
Lines 124-129 Link Here
124
            }
125
            }
125
        }
126
        }
126
127
128
        if (getManager().hasErrors()) {
129
            getManager().showErrorFor(toolbar.getShell(), null, null, null);
130
        }
131
        
127
        progressRegion.processDoubleClick();
132
        progressRegion.processDoubleClick();
128
        refresh();
133
        refresh();
129
    }
134
    }
Lines 183-188 Link Here
183
                }
188
                }
184
            }
189
            }
185
        }
190
        }
191
        
192
        // If the error manager has errors, display the error indication
193
        // just in case a previous job ended in error but wasn't kept
194
        ErrorNotificationManager errorNotificationManager = ProgressManager.getInstance().errorManager;
195
        if (errorNotificationManager.hasErrors()) {
196
            Collection errors = errorNotificationManager.getErrors();
197
            for (Iterator iter = errors.iterator(); iter.hasNext();) {
198
                ErrorInfo info = (ErrorInfo) iter.next();
199
	            initButton(
200
	                    errorImage,
201
	                    ProgressMessages
202
	                            .format(
203
	                                    "ProgressAnimationItem.error", new Object[] { info.getJob().getName() })); //$NON-NLS-1$
204
	            return;
205
            }
206
        }
186
207
187
        if (animationRunning) {
208
        if (animationRunning) {
188
            initButton(noneImage, ProgressMessages
209
            initButton(noneImage, ProgressMessages
Lines 317-321 Link Here
317
                refresh();
338
                refresh();
318
            }
339
            }
319
        });
340
        });
341
    }
342
    
343
    /*
344
     * Get the notificationManager that this is being created for.
345
     */
346
    private ErrorNotificationManager getManager() {
347
        return ProgressManager.getInstance().errorManager;
320
    }
348
    }
321
}
349
}
(-)Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java (-2 / +1 lines)
Lines 389-396 Link Here
389
                JobInfo info = getJobInfo(event.getJob());
389
                JobInfo info = getJobInfo(event.getJob());
390
                if (event.getResult() != null
390
                if (event.getResult() != null
391
                        && event.getResult().getSeverity() == IStatus.ERROR) {
391
                        && event.getResult().getSeverity() == IStatus.ERROR) {
392
                    errorManager.addError(event.getResult(), event.getJob()
392
                    errorManager.addError(event.getResult(), event.getJob());
393
                            .getName());
394
                }
393
                }
395
                jobs.remove(event.getJob());
394
                jobs.remove(event.getJob());
396
                //Only refresh if we are showing it
395
                //Only refresh if we are showing it
(-)Eclipse UI/org/eclipse/ui/internal/progress/messages.properties (-1 / +1 lines)
Lines 19-25 Link Here
19
JobInfo.Sleeping = {0} (Sleeping)
19
JobInfo.Sleeping = {0} (Sleeping)
20
JobInfo.System = System: {0}
20
JobInfo.System = System: {0}
21
JobInfo.Cancelled = {0} (Cancelled)
21
JobInfo.Cancelled = {0} (Cancelled)
22
JobInfo.Error = {0} (Error: {1})
22
JobInfo.Error = {0} (Time of error: {1})
23
JobInfo.Blocked = {0} (Blocked: {1})
23
JobInfo.Blocked = {0} (Blocked: {1})
24
JobInfo.Finished = {0} (Finished)
24
JobInfo.Finished = {0} (Finished)
25
JobInfo.FinishedAt = {0} (Finished at {1})
25
JobInfo.FinishedAt = {0} (Finished at {1})
(-)Eclipse UI/org/eclipse/ui/progress/IProgressConstants.java (-2 / +18 lines)
Lines 48-55 Link Here
48
     * set of kept Jobs. That is, whenever a Job that has the KEEPONE_PROPERTY starts or finishes,
48
     * set of kept Jobs. That is, whenever a Job that has the KEEPONE_PROPERTY starts or finishes,
49
     * all other kept Jobs of the same family are removed first.
49
     * all other kept Jobs of the same family are removed first.
50
     * <p>
50
     * <p>
51
     * Membership to family is established by implementing a Job's <code>belongsTo</code>
51
     * Membership to family is determined using a Job's <code>belongsTo</code>
52
     * method and returning <code>true</code>.
52
     * method. The progress service will pass each job that currently exists in the
53
     * view to the <code>belongsTo</code> method of a newly added job. Clients who
54
     * set the <code>KEEPONE_PROPERTY</code> must implement a <code>belongsTo</code>
55
     * method that determines if the passed job is of the same family as their job
56
     * and return <code>true</code> if it is.
53
     * </p>
57
     * </p>
54
     * <p>
58
     * <p>
55
     * Please note that other Jobs of the same family are only removed if they have finished.
59
     * Please note that other Jobs of the same family are only removed if they have finished.
Lines 108-111 Link Here
108
     */
112
     */
109
    public static final QualifiedName PROPERTY_IN_DIALOG = new QualifiedName(
113
    public static final QualifiedName PROPERTY_IN_DIALOG = new QualifiedName(
110
            IProgressConstants.PROPERTY_PREFIX, "inDialog"); //$NON-NLS-1$
114
            IProgressConstants.PROPERTY_PREFIX, "inDialog"); //$NON-NLS-1$
115
    
116
    /**
117
     * This property provides a hint to the progress UI to not prompt on errors
118
     * immediatlybut instead make the errors available through the progress UI.
119
     * <p>
120
     * The property must be of type <code>Boolean</code> and the hint is used
121
     * if its value is <code>true</code>.
122
     * </p>
123
     * @since 3.1
124
     */
125
    public static final QualifiedName NO_IMMEDIATE_ERROR_PROMPT_PROPERTY = new QualifiedName(
126
            PROPERTY_PREFIX, "delayErrorPrompt"); //$NON-NLS-1$
111
}
127
}
(-)Eclipse (+471 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2004 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.ui.internal.progress;
12
13
import java.net.URL;
14
import java.util.*;
15
16
import org.eclipse.core.runtime.jobs.Job;
17
import org.eclipse.jface.action.IAction;
18
import org.eclipse.jface.dialogs.*;
19
import org.eclipse.jface.dialogs.ErrorDialog;
20
import org.eclipse.jface.dialogs.IDialogConstants;
21
import org.eclipse.jface.preference.IPreferenceStore;
22
import org.eclipse.jface.resource.ImageDescriptor;
23
import org.eclipse.jface.viewers.*;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.graphics.*;
26
import org.eclipse.swt.layout.GridData;
27
import org.eclipse.swt.layout.GridLayout;
28
import org.eclipse.swt.widgets.*;
29
import org.eclipse.ui.internal.WorkbenchPlugin;
30
import org.eclipse.ui.progress.IProgressConstants;
31
32
/**
33
 * A dialog that can display the errors from multiple jobs at once
34
 * but is visually optimal for the case of one job (which is the
35
 * case 99% of the time).
36
 */
37
public class JobErrorDialog extends ErrorDialog {
38
    
39
    /*
40
     * Preference used to indicate whether the user should be prompted
41
     * to confirm the execution of the job's goto action
42
     */
43
    private static final String PREF_SKIP_GOTO_ACTION_PROMPT = "pref_skip_goto_action_prompt"; //$NON-NLS-1$
44
    
45
    /*
46
     * The id of the goto action button
47
     */
48
    private static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1;
49
    
50
    private TableViewer jobListViewer;
51
    private ErrorInfo selectedError;
52
53
    public JobErrorDialog(Shell parentShell, String title, String msg, ErrorInfo errorInfo, int displayMask) {
54
        super(parentShell, title == null ? errorInfo.getJob().getName() : title, msg, errorInfo.getErrorStatus(), displayMask);
55
        this.selectedError = errorInfo;
56
    }
57
    
58
    private Composite createComposite(Composite parent, int numColumns) {
59
        Composite composite = new Composite(parent, SWT.NONE);
60
        GridLayout layout = new GridLayout();
61
        layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
62
        layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
63
        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
64
        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
65
        layout.numColumns = numColumns;
66
        composite.setLayout(layout);
67
        GridData childData = new GridData(GridData.FILL_BOTH);
68
        composite.setLayoutData(childData);
69
        return composite;
70
    }
71
72
    /**
73
     * Method which should be invoked when new errors become available for display
74
     */
75
    void refresh() {
76
        if (isMultipleJobErrors()) {
77
            if (jobListViewer == null && !dialogArea.isDisposed()) {
78
	            // The job list doesn't exist so create it.
79
	            setMessage("Multiple background operations have reported errors. Select an operation to view its errors.");
80
	            getShell().setText("Multiple Errors have Occurred");
81
	            createJobListArea((Composite)dialogArea);
82
	            showDetailsArea();
83
            }
84
	        refreshJobList();
85
        }
86
        updateEnablements();
87
    }
88
89
    /* (non-Javadoc)
90
     * @see org.eclipse.jface.dialogs.ErrorDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
91
     */
92
    protected void createButtonsForButtonBar(Composite parent) {
93
        IAction gotoAction = getGotoAction();
94
        String text = null;
95
        if (gotoAction != null) {
96
            text = gotoAction.getText();
97
        }
98
        if (text == null) {
99
            // Text is set to this initiallybut will be changed for active job
100
            text = "Custom Job Action";
101
        }
102
        createButton(parent, GOTO_ACTION_ID, text, false);
103
        super.createButtonsForButtonBar(parent);
104
    }
105
    
106
    /*
107
     * Update the button enablements
108
     */
109
    private void updateEnablements() {
110
        Button details = getButton(IDialogConstants.DETAILS_ID);
111
        if (details != null) {
112
            details.setEnabled(selectedError.getErrorStatus().isMultiStatus() || isMultipleJobErrors());
113
        }
114
        Button gotoButton = getButton(GOTO_ACTION_ID);
115
        if (gotoButton != null) {
116
            IAction gotoAction = getGotoAction();
117
            boolean hasValidGotoAction = gotoAction != null;
118
            String text = gotoButton.getText();
119
            String newText = null;
120
            if (hasValidGotoAction) {
121
                newText = gotoAction.getText();
122
            }
123
            if (newText == null) {
124
                hasValidGotoAction = false;
125
                newText = "Custom Job Action";
126
            }
127
            if (!newText.equals(text)) {
128
                gotoButton.setText(newText);
129
            }
130
            gotoButton.setEnabled(hasValidGotoAction);
131
            gotoButton.setVisible(hasValidGotoAction);
132
        }
133
    }
134
135
    /* (non-Javadoc)
136
     * @see org.eclipse.jface.dialogs.ErrorDialog#buttonPressed(int)
137
     */
138
    protected void buttonPressed(int id) {
139
        if (id == GOTO_ACTION_ID) {
140
            IAction gotoAction = getGotoAction();
141
            if (gotoAction != null) {
142
	            if (!isMultipleJobErrors() || isPromptToClose()) {
143
		            okPressed(); // close the dialog
144
		            gotoAction.run(); // run the goto action
145
	            }
146
            }
147
        }
148
        super.buttonPressed(id);
149
    }
150
    
151
152
    /*
153
     * Prompt to inform the user that the dialog will close and the errors 
154
     * cleared.
155
     */
156
    private boolean isPromptToClose() {
157
        IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
158
        if (!store.contains(PREF_SKIP_GOTO_ACTION_PROMPT) || !store.getString(PREF_SKIP_GOTO_ACTION_PROMPT).equals(MessageDialogWithToggle.ALWAYS)) {
159
	        MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(getShell(), "OK to Close?", 
160
	                "Performing this action will close the error dialog and clear the errors being displayed.",
161
	                "Don't show this again", false, store, PREF_SKIP_GOTO_ACTION_PROMPT);
162
	        return dialog.getReturnCode() == OK;
163
        }
164
        return true;
165
    }
166
167
    private IAction getGotoAction() {
168
        Object property = selectedError.getJob().getProperty(IProgressConstants.ACTION_PROPERTY);
169
        if (property instanceof IAction)
170
            return (IAction)property;
171
        return null;
172
    }
173
174
    /**
175
     * This method sets the message in the message label.
176
     * 
177
     * @param messageString -
178
     *            the String for the message area
179
     */
180
    private void setMessage(String messageString) {
181
        //must not set null text in a label
182
        message = messageString == null ? "" : messageString; //$NON-NLS-1$
183
        if (messageLabel == null || messageLabel.isDisposed())
184
            return;
185
        messageLabel.setText(message);
186
    }
187
    
188
    /*
189
     * Create an area that allow the user to select one of multiple
190
     * jobs that have reported errors
191
     */
192
    private Control createJobListArea(Composite parent) {
193
        Composite composite = createComposite(parent, 1);
194
		
195
		// Display a list of jobs that have reported errors
196
        jobListViewer = new TableViewer(composite, SWT.SINGLE | SWT.H_SCROLL
197
                | SWT.V_SCROLL | SWT.BORDER);
198
        jobListViewer.setSorter(getViewerSorter());
199
        Control control = jobListViewer.getControl();
200
        GridData data = new GridData(GridData.FILL_BOTH
201
                | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
202
        data.widthHint = convertWidthInCharsToPixels(60);
203
        data.heightHint = convertHeightInCharsToPixels(10);
204
        control.setLayoutData(data);
205
        initContentProvider();
206
        initLabelProvider();
207
        jobListViewer.addSelectionChangedListener(new ISelectionChangedListener() {
208
            public void selectionChanged(SelectionChangedEvent event) {
209
                handleSelectionChange();
210
            }
211
        });
212
        applyDialogFont(parent);
213
        return composite;
214
    }
215
    
216
    /*
217
     * Return whether there are multiple errors to be displayed
218
     */
219
    private boolean isMultipleJobErrors() {
220
        return getManager().getErrors().size() > 1;
221
    }
222
    
223
    /*
224
     * Get the notificationManager that this is being created for.
225
     */
226
    private ErrorNotificationManager getManager() {
227
        return ProgressManager.getInstance().errorManager;
228
    }
229
    
230
    public ErrorInfo getSelectedError() {
231
        return selectedError;
232
    }
233
    
234
    /**
235
     * Return a viewer sorter for looking at the jobs.
236
     * 
237
     * @return
238
     */
239
    private ViewerSorter getViewerSorter() {
240
        return new ViewerSorter() {
241
            /* (non-Javadoc)
242
             * 
243
             * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer,
244
             *      java.lang.Object, java.lang.Object)
245
             */
246
            public int compare(Viewer testViewer, Object e1, Object e2) {
247
                return ((Comparable) e1).compareTo(e2);
248
            }
249
        };
250
    }
251
    
252
    /**
253
     * Sets the content provider for the viewer.
254
     */
255
    protected void initContentProvider() {
256
        IContentProvider provider = new IStructuredContentProvider() {
257
            /*
258
             * (non-Javadoc)
259
             * 
260
             * @see org.eclipse.jface.viewers.IContentProvider#dispose()
261
             */
262
            public void dispose() {
263
                //Nothing of interest here
264
            }
265
266
            /*
267
             * (non-Javadoc)
268
             * 
269
             * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
270
             */
271
            public Object[] getElements(Object inputElement) {
272
                return getManager().getErrors().toArray();
273
            }
274
275
            /*
276
             * (non-Javadoc)
277
             * 
278
             * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
279
             *      java.lang.Object, java.lang.Object)
280
             */
281
            public void inputChanged(Viewer viewer, Object oldInput,
282
                    Object newInput) {
283
                if (newInput != null)
284
                    refreshJobList();
285
            }
286
        };
287
        jobListViewer.setContentProvider(provider);
288
        jobListViewer.setInput(getManager());
289
        jobListViewer.setSelection(new StructuredSelection(selectedError));
290
    }
291
    
292
    /**
293
     * Refresh the contents of the viewer.
294
     */
295
    void refreshJobList() {
296
        if (jobListViewer != null && !jobListViewer.getControl().isDisposed()) {
297
            jobListViewer.refresh();
298
            Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
299
            getShell().setSize(newSize);
300
        }
301
        setStatus(selectedError.getErrorStatus());
302
    }
303
304
    private void initLabelProvider() {
305
        ITableLabelProvider provider = new ITableLabelProvider() {
306
            Map imageTable = new HashMap();
307
            /*
308
             * (non-Javadoc)
309
             * 
310
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
311
             */
312
            public void addListener(ILabelProviderListener listener) {
313
                //Do nothing
314
            }
315
316
            /*
317
             * (non-Javadoc)
318
             * 
319
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
320
             */
321
            public void dispose() {
322
                if (!imageTable.isEmpty()) {
323
	                for (Iterator iter = imageTable.values().iterator(); iter.hasNext();) {
324
	                    Image image = (Image) iter.next();
325
	                    image.dispose();
326
	                }
327
                }
328
            }
329
330
            /*
331
             * (non-Javadoc)
332
             * 
333
             * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object,
334
             *      int)
335
             */
336
            public Image getColumnImage(Object element, int columnIndex) {
337
                return getIcon(((ErrorInfo)element).getJob());
338
            }
339
340
            /*
341
             * Get the icon for the job. Code copied from NewProgressViewer
342
             */
343
            private Image getIcon(Job job) {
344
                if (job != null) {
345
                    
346
                    Object property = job.getProperty(IProgressConstants.ICON_PROPERTY);
347
                    
348
                    // If we already have an image cached, return it
349
                    Image im = (Image)imageTable.get(property);
350
                    if (im != null) {
351
                        return im;
352
                    }
353
                    
354
                    // Create an image from the job's icon property or family
355
                    Display display = getShell().getDisplay();
356
                    if (property instanceof ImageDescriptor) {
357
                        im = ((ImageDescriptor) property).createImage(display);
358
                        imageTable.put(property, im); // Cache for disposal
359
                    } else if (property instanceof URL) {
360
                        im = ImageDescriptor.createFromURL((URL) property)
361
                                .createImage(display);
362
                        imageTable.put(property, im); // Cache for disposal
363
                    } else {
364
                        im = ProgressManager.getInstance().getIconFor(job);
365
                        // No need to cache since the progress manager will
366
                    }
367
                    return im;
368
                }
369
                return null;
370
            }
371
            
372
            /*
373
             * (non-Javadoc)
374
             * 
375
             * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object,
376
             *      int)
377
             */
378
            public String getColumnText(Object element, int columnIndex) {
379
                return ((ErrorInfo) element).getDisplayString();
380
            }
381
382
            /*
383
             * (non-Javadoc)
384
             * 
385
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
386
             *      java.lang.String)
387
             */
388
            public boolean isLabelProperty(Object element, String property) {
389
                return false;
390
            }
391
392
            /*
393
             * (non-Javadoc)
394
             * 
395
             * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
396
             */
397
            public void removeListener(ILabelProviderListener listener) {
398
                //Do nothing
399
            }
400
        };
401
        jobListViewer.setLabelProvider(provider);
402
    }
403
    
404
    /**
405
     * Get the single selection. Return null if the selection is not just one
406
     * element.
407
     * 
408
     * @return ErrorInfo or <code>null</code>.
409
     */
410
    private ErrorInfo getSingleSelection() {
411
        ISelection rawSelection = jobListViewer.getSelection();
412
        if (rawSelection != null
413
                && rawSelection instanceof IStructuredSelection) {
414
            IStructuredSelection selection = (IStructuredSelection) rawSelection;
415
            if (selection.size() == 1)
416
                return (ErrorInfo) selection.getFirstElement();
417
        }
418
        return null;
419
    }
420
    
421
    public boolean close() {
422
        Rectangle shellPosition = getShell().getBounds();
423
        boolean result = super.close();
424
        ProgressManagerUtil.animateDown(shellPosition);
425
        return result;
426
    }
427
428
    /*
429
     * (non-Javadoc)
430
     * 
431
     * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
432
     */
433
    protected void initializeBounds() {
434
        // We need to refesh here instead of in createContents
435
        // because the showDetailsArea requires that the content
436
        // composite be set
437
        refresh();
438
        super.initializeBounds();
439
        Rectangle shellPosition = getShell().getBounds();
440
        ProgressManagerUtil.animateUp(shellPosition);
441
    }
442
    
443
    /**
444
     * The selection in the multiple job list has changed.
445
     * Update widget enablements and repopulate the list.
446
     */
447
    void handleSelectionChange() {
448
        ErrorInfo newSelection = getSingleSelection();
449
        if (newSelection != null && newSelection != selectedError) {
450
            selectedError = newSelection;
451
            setStatus(selectedError.getErrorStatus());
452
            updateEnablements();
453
            showDetailsArea();
454
        }
455
    }
456
    
457
    /* (non-Javadoc)
458
     * @see org.eclipse.jface.dialogs.ErrorDialog#isIncludeTopLevelErrorInDetails()
459
     */
460
    protected boolean isIncludeTopLevelErrorInDetails() {
461
        return isMultipleJobErrors();
462
    }
463
    
464
    /* (non-Javadoc)
465
     * @see org.eclipse.jface.dialogs.ErrorDialog#isIncludeDetailsButton()
466
     */
467
    protected boolean isIncludeDetailsButton() {
468
        // Always include the deatils button since we may have errors added that have details
469
        return true;
470
    }
471
}

Return to bug 76726