diff --git a/api.progress/apichanges.xml b/api.progress/apichanges.xml
--- a/api.progress/apichanges.xml
+++ b/api.progress/apichanges.xml
@@ -106,6 +106,30 @@
+
+ SPI added
+
+
+
+
+
+
+ Added methods to ProgressUtils for invoking a runnable or
+ similar with
+ a modal dialog blocking the UI and showing progress:
+
+ public static void showProgressDialogAndRun(Runnable operation, String displayName)
+ public static T showProgressDialogAndRun(final ProgressRunnable operation, final String displayName, boolean includeDetailLabel)
+ public static void showProgressDialogAndRun(Runnable operation, ProgressHandle progress, boolean includeDetailLabel
+
+ Added interface ProgressRunnable for performing background
+ work, and an SPI class ProgressRunOffEdtProvider which is
+ implemented by the Progress UI module.
+
+
+
+
+
SPI added
diff --git a/api.progress/manifest.mf b/api.progress/manifest.mf
--- a/api.progress/manifest.mf
+++ b/api.progress/manifest.mf
@@ -3,5 +3,5 @@
OpenIDE-Module-Localizing-Bundle: org/netbeans/progress/module/resources/Bundle.properties
OpenIDE-Module-Recommends: org.netbeans.modules.progress.spi.ProgressUIWorkerProvider, org.netbeans.modules.progress.spi.RunOffEDTProvider
AutoUpdate-Essential-Module: true
-OpenIDE-Module-Specification-Version: 1.18
+OpenIDE-Module-Specification-Version: 1.19
diff --git a/api.progress/src/org/netbeans/api/progress/ProgressHandle.java b/api.progress/src/org/netbeans/api/progress/ProgressHandle.java
--- a/api.progress/src/org/netbeans/api/progress/ProgressHandle.java
+++ b/api.progress/src/org/netbeans/api/progress/ProgressHandle.java
@@ -197,6 +197,12 @@
LOG.fine(newDisplayName);
internal.requestDisplayNameChange(newDisplayName);
}
+
+ String getDisplayName() {
+ synchronized (internal) {
+ return internal.getDisplayName();
+ }
+ }
/**
* have the component in custom location, don't include in the status bar.
diff --git a/api.progress/src/org/netbeans/api/progress/ProgressRunnable.java b/api.progress/src/org/netbeans/api/progress/ProgressRunnable.java
new file mode 100644
--- /dev/null
+++ b/api.progress/src/org/netbeans/api/progress/ProgressRunnable.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.progress;
+
+/**
+ * Callable used by ProgressUtils.showProgressDialogAndRun to do background
+ * work while a modal progress dialog is shown blocking all application windows.
+ *
+ * @author Tim Boudreau
+ */
+public interface ProgressRunnable {
+ /**
+ * Perform the background work
+ * @param handle A progress handle to post background work progress from.
+ * The handle, when passed in, has had start() and setToIndeterminate() called.
+ * @return The result of the background computation
+ */
+ public T run(ProgressHandle handle);
+}
diff --git a/api.progress/src/org/netbeans/api/progress/ProgressUtils.java b/api.progress/src/org/netbeans/api/progress/ProgressUtils.java
--- a/api.progress/src/org/netbeans/api/progress/ProgressUtils.java
+++ b/api.progress/src/org/netbeans/api/progress/ProgressUtils.java
@@ -40,7 +40,9 @@
package org.netbeans.api.progress;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import javax.swing.SwingUtilities;
+import org.netbeans.modules.progress.spi.ProgressRunOffEdtProvider;
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
import org.openide.util.Lookup;
import org.openide.util.RequestProcessor;
@@ -100,6 +102,100 @@
PROVIDER.runOffEventDispatchThread(operation, operationDescr, cancelOperation, waitForCanceled, waitCursorAfter, dialogAfter);
}
+ /**
+ * Show a modal progress dialog that blocks the main window, while running
+ * the passed runnable on a background thread.
+ *
+ * This method is thread-safe, and will block until the operation has
+ * completed, regardless of what thread calls this method.
+ *
+ * Unless you are being passed the runnable or progress handle from foreign
+ * code (such as in WizardDescriptor.progressInstantiatingIterator), it
+ * is usually simpler to use the version of this method that takes a
+ * ProgressCallable
.
+ *
+ * @param operation A runnable to run in the background
+ * @param progress A progress handle to create a progress bar for
+ * @param includeDetailLabel True if the caller will use
+ * ProgressHandle.progress (String, int), false if not. If true, the
+ * created dialog will include a label that shows progress details.
+ */
+ public static void showProgressDialogAndRun(Runnable operation, ProgressHandle progress, boolean includeDetailLabel) {
+ if (PROVIDER instanceof ProgressRunOffEdtProvider) {
+ ProgressRunOffEdtProvider p = (ProgressRunOffEdtProvider) PROVIDER;
+ p.showProgressDialogAndRun(operation, progress, includeDetailLabel);
+ } else {
+ PROVIDER.runOffEventDispatchThread(operation, progress.getDisplayName(), new AtomicBoolean(false), false, 0, 0);
+ }
+ }
+
+ /**
+ * Show a modal progress dialog that blocks the main window, while running
+ * the passed runnable on a background thread.
+ *
+ * This method is thread-safe, and will block until the operation has
+ * completed, regardless of what thread calls this method.
+ *
+ * @param The result type - use Void if no return type needed
+ * @param operation A runnable-like object which performs work in the
+ * background, and is passed a ProgressHandle to update progress
+ * @param displayName The display name for this operation
+ * @param includeDetailLabel If true, include a lable to show progress
+ * details (needed only if you plan to call ProgressHandle.setProgress(String, int)
+ * @return The result of the operation.
+ */
+ public static T showProgressDialogAndRun(final ProgressRunnable operation, final String displayName, boolean includeDetailLabel) {
+ if (PROVIDER instanceof ProgressRunOffEdtProvider) {
+ ProgressRunOffEdtProvider p = (ProgressRunOffEdtProvider) PROVIDER;
+ return p.showProgressDialogAndRun(operation, displayName, includeDetailLabel);
+ } else {
+ final AtomicReference ref = new AtomicReference();
+ PROVIDER.runOffEventDispatchThread(new Runnable() {
+ @Override
+ public void run() {
+ ProgressHandle handle = ProgressHandleFactory.createHandle(displayName);
+ handle.start();
+ handle.switchToIndeterminate();
+ try {
+ ref.set(operation.run(handle));
+ } finally {
+ handle.finish();
+ }
+ }
+ }, displayName, new AtomicBoolean(false), true, 0, 0);
+ return ref.get();
+ }
+ }
+
+ /**
+ * Show a modal progress dialog that blocks the main window, while running
+ * the passed runnable on a background thread with an indeterminate-state
+ * progress bar.
+ *
+ * This method is thread-safe, and will block until the operation has
+ * completed, regardless of what thread calls this method.
+ * .
+ * @param operation A runnable to run
+ * @param displayName The display name of the operation, to show in the dialog
+ */
+ public static void showProgressDialogAndRun(Runnable operation, String displayName) {
+ showProgressDialogAndRun(new RunnableWrapper(operation), displayName, false);
+ }
+
+
+ private static final class RunnableWrapper implements ProgressRunnable {
+ private final Runnable toRun;
+ RunnableWrapper(Runnable toRun) {
+ this.toRun = toRun;
+ }
+
+ @Override
+ public Void run(ProgressHandle handle) {
+ toRun.run();
+ return null;
+ }
+ }
+
private static class Trivial implements RunOffEDTProvider {
private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
diff --git a/api.progress/src/org/netbeans/modules/progress/spi/ProgressRunOffEdtProvider.java b/api.progress/src/org/netbeans/modules/progress/spi/ProgressRunOffEdtProvider.java
new file mode 100644
--- /dev/null
+++ b/api.progress/src/org/netbeans/modules/progress/spi/ProgressRunOffEdtProvider.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.progress.spi;
+
+import org.netbeans.api.progress.ProgressRunnable;
+import org.netbeans.api.progress.ProgressHandle;
+
+/**
+ * Extension to RunOffEDTProvider which allows for a modal dialog to
+ * be shown which contains a progress bar.
+ *
+ * @author Tim Boudreau
+ */
+public interface ProgressRunOffEdtProvider extends RunOffEDTProvider{
+ /**
+ * Show a modal progress dialog that blocks the main window while running
+ * a background process. This call should block until the work is
+ * completed.
+ *
+ * @param operation A runnable that needs to be run with the UI blocked
+ * @param handle A progress handle that will be updated to reflect
+ * the progress of the operation
+ * @param showDetails If true, a label should be provided in the progress
+ * dialog to show detailed progress messages
+ */
+ void showProgressDialogAndRun(Runnable operation, ProgressHandle handle, boolean showDetails);
+ /**
+ * Show a modal progress dialog that blocks the main window while running
+ * a background process. This call should block until the work is
+ * completed.
+ *
+ * @param The type of the return value
+ * @param toRun A ProgressCallable which will be passed a progress handle
+ * on a background thread, can do its work and (optionally) return a value
+ * @param displayName The display name of the work being done
+ * @param includeDetailLabel Show the detail levels. Set to true if the
+ * caller will use ProgressHandle.progress (String, int) to provide
+ * detailed progress messages
+ * @return The result of the call to ProgressRunnable.call()
+ */
+ T showProgressDialogAndRun(ProgressRunnable toRun, String displayName, boolean includeDetailLabel);
+}
diff --git a/progress.ui/manifest.mf b/progress.ui/manifest.mf
--- a/progress.ui/manifest.mf
+++ b/progress.ui/manifest.mf
@@ -4,5 +4,5 @@
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/progress/ui/Bundle.properties
OpenIDE-Module-Provides: org.netbeans.modules.progress.spi.ProgressUIWorkerProvider, org.netbeans.modules.progress.spi.RunOffEDTProvider
AutoUpdate-Essential-Module: true
-OpenIDE-Module-Specification-Version: 1.8
+OpenIDE-Module-Specification-Version: 1.9
diff --git a/progress.ui/nbproject/project.xml b/progress.ui/nbproject/project.xml
--- a/progress.ui/nbproject/project.xml
+++ b/progress.ui/nbproject/project.xml
@@ -11,7 +11,7 @@
1
- 1.18
+ 1.19
@@ -54,6 +54,10 @@
org.netbeans.libs.junit4
+
+ org.netbeans.modules.nbjunit
+
+
diff --git a/progress.ui/src/org/netbeans/modules/progress/ui/RunOffEDTImpl.java b/progress.ui/src/org/netbeans/modules/progress/ui/RunOffEDTImpl.java
--- a/progress.ui/src/org/netbeans/modules/progress/ui/RunOffEDTImpl.java
+++ b/progress.ui/src/org/netbeans/modules/progress/ui/RunOffEDTImpl.java
@@ -38,11 +38,24 @@
*/
package org.netbeans.modules.progress.ui;
+import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridLayout;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
@@ -51,24 +64,36 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+import org.netbeans.api.progress.ProgressRunnable;
+import org.netbeans.api.progress.ProgressHandle;
+import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.api.progress.ProgressUtils;
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
+import org.netbeans.modules.progress.spi.ProgressRunOffEdtProvider;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.openide.util.RequestProcessor;
+import org.openide.util.Utilities;
import org.openide.windows.WindowManager;
/**
* Default RunOffEDTProvider implementation for ProgressUtils.runOffEventDispatchThread() methods
- * @author Jan Lahoda, Tomas Holy
+ * @author Jan Lahoda, Tomas Holy, Tim Boudreau
*/
@org.openide.util.lookup.ServiceProvider(service = org.netbeans.modules.progress.spi.RunOffEDTProvider.class, position = 100)
-public class RunOffEDTImpl implements RunOffEDTProvider {
+public class RunOffEDTImpl implements RunOffEDTProvider, ProgressRunOffEdtProvider {
private static final RequestProcessor WORKER = new RequestProcessor(ProgressUtils.class.getName());
private static final Map, Integer> OPERATIONS = new WeakHashMap, Integer>();
@@ -190,4 +215,239 @@
glassPane.setCursor(original);
}
}
+
+ @Override
+ public void showProgressDialogAndRun(Runnable operation, ProgressHandle handle, boolean includeDetailLabel) {
+ AbstractWindowRunner wr = new RunnableWindowRunner(operation, handle, includeDetailLabel);
+ wr.start();
+ if (!EventQueue.isDispatchThread()) {
+ try {
+ wr.await();
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+
+ @Override
+ public T showProgressDialogAndRun(ProgressRunnable toRun, String displayName, boolean includeDetailLabel) {
+ AbstractWindowRunner wr = new ProgressBackgroundRunner(toRun, displayName, includeDetailLabel);
+ wr.start();
+ if (!EventQueue.isDispatchThread()) {
+ try {
+ wr.await();
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return wr.getResult();
+ }
+
+ private static abstract class AbstractWindowRunner extends WindowAdapter implements Runnable {
+ private volatile JDialog dlg;
+ private final boolean includeDetail;
+ protected final ProgressHandle handle;
+ private final CountDownLatch latch = new CountDownLatch(1);
+ private volatile T operationResult;
+
+ AbstractWindowRunner(ProgressHandle handle, boolean includeDetail) {
+ this.includeDetail = includeDetail;
+ this.handle = handle;
+ }
+
+ @Override
+ public final void windowOpened(WindowEvent e) {
+ dlg = (JDialog) e.getSource();
+ RequestProcessor.getDefault().post(this);
+ grayOutMainWindow();
+ }
+
+ @Override
+ public final void windowClosed(WindowEvent e) {
+ ungrayMainWindow();
+ latch.countDown();
+ }
+
+ final void await() throws InterruptedException {
+ latch.await();
+ }
+
+ final void start() {
+ if (EventQueue.isDispatchThread()) {
+ createModalProgressDialog(handle, includeDetail);
+ } else {
+ CountDownLatch dlgLatch = new CountDownLatch(1);
+ DialogCreator dc = new DialogCreator(dlgLatch);
+ EventQueue.invokeLater (dc);
+ try {
+ dlgLatch.await();
+ } catch (InterruptedException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+
+ protected abstract T runBackground();
+
+ T getResult() {
+ return operationResult;
+ }
+
+ @Override
+ public void run() {
+ if (!EventQueue.isDispatchThread()) {
+ try {
+ operationResult = runBackground();
+ } finally {
+ EventQueue.invokeLater(this);
+ }
+ } else {
+ dlg.setVisible(false);
+ dlg.dispose();
+ }
+ }
+
+ private final class DialogCreator implements Runnable {
+ private final CountDownLatch latch;
+ DialogCreator (CountDownLatch latch) {
+ this.latch = latch;
+ }
+
+ @Override
+ public void run() {
+ createModalProgressDialog(handle, includeDetail);
+ latch.countDown();
+ }
+ }
+
+ private JDialog createModalProgressDialog(ProgressHandle handle, boolean includeDetail) {
+ assert EventQueue.isDispatchThread();
+ int edgeGap = Utilities.isMac() ? 12 : 8;
+ int compGap = Utilities.isMac() ? 9 : 5;
+ JPanel panel = new JPanel(new GridLayout(includeDetail ? 3 : 2, 1, compGap, compGap));
+ JLabel mainLabel = ProgressHandleFactory.createMainLabelComponent(handle);
+ Font f = mainLabel.getFont();
+ if (f != null) {
+ mainLabel.setFont (f.deriveFont(Font.BOLD));
+ }
+ panel.add(mainLabel);
+
+ JComponent progressBar = ProgressHandleFactory.createProgressComponent(handle);
+ progressBar.setMinimumSize(new Dimension (400, 32));
+ panel.add(progressBar);
+
+ if (includeDetail) {
+ JLabel details = ProgressHandleFactory.createDetailLabelComponent(handle);
+ details.setMinimumSize(new Dimension(300, 16));
+ panel.add(details);
+ }
+ panel.setBorder (BorderFactory.createCompoundBorder(
+ BorderFactory.createRaisedBevelBorder(),
+ BorderFactory.createEmptyBorder(edgeGap, edgeGap, edgeGap, edgeGap)));
+ panel.setMinimumSize(new Dimension(400, 100));
+ Frame mainWindow = WindowManager.getDefault().getMainWindow();
+ JDialog result = new JDialog(mainWindow, true);
+ result.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ result.setUndecorated(true);
+ result.setSize(400, 100);
+ result.getContentPane().setLayout(new BorderLayout());
+ result.getContentPane().add(panel, BorderLayout.CENTER);
+ result.pack();
+ int reqWidth = result.getWidth();
+ result.setSize(Math.max (reqWidth,
+ mainWindow instanceof JFrame ?
+ ((JFrame) mainWindow).getContentPane().getWidth() / 3 :
+ mainWindow.getWidth()), result.getHeight());
+ result.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
+ result.addWindowListener(this);
+ result.setVisible(true);
+ return result;
+ }
+
+ private Component oldGlassPane;
+ private void grayOutMainWindow() {
+ assert EventQueue.isDispatchThread();
+ Frame f = WindowManager.getDefault().getMainWindow();
+ if (f instanceof JFrame) {
+ Map,?> hintsMap = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); //NOI18N
+ //Avoid translucent painting on, for example, remote X terminal
+ if (hintsMap == null || !RenderingHints.VALUE_TEXT_ANTIALIAS_OFF.equals(hintsMap.get(RenderingHints.KEY_TEXT_ANTIALIASING))) {
+ JFrame jf = (JFrame) f;
+ TranslucentMask mask = new TranslucentMask();
+ oldGlassPane = jf.getGlassPane();
+ jf.setGlassPane(mask);
+ mask.setVisible(true);
+ mask.setBounds (0, 0, jf.getContentPane().getWidth(), jf.getContentPane().getHeight());
+ mask.invalidate();
+ mask.revalidate();
+ mask.repaint();
+ jf.getRootPane().paintImmediately(0, 0, jf.getRootPane().getWidth(), jf.getRootPane().getHeight());
+ }
+ }
+ }
+
+ private void ungrayMainWindow() {
+ if (oldGlassPane != null) {
+ JFrame jf = (JFrame) WindowManager.getDefault().getMainWindow();
+ jf.setGlassPane(oldGlassPane);
+ jf.invalidate();
+ jf.repaint();
+ }
+ }
+ }
+
+ static final class TranslucentMask extends JComponent { //pkg private for tests
+ TranslucentMask() {
+ setVisible(false); //so we will trigger a property change
+ }
+
+ @Override
+ public boolean isOpaque() {
+ return false;
+ }
+
+ @Override
+ public void paint (Graphics g) {
+ Graphics2D g2d = (Graphics2D) g;
+ Color translu = new Color (180, 180, 180, 148);
+ g2d.setColor(translu);
+ g2d.fillRect (0, 0, getWidth(), getHeight());
+ }
+ }
+
+ private static final class ProgressBackgroundRunner extends AbstractWindowRunner {
+ private final ProgressRunnable toRun;
+ public ProgressBackgroundRunner(ProgressRunnable toRun, String displayName, boolean includeDetail) {
+ super (ProgressHandleFactory.createHandle(displayName), includeDetail);
+ this.toRun = toRun;
+ }
+
+ @Override
+ protected T runBackground() {
+ handle.start();
+ handle.switchToIndeterminate();
+ T result;
+ try {
+ result = toRun.run(handle);
+ } finally {
+ handle.finish();
+ }
+ return result;
+ }
+ }
+
+ private static final class RunnableWindowRunner extends AbstractWindowRunner {
+ private Runnable toRun;
+ public RunnableWindowRunner(Runnable toRun, ProgressHandle progress, boolean includeDetail) {
+ super (progress, includeDetail);
+ this.toRun = toRun;
+ }
+
+ @Override
+ protected Void runBackground() {
+ toRun.run();
+ return null;
+ }
+ }
+
}
diff --git a/progress.ui/test/unit/src/org/netbeans/modules/progress/ui/RunOffEDTImplTest.java b/progress.ui/test/unit/src/org/netbeans/modules/progress/ui/RunOffEDTImplTest.java
new file mode 100644
--- /dev/null
+++ b/progress.ui/test/unit/src/org/netbeans/modules/progress/ui/RunOffEDTImplTest.java
@@ -0,0 +1,310 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2010 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.progress.ui;
+
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.Toolkit;
+import java.beans.PropertyChangeListener;
+import java.util.Map;
+import java.util.Set;
+import javax.swing.Action;
+import javax.swing.JFrame;
+import org.netbeans.api.progress.ProgressHandle;
+import org.openide.nodes.Node;
+import org.openide.util.Exceptions;
+import org.openide.windows.Mode;
+import org.openide.windows.TopComponent;
+import org.openide.windows.TopComponentGroup;
+import org.openide.windows.WindowManager;
+import org.junit.After;
+import static org.junit.Assert.*;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.netbeans.api.progress.ProgressRunnable;
+import org.netbeans.api.progress.ProgressUtils;
+import org.netbeans.junit.MockServices;
+import org.openide.windows.Workspace;
+
+/**
+ *
+ * @author Tim Boudreau
+ */
+public class RunOffEDTImplTest {
+
+ public RunOffEDTImplTest() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() {
+ MockServices.setServices(WM.class, RunOffEDTImpl.class);
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ private static boolean canTestGlassPane() {
+ Map,?> hintsMap = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); //NOI18N
+ //Avoid translucent painting on, for example, remote X terminal
+ return hintsMap == null || !RenderingHints.VALUE_TEXT_ANTIALIAS_OFF.equals(hintsMap.get(RenderingHints.KEY_TEXT_ANTIALIASING));
+ }
+
+ @Test
+ public void testShowProgressDialogAndRun_3args_1_EQ() throws Exception {
+ EventQueue.invokeAndWait(new Runnable() {
+
+ @Override
+ public void run() {
+ testShowProgressDialogAndRun_3args_1();
+ }
+ });
+ }
+
+ @Test
+ public void testShowProgressDialogAndRun_3args_2_EQ() throws Exception {
+ EventQueue.invokeAndWait(new Runnable() {
+
+ @Override
+ public void run() {
+ testShowProgressDialogAndRun_3args_2();
+ }
+ });
+ }
+
+ @Test
+ public void testShowProgressDialogAndRun_3args_1() {
+ assertEquals ("Done", ProgressUtils.showProgressDialogAndRun(new CB(), "Doing Stuff", true));
+ }
+
+ @Test
+ public void testShowProgressDialogAndRun_3args_2() {
+ final JFrame jf = (JFrame) WindowManager.getDefault().getMainWindow();
+ class R implements Runnable {
+ boolean hasRun;
+ public void run() {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ if (canTestGlassPane()) {
+ assertTrue (jf.getGlassPane() instanceof RunOffEDTImpl.TranslucentMask);
+ }
+ hasRun = true;
+ }
+ };
+ R r = new R();
+ ProgressUtils.showProgressDialogAndRun(r, "Something");
+ assertTrue (r.hasRun);
+ }
+
+ private class CB implements ProgressRunnable {
+
+ @Override
+ public String run(ProgressHandle handle) {
+ handle.switchToDeterminate(5);
+ for (int i= 0; i < 5; i++) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ handle.progress("Job " + i, i);
+ }
+ return "Done";
+ }
+
+ }
+
+ public static final class WM extends WindowManager {
+ private final JFrame jf = new JFrame ("Main Window");
+ public WM() {
+ jf.setVisible(true);
+ }
+
+ @Override
+ public Mode findMode(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Mode findMode(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Set extends Mode> getModes() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Frame getMainWindow() {
+ return jf;
+ }
+
+ @Override
+ public void updateUI() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected Component createTopComponentManager(TopComponent c) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Workspace createWorkspace(String name, String displayName) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Workspace findWorkspace(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Workspace[] getWorkspaces() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void setWorkspaces(Workspace[] workspaces) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Workspace getCurrentWorkspace() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public TopComponentGroup findTopComponentGroup(String name) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentOpen(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentClose(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentRequestActive(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentRequestVisible(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentDisplayNameChanged(TopComponent tc, String displayName) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentHtmlDisplayNameChanged(TopComponent tc, String htmlDisplayName) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentToolTipChanged(TopComponent tc, String toolTip) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentIconChanged(TopComponent tc, Image icon) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected void topComponentActivatedNodesChanged(TopComponent tc, Node[] activatedNodes) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected boolean topComponentIsOpened(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected Action[] topComponentDefaultActions(TopComponent tc) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ protected String topComponentID(TopComponent tc, String preferredID) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public TopComponent findTopComponent(String tcID) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+}