This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 204553
Collapse All | Expand All

(-)a/api.progress/apichanges.xml (-1 / +12 lines)
Lines 106-113 Link Here
106
    </apidefs>
106
    </apidefs>
107
107
108
    <!-- ACTUAL CHANGES BEGIN HERE: -->
108
    <!-- ACTUAL CHANGES BEGIN HERE: -->
109
  <changes>
110
    <change id="customDialogs">
111
        <api name="progress_api"/>
112
        <summary><code>ProgressUtils</code> class with <code>runOffEventThreadWithCustomDialogContent</code> and <code>runOffEventThreadWithProgressDialog</code> methods were added.</summary>
113
        <version major="1" minor="28"/>
114
        <date day="1" month="11" year="2011"/>
115
        <author login="pflaska	"/>
116
        <compatibility binary="compatible" source="compatible" deprecation="no" deletion="no" addition="yes"/>
117
        <description><code>ProgressUtils</code> class with <code>runOffEventThreadWithCustomDialogContent</code> and <code>runOffEventThreadWithProgressDialog</code> methods were added. These methods allow movement of operations out of AWT thread, showing the waint cursor after one second and a dialog when task is not finished in a three seconds.
118
        </description>
119
        <issue number="204553"/>
120
    </change>
109
121
110
  <changes>
111
    <change id="modalRunMethods">
122
    <change id="modalRunMethods">
112
        <api name="progress_api"/>
123
        <api name="progress_api"/>
113
        <summary>Modal progress dialogs</summary>
124
        <summary>Modal progress dialogs</summary>
(-)a/api.progress/manifest.mf (-1 / +1 lines)
Lines 3-7 Link Here
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/progress/module/resources/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/progress/module/resources/Bundle.properties
4
OpenIDE-Module-Recommends: org.netbeans.modules.progress.spi.ProgressUIWorkerProvider, org.netbeans.modules.progress.spi.RunOffEDTProvider
4
OpenIDE-Module-Recommends: org.netbeans.modules.progress.spi.ProgressUIWorkerProvider, org.netbeans.modules.progress.spi.RunOffEDTProvider
5
AutoUpdate-Essential-Module: true
5
AutoUpdate-Essential-Module: true
6
OpenIDE-Module-Specification-Version: 1.26
6
OpenIDE-Module-Specification-Version: 1.28
7
7
(-)a/api.progress/src/org/netbeans/api/progress/ProgressUtils.java (+70 lines)
Lines 47-54 Link Here
47
import java.util.concurrent.FutureTask;
47
import java.util.concurrent.FutureTask;
48
import java.util.concurrent.atomic.AtomicBoolean;
48
import java.util.concurrent.atomic.AtomicBoolean;
49
import java.util.concurrent.atomic.AtomicReference;
49
import java.util.concurrent.atomic.AtomicReference;
50
import javax.swing.JPanel;
50
import javax.swing.SwingUtilities;
51
import javax.swing.SwingUtilities;
51
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
52
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
53
import org.netbeans.modules.progress.spi.RunOffEDTProvider.JdevProgressExt;
52
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress;
54
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress;
53
import org.openide.util.Lookup;
55
import org.openide.util.Lookup;
54
import org.openide.util.RequestProcessor;
56
import org.openide.util.RequestProcessor;
Lines 141-146 Link Here
141
    }
143
    }
142
144
143
    /**
145
    /**
146
     * Runs operation out of the event thread, blocking the whole UI. When
147
     * operation takes more than 1s, the method first displays wait cursor.
148
     * If operation will not end in 3s interval, modal dialog with
149
     * progress is shown up.
150
     * If operation is marked with Cancelable interface, cancel button is
151
     * part of dialog and can be used to interrupt the operation.
152
     * 
153
     * @param operation  task to perform in the background
154
     * @param dialogTitle dialog title
155
     * @param progress  progress handle. Do not invoke any methods before
156
     *                  passing to this method. Start/progress/finish it
157
     *                  only in {@code operation}
158
     * @param includeDetailLabel  show progress detail label in the dialog
159
     * 
160
     * @since 1.28
161
     */
162
    public static void runOffEventThreadWithProgressDialog(
163
            final Runnable operation,
164
            final String dialogTitle, 
165
            final ProgressHandle progress, 
166
            final boolean includeDetailLabel) 
