All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.api.progress.BaseProgressUtils Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.api.progress;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.netbeans.modules.progress.spi.RunOffEDTProvider;
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress;
import org.netbeans.modules.progress.spi.RunOffEDTProvider.Progress2;
import org.openide.util.Cancellable;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
import org.openide.util.RequestProcessor;

/**
 * Contains useful utilities that can function in a non-Swing environment. For
 * Swing-related utilities (which use e.g. JComponent and Swing Actions), use
 * org.netbeans.api.progress.ProgressUtils from the api.progress.nb module.
 * 
 * @author Tomas Holy
 * @since 1.40
 */
public final class BaseProgressUtils {
    private static final RunOffEDTProvider PROVIDER = getProvider();
    private static final int DISPLAY_DIALOG_MS = 9450;
    private static final int DISPLAY_WAIT_CURSOR_MS = 50;

    private BaseProgressUtils() {
    }

    private static RunOffEDTProvider getProvider() {
        RunOffEDTProvider p = Lookup.getDefault().lookup(RunOffEDTProvider.class);
        return p != null ? p : new Trivial();
    }

    /**
     * Runs operation out of event dispatch thread, blocks UI while operation is in progress. First it shows
     * wait cursor after ~50ms elapses, if operation takes longer than ~10s a dialog with Cancel button is shown.
     * 

* This method is supposed to be used by user invoked foreground actions, that are expected to run very fast in vast majority of cases. * However, in some rather rare cases (e.g. extensive IO operations in progress), supplied operation may need longer time. In such case * this method first displays wait cursor and if operation takes even more time it displays dialog allowing to cancel operation. * DO NOT use this method for operations that may take long time under normal circumstances! * @param operation operation to perform * @param operationDescr text shown in dialog * @param cancelOperation set to true if user canceled the operation * @param waitForCanceled true if method should wait until canceled task is finished (if it is not finished in 1s ISE is thrown) */ public static void runOffEventDispatchThread(Runnable operation, String operationDescr, AtomicBoolean cancelOperation, boolean waitForCanceled) { PROVIDER.runOffEventDispatchThread(operation, operationDescr, cancelOperation, waitForCanceled, DISPLAY_WAIT_CURSOR_MS, DISPLAY_DIALOG_MS); } /** * Runs operation out of event dispatch thread, blocks UI while operation is in progress. First it shows * wait cursor after waitCursorAfter elapses, if operation takes longer than dialogAfter a dialog with Cancel button is shown. *

* This method is supposed to be used by user invoked foreground actions, that are expected to run very fast in vast majority of cases. * However, in some rather rare cases (e.g. extensive IO operations in progress), supplied operation may need longer time. In such case * this method first displays wait cursor and if operation takes even more time it displays dialog allowing to cancel operation. * DO NOT use this method for operations that may take long time under normal circumstances! * @param operation operation to perform * @param operationDescr text shown in dialog * @param cancelOperation set to true if user canceled the operation * @param waitForCanceled true if method should wait until canceled task is finished (if it is not finished in 1s ISE is thrown) * @param waitCursorAfter time in ms after which wait cursor is shown * @param dialogAfter time in ms after which dialog with "Cancel" button is shown * @since 1.19 */ public static void runOffEventDispatchThread(Runnable operation, String operationDescr, AtomicBoolean cancelOperation, boolean waitForCanceled, int waitCursorAfter, int dialogAfter) { PROVIDER.runOffEventDispatchThread(operation, operationDescr, cancelOperation, waitForCanceled, waitCursorAfter, dialogAfter); } /** * Show a modal progress dialog that blocks the main window and all other * currently displayed frames or dialogs, 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. *

* The resulting progress UI should show a cancel button if the passed * runnable implements org.openide.util.Cancellable. *

* Unless you are being passed the runnable or progress handle from foreign * code (such as in WizardDescriptor.progressInstantiatingIterator), it * is usually simpler to use {@link #showProgressDialogAndRun(ProgressRunnable, String, boolean)}. * * @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. * @since 1.19 */ public static void showProgressDialogAndRun(Runnable operation, ProgressHandle progress, boolean includeDetailLabel) { if (PROVIDER instanceof Progress) { Progress p = (Progress) PROVIDER; p.showProgressDialogAndRun(operation, progress, includeDetailLabel); } else { PROVIDER.runOffEventDispatchThread(operation, progress.getDisplayName(), new AtomicBoolean(false), false, 0, 0); } } /** * Runs operation out of the event thread, blocking the whole UI. When * operation takes more than 1s, the method first displays wait cursor. * If operation will not end in 3s interval, modal dialog with * progress is shown up. * If operation is marked with {@link org.openide.util.Cancellable} * interface, cancel button is part of dialog and can be used * to interrupt the operation. * * @param operation task to perform in the background * @param dialogTitle dialog title * @param progress progress handle. Do not invoke any methods before * passing to this method. Start/progress/finish it * only in {@code operation} * @param includeDetailLabel show progress detail label in the dialog * @param waitCursorAfter amount of time, in milliseconds, after which wait * cursor is shown * @param dialogAfter amount of time, in milliseconds, after which dialog * is shown * * @since 1.30 */ public static void runOffEventThreadWithProgressDialog( final Runnable operation, final String dialogTitle, final ProgressHandle progress, final boolean includeDetailLabel, int waitCursorAfter, int dialogAfter) { if (PROVIDER instanceof Progress2) { Progress2 p = (Progress2) PROVIDER; p.runOffEventThreadWithProgressDialog(operation, dialogTitle, progress, includeDetailLabel, waitCursorAfter, dialogAfter); } else { PROVIDER.runOffEventDispatchThread(operation, progress.getDisplayName(), new AtomicBoolean(false), true, DISPLAY_WAIT_CURSOR_MS, DISPLAY_DIALOG_MS); } } /** * Show a modal progress dialog that blocks the main window and all other * currently displayed frames or dialogs, 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. *

* The resulting progress UI should show a cancel button if the passed * runnable implements org.openide.util.Cancellable. * * @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. * @since 1.19 */ public static T showProgressDialogAndRun(final ProgressRunnable operation, final String displayName, boolean includeDetailLabel) { if (PROVIDER instanceof Progress) { Progress p = (Progress) PROVIDER; return p.showProgressDialogAndRun(operation, displayName, includeDetailLabel); } else { final AtomicReference ref = new AtomicReference(); PROVIDER.runOffEventDispatchThread(new Runnable() { @Override public void run() { try (ProgressHandle handle = ProgressHandle.createHandle(displayName)) { handle.start(); handle.switchToIndeterminate(); ref.set(operation.run(handle)); } } }, displayName, new AtomicBoolean(false), true, 0, 0); return ref.get(); } } /** * Show a modal progress dialog that blocks the main window and all other * currently displayed frames or dialogs, 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. *

* The resulting progress UI should show a cancel button if the passed * runnable implements org.openide.util.Cancellable. * . * @param operation A runnable to run * @param displayName The display name of the operation, to show in the dialog * @since 1.19 */ public static void showProgressDialogAndRun(Runnable operation, String displayName) { RunnableWrapper wrapper; if (operation instanceof Cancellable) { wrapper = new CancellableRunnableWrapper(operation); } else { wrapper = new RunnableWrapper(operation); } showProgressDialogAndRun(wrapper, displayName, false); } /** * Show a modal progress dialog that blocks the main window and all other * currently displayed frames or dialogs while running a background process. * This call should block until the work is started, and then return a task * which can be monitored for completion or cancellation. This method will * not block while the work is run, only until the progress UI is * initialized. *

* The resulting progress UI should show a cancel button if the passed * runnable implements org.openide.util.Cancellable. * * @param operation * @param handle * @param includeDetailLabel * @return */ public static Future showProgressDialogAndRunLater (final ProgressRunnable operation, final ProgressHandle handle, boolean includeDetailLabel) { if (PROVIDER instanceof Progress) { Progress p = (Progress) PROVIDER; return p.showProgressDialogAndRunLater(operation, handle, includeDetailLabel); } else { FutureTask result = new FutureTask(new Callable() { @Override public T call() throws Exception { return operation.run(handle); } }); PROVIDER.runOffEventDispatchThread(result, handle.getDisplayName(), new AtomicBoolean(false), true, 0, 0); return result; } } private static 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 final RequestProcessor TRIVIAL = new RequestProcessor(Trivial.class); private static final class CancellableRunnableWrapper extends RunnableWrapper implements Cancellable { private final Cancellable cancelable; CancellableRunnableWrapper(Runnable toRun) { super(toRun); this.cancelable = (Cancellable)toRun; } @Override public boolean cancel() { return cancelable.cancel(); } } private static class Trivial implements RunOffEDTProvider { @Override public void runOffEventDispatchThread(Runnable operation, String operationDescr, AtomicBoolean cancelOperation, boolean waitForCanceled, int waitCursorAfter, int dialogAfter) { if (Mutex.EVENT.isReadAccess()) { // PENDING: the EDT should continue to service events. TRIVIAL.post(operation).waitFinished(); } else { operation.run(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy