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.

Bug 165005

Summary: Simple way to show modal progress w/ background runnable
Product: platform Reporter: _ tboudreau <tboudreau>
Component: ProgressAssignee: _ tboudreau <tboudreau>
Status: RESOLVED FIXED    
Severity: blocker CC: anebuzelsky, dsimonek, mkleint, vv159170
Priority: P3 Keywords: API, API_REVIEW_FAST
Version: 6.x   
Hardware: All   
OS: All   
Issue Type: ENHANCEMENT Exception Reporter:
Attachments: Patch to enhance API & implementation as described in previous comment
Patch to Java Card modules to use this API and delete the internal equivalent

Description _ tboudreau 2009-05-12 22:06:00 UTC
I frequently need to block the UI and show progress while running a background task.  This involves a bunch of
complicated code that can easily be abstracted into a static method you just pass a Runnable and ProgressHandle into. 
Would be nice to see this become API either in the progress API or elsewhere:

    public static JDialog createModalProgressDialog(ProgressHandle handle, boolean includeDetail) {
        assert EventQueue.isDispatchThread();
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(ProgressHandleFactory.createMainLabelComponent(handle), BorderLayout.SOUTH);
        panel.add(ProgressHandleFactory.createProgressComponent(handle), BorderLayout.CENTER);
        panel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
        panel.setSize(new Dimension(400, 100));
        panel.setPreferredSize(new Dimension(400, 50));
        JDialog dlg = new JDialog(WindowManager.getDefault().getMainWindow(), true);
        dlg.setSize(400, 100);
        dlg.getContentPane().setLayout(new BorderLayout());
        dlg.getContentPane().add(panel, BorderLayout.CENTER);
        if (includeDetail) {
            dlg.getContentPane().add(ProgressHandleFactory.createDetailLabelComponent(handle));
        }
        dlg.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        dlg.setAlwaysOnTop(true);
        dlg.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
        return dlg;
    }

    public static void showProgressDialogAndRun (final ProgressHandle handle, final Runnable run, boolean includeDetail) {
        final JDialog dlg = createModalProgressDialog(handle, includeDetail);
        class WR extends WindowAdapter implements Runnable {

            public void run() {
                if (!EventQueue.isDispatchThread()) {
                    try {
                        run.run();
                    } finally {
                        EventQueue.invokeLater(this);
                    }
                } else {
                    dlg.setVisible(false);
                    dlg.dispose();
                }
            }

            @Override
            public void windowOpened(WindowEvent e) {
                RequestProcessor.getDefault().post(this);
            }
        }
        WR wr = new WR();
        dlg.addWindowListener(wr);
        dlg.setVisible(true);
    }
Comment 1 _ tboudreau 2010-01-31 16:48:46 UTC
It adds an optional interface, ProgressRunOffEdtProvider, which extends the existing RunOffEDTProvider and adds two methods:

void showProgressDialogAndRun(Runnable operation, ProgressHandle handle, boolean showDetails);
<T> T showProgressDialogAndRun(ProgressRunnable<T> toRun, String displayName, boolean includeDetailLabel);

extends the existing RunOffEDTImpl to implement it, and adds three methods to ProgressUtils:

public static void showProgressDialogAndRun(Runnable operation, ProgressHandle progress, boolean includeDetailLabel)
public static <T> T showProgressDialogAndRun(final ProgressRunnable<T> operation, final String displayName, boolean includeDetailLabel)
public static void showProgressDialogAndRun(Runnable operation, String displayName)

and an interface, ProgressRunnable, which has one method
<T> T run(ProgressHandle handle);

This will replace a number of uses of org.netbeans.modules.javacard.common.GuiUtils in various Java Card modules.  Could also be useful for a number of other operations such as saving project properties, which currently do the same thing with custom code.
Comment 2 _ tboudreau 2010-01-31 16:55:19 UTC
Created attachment 93694 [details]
Patch to enhance API & implementation as described in previous comment

Attaching patch w/ compatible API changes and tests
Comment 3 _ tboudreau 2010-01-31 16:57:12 UTC
BTW, all three added methods to ProgressUtils are thread-safe and will block until the background work has completed, no matter what thread they are called from (w/ tests to check this behavior).
Comment 4 _ tboudreau 2010-01-31 23:25:35 UTC
Created attachment 93697 [details]
Patch to Java Card modules to use this API and delete the internal equivalent
Comment 5 Jaroslav Tulach 2010-02-01 08:31:23 UTC
Y01 Be consistent when referring to EDT. Compare: "RunOffEDTProvider, ProgressRunOffEdtProvider". Possibly rename the new interface to RunOffEDTProvider.Progress

Y02 Missing @since tags on new methods

Y03 javacard modules need updated dependency on api.progress
Comment 6 David Simonek 2010-02-01 09:22:46 UTC
Just one minor comment from me - is making main window gray really needed? I mean, OS like Ubuntu uses graying as signalization that application stopped responding and users may be confused. No strong opinion on this though.
Comment 7 greggwon 2010-02-01 11:07:16 UTC
Tim, would you be willing to look at the code that I've put up in issue

https://netbeans.org/bugzilla/show_bug.cgi?id=175342

and see if you'd be willing to put all of this together into one package?  I'd really like to see a lot more formal framework for event handling happen that makes it very easy and practical to get things set up correctly to use the EDT only when it needs to be, and background threads for everything else.
Comment 8 _ tboudreau 2010-02-01 15:14:18 UTC
@Y01 & @Y02: RunOffEDTProvider.Progress would be fine.  Would prefer to rename RunOffEDTProvider to RunOffEdtProvider (capitalizing acronyms in class names makes it hard to see where the acronym ends - i.e. it is EDT not EDTP - since I broke our CVS repository for 3 days once by renaming HTMLRenderer to HtmlRenderer at Jesse's suggestion, I will never forget it)

@Dafe:  Perhaps the color should be L&F-specific, so it does not confuse users with Ubuntu's behavior?  Since we are using a non-decorated window (and I would like to keep it that way - title-bar is useless in this case), it can be a little non-obvious what is happening otherwise.  This has also become the convention in a lot of web applications that create fake modal dialogs using Javascript, so it is likely to be clear what is happening.  There is already a test to avoid using translucency if text antialiasing is off (a likely sign that it is VNC or remote X or similar).

@Gregg:  See my comments in issue #175342.  A general mechanism for this sort of thing would be nice, but seems out of scope for this issue.  Given the diminished size of the core tem, merging these two into one would likely guarantee that neither issue gets integrated for 6.9.
Comment 9 Jaroslav Tulach 2010-02-02 01:14:53 UTC
Re. Y01: Use RunOffEDTProvider.Progress then.
Comment 10 _ tboudreau 2010-02-09 00:45:27 UTC
Integrated in main/ 3a4848d4fd0
Comment 11 Quality Engineering 2010-02-10 02:19:10 UTC
Integrated into 'main-golden', will be available in build *201002100200* on http://bits.netbeans.org/dev/nightly/ (upload may still be in progress)
Changeset: http://hg.netbeans.org/main/rev/3a4848d4fd0f
User: Tim Boudreau <tboudreau@netbeans.org>
Log: #165005 - Ability to use progress API w/ blocking modal dialog showing progress