167
    {
168
        if (PROVIDER instanceof JdevProgressExt) {
169
            JdevProgressExt p = (JdevProgressExt) PROVIDER;
170
            p.runOffEventThreadWithProgressDialog(operation, dialogTitle, progress, includeDetailLabel);
171
        } else {
172
            PROVIDER.runOffEventDispatchThread(operation, progress.getDisplayName(),
173
                    new AtomicBoolean(false),
174
                    true,
175
                    DISPLAY_WAIT_CURSOR_MS,
176
                    DISPLAY_DIALOG_MS);
177
        }
178
    }
179
180
    /**
181
     * Runs operation out of the event thread, blocking the whole UI. When
182
     * operation takes more than 1s, the method first displays wait cursor.
183
     * If operation will not end up in 3s interval, modal dialog with
184
     * {@code content} panel is shown.
185
     * If operation is marked with Cancelable interface, cancel button is
186
     * part of dialog and can be used to interrupt the operation.
187
     * 
188
     * @param operation  task to perform in the background
189
     * @param dialogTitle dialog title
190
     * @param content  panel to be shown in the dialog
191
     * 
192
     * @since 1.28
193
     */
194
    public static void runOffEventThreadWithCustomDialogContent(
195
            final Runnable operation,
196
            final String dialogTitle,
197
            final JPanel content)
198
    {
199
        if (PROVIDER instanceof JdevProgressExt) {
200
            JdevProgressExt p = (JdevProgressExt) PROVIDER;
201
            p.runOffEventThreadWithCustomDialogContent(operation, dialogTitle, content);
202
        } else {
203
            PROVIDER.runOffEventDispatchThread(operation, 
204
                    dialogTitle, 
205
                    new AtomicBoolean(false),
206
                    true, 
207
                    DISPLAY_WAIT_CURSOR_MS,
208
                    DISPLAY_DIALOG_MS);
209
        }
210
    }
211
    
212
    /**
144
     * Show a modal progress dialog that blocks the main window, while running
213
     * Show a modal progress dialog that blocks the main window, while running
145
     * the passed runnable on a background thread.
214
     * the passed runnable on a background thread.
146
     * <p/>
215
     * <p/>
Lines 250-255 Link Here
250
    private static class Trivial implements RunOffEDTProvider {
319
    private static class Trivial implements RunOffEDTProvider {
251
        private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
320
        private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
252
321
322
        @Override
253
        public void runOffEventDispatchThread(Runnable operation, String operationDescr, AtomicBoolean cancelOperation, boolean waitForCanceled, int waitCursorAfter, int dialogAfter) {
323
        public void runOffEventDispatchThread(Runnable operation, String operationDescr, AtomicBoolean cancelOperation, boolean waitForCanceled, int waitCursorAfter, int dialogAfter) {
254
            if (SwingUtilities.isEventDispatchThread()) {
324
            if (SwingUtilities.isEventDispatchThread()) {
255
                Task t = WORKER.post(operation);
325
                Task t = WORKER.post(operation);
(-)a/api.progress/src/org/netbeans/modules/progress/spi/RunOffEDTProvider.java (+46 lines)
Lines 43-48 Link Here
43
43
44
import java.util.concurrent.Future;
44
import java.util.concurrent.Future;
45
import java.util.concurrent.atomic.AtomicBoolean;
45
import java.util.concurrent.atomic.AtomicBoolean;
46
import javax.swing.JPanel;
46
import org.netbeans.api.progress.ProgressHandle;
47
import org.netbeans.api.progress.ProgressHandle;
47
import org.netbeans.api.progress.ProgressRunnable;
48
import org.netbeans.api.progress.ProgressRunnable;
48
49
Lines 116-119 Link Here
116
         */
117
         */
117
        public <T> Future<T> showProgressDialogAndRunLater (ProgressRunnable<T> toRun, ProgressHandle handle, boolean includeDetailLabel);
118
        public <T> Future<T> showProgressDialogAndRunLater (ProgressRunnable<T> toRun, ProgressHandle handle, boolean includeDetailLabel);
118
    }
119
    }
120
        
121
    public interface JdevProgressExt extends Progress {
122
        
123
        /**
124
         * Runs operation out of the event thread, blocking the whole UI. When
125
         * operation takes more than 1s, the method first displays wait cursor.
126
         * If operation will not end up in 3s interval, modal dialog with
127
         * progress is shown up.
128
         * If operation is marked with Cancelable interface, cancel button is
129
         * part of dialog and can be used to interrupt the operation.
130
         * 
131
         * @param operation  task to perform in the background
132
         * @param dialogTitle dialog title
133
         * @param progress  progress handle. Do not invoke any methods before
134
         *                  passing to this method. Start/progress/finish it
135
         *                  only in {@code operation.run()} method
136
         * @param includeDetailLabel  show progress detail label in the dialog
137
         * 
138
         * @since 1.28
139
         */
140
        public void runOffEventThreadWithProgressDialog(
141
            final Runnable operation, 
142
            final String operationDescr,
143
            final ProgressHandle progress, 
144
            final boolean includeDetailLabel);
145
146
        /**
147
         * Runs operation out of the event thread, blocking the whole UI. When
148
         * operation takes more than 1s, the method first displays wait cursor.
149
         * If operation will not end up in 3s interval, modal dialog with
150
         * {@code content} panel is shown.
151
         * If operation is marked with Cancelable interface, cancel button is
152
         * part of dialog and can be used to interrupt the operation.
153
         * 
154
         * @param operation  task to perform in the background
155
         * @param dialogTitle dialog title
156
         * @param content  panel to be shown in the dialog
157
         * 
158
         * @since 1.28
159
         */
160
        public void runOffEventThreadWithCustomDialogContent(
161
            final Runnable operation,
162
            final String dialogTitle,
163
            final JPanel content);
164
        }
119
}
165
}
(-)a/progress.ui/nbproject/project.xml (-1 / +1 lines)
Lines 11-17 Link Here
11
                    <compile-dependency/>
11
                    <compile-dependency/>
12
                    <run-dependency>
12
                    <run-dependency>
13
                        <release-version>1</release-version>
13
                        <release-version>1</release-version>
14
                        <specification-version>1.19</specification-version>
14
                        <specification-version>1.28</specification-version>
15
                    </run-dependency>
15
                    </run-dependency>
16
                </dependency>
16
                </dependency>
17
                <dependency>
17
                <dependency>
(-)a/progress.ui/src/org/netbeans/modules/progress/ui/RunOffEDTImpl.java (-17 / +182 lines)
Lines 41-53 Link Here
41
 */
41
 */
42
package org.netbeans.modules.progress.ui;
42
package org.netbeans.modules.progress.ui;
43
43
44
import java.awt.Color;
44
import java.awt.*;
45
import java.awt.Component;
46
import java.awt.Cursor;
47
import java.awt.Dialog;
48
import java.awt.EventQueue;
49
import java.awt.Graphics;
50
import java.awt.Graphics2D;
51
import java.awt.event.ActionEvent;
45
import java.awt.event.ActionEvent;
52
import java.awt.event.ActionListener;
46
import java.awt.event.ActionListener;
53
import java.util.HashMap;
47
import java.util.HashMap;
Lines 63-86 Link Here
63
import java.util.concurrent.atomic.AtomicReference;
57
import java.util.concurrent.atomic.AtomicReference;
64
import java.util.logging.Level;
58
import java.util.logging.Level;
65
import java.util.logging.Logger;
59
import java.util.logging.Logger;
66
import javax.swing.JComponent;
60
import javax.swing.*;
67
import javax.swing.JFrame;
68
import javax.swing.SwingUtilities;
69
import javax.swing.UIManager;
70
import org.netbeans.api.progress.ProgressHandle;
61
import org.netbeans.api.progress.ProgressHandle;
71
import org.netbeans.api.progress.ProgressHandleFactory;
62
import org.netbeans.api.progress.ProgressHandleFactory;
72
import org.netbeans.api.progress.ProgressRunnable;
63
import org.netbeans.api.progress.ProgressRunnable;
73
import org.netbeans.api.progress.ProgressUtils;
64
import org.netbeans.api.progress.ProgressUtils;
74
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
65
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
75
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress;
66
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress;
67
import org.netbeans.modules.progress.spi.RunOffEDTProvider.JdevProgressExt;
76
import org.openide.DialogDescriptor;
68
import org.openide.DialogDescriptor;
77
import org.openide.DialogDisplayer;
69
import org.openide.DialogDisplayer;
78
import org.openide.NotifyDescriptor;
70
import org.openide.NotifyDescriptor;
79
import org.openide.util.Cancellable;
71
import org.openide.util.*;
80
import org.openide.util.Exceptions;
81
import org.openide.util.NbBundle;
82
import org.openide.util.Parameters;
83
import org.openide.util.RequestProcessor;
84
import org.openide.util.RequestProcessor.Task;
72
import org.openide.util.RequestProcessor.Task;
85
import org.openide.util.lookup.ServiceProvider;
73
import org.openide.util.lookup.ServiceProvider;
86
import org.openide.windows.WindowManager;
74
import org.openide.windows.WindowManager;
Lines 90-98 Link Here
90
 * @author Jan Lahoda, Tomas Holy
78
 * @author Jan Lahoda, Tomas Holy
91
 */
79
 */
92
@ServiceProvider(service=RunOffEDTProvider.class, position = 100)
80
@ServiceProvider(service=RunOffEDTProvider.class, position = 100)
93
public class RunOffEDTImpl implements RunOffEDTProvider, Progress {
81
public class RunOffEDTImpl implements RunOffEDTProvider, Progress, JdevProgressExt {
94
82
95
    private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
83
    private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
84
    private static final RequestProcessor TI_WORKER = new RequestProcessor("TI_" + ProgressUtils.class.getName(), 1, true);
85
    
96
    private static final Map<String, Long> CUMULATIVE_SPENT_TIME = new HashMap<String, Long>();
86
    private static final Map<String, Long> CUMULATIVE_SPENT_TIME = new HashMap<String, Long>();
97
    private static final Map<String, Long> MAXIMAL_SPENT_TIME = new HashMap<String, Long>();
87
    private static final Map<String, Long> MAXIMAL_SPENT_TIME = new HashMap<String, Long>();
98
    private static final Map<String, Integer> INVOCATION_COUNT = new HashMap<String, Integer>();
88
    private static final Map<String, Integer> INVOCATION_COUNT = new HashMap<String, Integer>();
Lines 212-218 Link Here
212
            }
202
            }
213
        }
203
        }
214
    }
204
    }
205
    
206
    @Override
207
    public void runOffEventThreadWithCustomDialogContent(Runnable operation, String dialogTitle, JPanel content) {
208
        runOffEventThreadCustomDialogImpl(operation, dialogTitle, content);
209
    }
215
210
211
    @Override
212
    public void runOffEventThreadWithProgressDialog(final Runnable operation, final String operationDescr,
213
            ProgressHandle handle, boolean includeDetailLabel) {
214
        JPanel content = contentPanel(handle, includeDetailLabel);
215
        runOffEventThreadCustomDialogImpl(operation, operationDescr, content);
216
    }
217
    
218
    private void runOffEventThreadCustomDialogImpl(final Runnable operation, final String operationDescr,
219
            final JPanel contentPanel) {
220
        final int WAIT_CURSOR_TIME = 1000;
221
        final int DIALOG_TIME = 2000;
222
        
223
        final CountDownLatch latch = new CountDownLatch(1);
224
        final AtomicReference<Dialog> d = new AtomicReference<Dialog>();
225
        final AtomicReference<RequestProcessor.Task> t  = new AtomicReference<RequestProcessor.Task>();
226
        
227
        JDialog dialog = createModalDialog(operation, operationDescr, contentPanel, d, t, operation instanceof Cancellable);
228
229
        final Task rt = TI_WORKER.post(new Runnable() {
230
231
            public @Override void run() {
232
		try {
233
		    operation.run();
234
		} finally {
235
		    latch.countDown();
236
237
		    SwingUtilities.invokeLater(new Runnable() {
238
239
			public @Override void run() {
240
			    Dialog dd = d.get();
241
			    if (dd != null) {
242
				dd.setVisible(false);
243
			    }
244
			}
245
		    });
246
		}
247
            }
248
        });
249
        t.set(rt);
250
251
        Component glassPane = ((JFrame) WindowManager.getDefault().getMainWindow()).getGlassPane();
252
253
        if (waitMomentarily(glassPane, null, WAIT_CURSOR_TIME, latch)) {
254
            return;
255
        }
256
257
        Cursor wait = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
258
259
        if (waitMomentarily(glassPane, wait, DIALOG_TIME, latch)) {
260
            return;
261
        }
262
263
        d.set(dialog);
264
        if (EventQueue.isDispatchThread()) {
265
            EventQueue.invokeLater(new Runnable() {
266
                @Override
267
                public void run() {
268
                    d.get().setVisible(true);
269
                }
270
            });
271
        } else {
272
            d.get().setVisible(true);
273
        }
274
    }
275
    
216
    private static boolean waitMomentarily(Component glassPane, Cursor wait, int timeout, final CountDownLatch l) {
276
    private static boolean waitMomentarily(Component glassPane, Cursor wait, int timeout, final CountDownLatch l) {
217
        Cursor original = glassPane.getCursor();
277
        Cursor original = glassPane.getCursor();
218
278
Lines 405-408 Link Here
405
        }
465
        }
406
466
407
    }
467
    }
468
469
    private static JPanel contentPanel(final ProgressHandle handle, boolean includeDetail) {
470
        // top panel
471
        JPanel contentPanel = new JPanel(new GridBagLayout());
472
        
473
        // main label
474
        GridBagConstraints gridBagConstraints = new GridBagConstraints();
475
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 0);
476
        gridBagConstraints.gridx = 0;
477
        gridBagConstraints.gridy = 0;
478
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
479
        
480
        JLabel mainLabel = ProgressHandleFactory.createMainLabelComponent(handle);
481
        Font f = mainLabel.getFont();
482
        if (f != null) {
483
            mainLabel.setFont(f.deriveFont(Font.BOLD));
484
        }
485
        contentPanel.add(mainLabel, gridBagConstraints);
486
        
487
        // progress bar
488
        gridBagConstraints = new java.awt.GridBagConstraints();
489
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 0);
490
        gridBagConstraints.gridx = 0;
491
        gridBagConstraints.gridy = 1;
492
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
493
        JComponent progressBar = ProgressHandleFactory.createProgressComponent(handle);
494
        contentPanel.add (progressBar, gridBagConstraints);
495
        
496
        if (includeDetail) {
497
            gridBagConstraints = new java.awt.GridBagConstraints();
498
            gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 0);
499
            gridBagConstraints.gridx = 0;
500
            gridBagConstraints.gridy = 2;
501
            gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
502
            JLabel details = ProgressHandleFactory.createDetailLabelComponent(handle);
503
            contentPanel.add(details, gridBagConstraints);
504
        }
505
        
506
        // empty panel - for correct resizing
507
        JPanel emptyPanel = new JPanel();
508
        gridBagConstraints = new java.awt.GridBagConstraints();
509
        gridBagConstraints.gridx = 0;
510
        gridBagConstraints.gridy = includeDetail ? 3 : 2;
511
        gridBagConstraints.weighty = 2.0;
512
        gridBagConstraints.weightx = 2.0;
513
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
514
        contentPanel.add(emptyPanel, gridBagConstraints);
515
        
516
        return contentPanel;
517
    }
518
    
519
    private static JDialog createModalDialog(
520
            final Runnable operation,
521
            final String title,
522
            final JPanel content,
523
            final AtomicReference<Dialog> d,
524
            final AtomicReference<RequestProcessor.Task> task,
525
            final boolean cancelAvail) 
526
    {
527
        assert EventQueue.isDispatchThread();
528
        
529
        JPanel panel = new JPanel(new GridBagLayout());
530
        
531
        GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
532
        gridBagConstraints.gridx = 0;
533
        gridBagConstraints.gridy = 0;
534
        gridBagConstraints.weightx = 1.0;
535
        gridBagConstraints.weighty = 1.0;
536
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
537
        
538
        panel.add(content, gridBagConstraints);
539
        
540
        if (cancelAvail) {
541
            JPanel buttonsPanel = new JPanel();
542
            buttonsPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
543
            String cancelButton = NbBundle.getMessage(RunOffEDTImpl.class, "RunOffAWT.BTN_Cancel"); //NOI18N
544
            JButton cancel = new JButton(cancelButton);
545
            cancel.addActionListener(new ActionListener() {
546
547
                @Override
548
                public void actionPerformed(ActionEvent e) {
549
                    if (operation instanceof Cancellable) {
550
                        ((Cancellable) operation).cancel();
551
                        task.get().cancel();
552
                        d.get().setVisible(false);
553
                    }
554
                }
555
            });
556
            buttonsPanel.add(cancel);
557
            gridBagConstraints = new java.awt.GridBagConstraints();
558
            gridBagConstraints.gridx = 0;
559
            gridBagConstraints.gridy = 1;
560
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
561
            gridBagConstraints.weightx = 1.0;
562
            panel.add(buttonsPanel, gridBagConstraints);
563
        }
564
        
565
        Frame mainWindow = WindowManager.getDefault().getMainWindow();
566
        final JDialog result = new JDialog(mainWindow, title, true);
567
        result.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
568
        result.setSize(400, 150);
569
        result.setContentPane(panel);
570
        result.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
571
        return result;
572
    }
408
}
573
}

Return to bug 204553