MessageDialog title is coming 'Not Responding' - eclipse

I am performing a long running operation and showing message dialog as "fetching details" and closing the same once the operation is performed.
try{
MessageDialog dialog = new MessageDialog(Display.getDefault().getActiveShell(), "Information", null, "Fetching Details...", MessageDialog.NONE , new String[] {}, -1);
dialog.setBlockOnOpen(false);
dialog.open();
//Schedule long Running operations
} finally{
dialog.close()
}
If the operation takes more time, dialog is showing not responding (Title changes to "Information (Not Responding)").
How can avoid the not responding status ?

You must not run long operations in the UI thread. Doing so will block the thread until they finish and the UI will become unresponsive.
Run your operations in a background thread, or an Eclipse Job or even a Java 8 CompleteableFuture.
Use the Display asyncExec in your background code to update the UI as required.
Another alternative is to use ProgressMonitorDialog:
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
try {
dialog.run(true, true, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor monitor) {
monitor.beginTask("Task name", IProgressMonitor.UNKNOWN);
try {
// TODO your long running code
// TODO check monitor.isCanceled() as often as possible
}
finally {
monitor.done();
}
}
});
}
... catch exceptions

Related

Eclipse Job: How to override Job's error handling dialog

I had a requirement to disable 'Run In Background' button from Progress monitor while Job is running. After I searched in forums, I did not find any direct solution to do so. Thus, I am using Workbench's progressive service to run the job and creating the Job in non-UI user mode(setUser(false)) as shown below.
PlatformUI.getWorkbench().getProgressService().run(true, true, new IRunnableWithProgress() {
#Override
public void run(final IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException {
progressMonitor.beginTask("Start Job", 1);
Job job = new Job("Job1") {
#Override
protected IStatus run(IProgressMonitor dummyMonitor) {
//Use monitor of progressive service
progressMonitor.beginTask("Started Job1", no_of_tasks);
//Perform Job and update monitor once task is done
}
#Override
public boolean belongsTo(Object family) {
return family == BuildConstants.MY_JOB_FAMILY;
}
});
}
job.setUser(false);
job.schedule();
//Wait for Job to be done
IJobManager jobManager = Job.getJobManager();
Job[] jobs = jobManager.find(BuildConstants.MY_JOB_FAMILY);
while(jobs.length > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//Do nothing.
}
jobs = jobManager.find(BuildConstants.MY_JOB_FAMILY);
}
//Once job finishes exit the Progressive service.
});
}
With this approach all positive scenarios are working fine. But in case of error, Job is showing 'Problem Occured' dialog and it is closing immediately, as the progressive service is exiting once the job is done(as job manager does not find any job belong to family 'MY_JOB_FAMILY').
Note: I can not perform all my tasks directly in IRunnableWithProgress, as I am running multiple Jobs in parallel from a parent Job.
My questions are as below:
Is there a different approach to disable 'Run In Background' button of Job ?
Is there a way to stop the 'Problem Occured' dialog to appear ?
How could I make my progressive service to wait for user click on 'problem occured' dialog ?

JavaFX 8 Dialog

I'm implementing a document editor with JavaFX8 and e(fx)clipse and want to user to be informed when the export (write to disc) is ongoing. I'm using the main (GUI) Thread for this as I want to block the gui during this operation (which takes 2-3 seconds). During this operation I want to show a small popup to inform the user that the export is ongoing, nothing fancy.
#FXML
public void export() {
Dialog dialog = new Dialog();
dialog.setContentText("exporting ...");
dialog.show();
// some lenghty methods come here, ~equivalent to Thread.sleep(3000);
dialog.hide();
}
When I press the corresponding Button which invokes the export method, I get somehow two dialogs, one of them NOT closing and remaining open after the method has finished.
Does somebody has an idea what's happening here? I'm really interested in a simple solution, I don't need to have a progress bar etc..
Another possibility would be to show a wait-cursor before the operation starts and switching back to the default cursor after that. Unfortunately, this does also not seem to work. I understand that the UI is blocked during the "lengthty" operation, but I don't udnerstand why I cant change the UI before and after that operation....
Your example isn't very complete - however I would recommend using one of two approaches. However, you aren't putting the long process on a background thread which will FREEZE your app. You want to offload that process.
1) Use the ControlsFX Dialog which has a Progess Alert. Tie your work to either a Task or a Service and provide that to the alert. This will pop the alert up while the thread is active, and will automatically close it when done. If you have intermediary progress values, it can be used to update the progress bar.
Or if you don't want to use this dialog, you could do something like this:
Alert progressAlert = displayProgressDialog(message, stage);
Executors.newSingleThreadExecutor().execute(() -> {
try {
//Do you work here....
Platform.runLater(() ->forcefullyHideDialog(progressAlert));
} catch (Exception e) {
//Do what ever handling you need here....
Platform.runLater(() ->forcefullyHideDialog(progressAlert));
}
});
private Alert displayProgressDialog(String message, Stage stage) {
Alert progressAlert = new Alert(AlertType.NONE);
final ProgressBar progressBar = new ProgressBar();
progressBar.setMaxWidth(Double.MAX_VALUE);
progressBar.setPrefHeight(30);
final Label progressLabel = new Label(message);
progressAlert.setTitle("Please wait....");
progressAlert.setGraphic(progressBar);
progressAlert.setHeaderText("This will take a moment...");
VBox vbox = new VBox(20, progressLabel, progressBar);
vbox.setMaxWidth(Double.MAX_VALUE);
vbox.setPrefSize(300, 100);
progressAlert.getDialogPane().setContent(vbox);
progressAlert.initModality(Modality.WINDOW_MODAL);
progressAlert.initOwner(stage);
progressAlert.show();
return progressAlert;
}
private void forcefullyHideDialog(javafx.scene.control.Dialog<?> dialog) {
// for the dialog to be able to hide, we need a cancel button,
// so lets put one in now and then immediately call hide, and then
// remove the button again (if necessary).
DialogPane dialogPane = dialog.getDialogPane();
dialogPane.getButtonTypes().add(ButtonType.CANCEL);
dialog.hide();
dialogPane.getButtonTypes().remove(ButtonType.CANCEL);
}

SWT - Tweaking my ProgressMonitorDialog

I have a working ProgressMonitorDialog, but I want to make sure that I am setting it up correctly.
First the Code:
Method to create Dialog
public void startProgressBar() {
try {
new ProgressMonitorDialog(getShell()).run(true, true,
new ProgressBarThread());
}
catch (InvocationTargetException e) {
MessageDialog.openError(getShell(), "Error", e.getMessage());
}
catch (InterruptedException e) {
MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
}
}
Class File
class ProgressBarThread implements IRunnableWithProgress {
private static final int TOTAL_TIME = 1000;
public ProgressBarThread() {
}
public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException {
monitor.beginTask("Creating PDF File(s): Please wait.....", IProgressMonitor.UNKNOWN);
for (int total = 0; total < TOTAL_TIME ; total++) {
Thread.sleep(total);
monitor.worked(total);
if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
}
monitor.done();
}
}
Method that calls the ProgressBar and runs a Pdf file creation Operation
private void startSavePdfOperation() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
startProgressBar();
}
});
saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
saveOp.addOperationListener(new MyOperationListener(this) {
public void endOperationImpl() {
java.io.File zipFile = null;
try {
AplotSaveResultsParser.SaveResult saveResults = saveOp.getSaveResults();
if (saveResults != null) {
ETC..... ETC......
Questions:
Being the ProgressMonitorDialog is a GUI, it needs to be executed in a
Display.getDefault().asyncExec?
If the ProgressMonitorDialog is running in a separate thread, how does it know to close when the operation is finsihed?
Is there any relationship between the progressbar and the operation?
I am correct in assuming that the for loop in the ProgressBarThread class is basically the timer that keeps the monitor open?
Is there a way to increase the speed of the ProgressMonitorDialog's indicator, also can you remove the cancel button?
This is what I am thinking is happening currently.
I am starting the progress bar just before I start the PDF Operation Listener
See startSavePdfOperation() Above
The progress bar is running as unknown, but using a for loop to keep the progress bar dialog open, while the operation is running on a thread in the background.
See Class ProgressBarThread above
When the PDF operation completes the listener operation class closes the base GUI dialog.
public void endOperation() {
try {
endOperationImpl();
}
finally {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
w.recursiveSetEnabled(getShell(), true);
w.getShell().setEnabled(!getShell().getEnabled());
w.close();
}
});
}
}
I am not sure what is happening to the ProgressBarThread monitor?
Is this Possible?
When the PDF Operation starts, the ProgressMonitorDialog opens and starts the indicator. OK with keeping it unknown.
When the PDF Operation completes, the monitor closes, then the base Dialog
I am just wanting to open progress bar dialog that will inform the user that their request is working in the background.
As stated the above code works, but I am afraid by letting the closing of Base GUI, destroy my Progress Thread and Monitor is not good practice.
First of all, in your ProgressBarThread#run() you should use monitor.worked(1). You don't need to set the total worked but increment it by the amount of work done, since the last time it was called.
Q1. Yes it needs to be executed in the display thread
Q2. Normally the work that needs to be done is actually performed in the runnable that is passed to the progress monitor dialog so that you can accurately report the amount of progress made. So your operation (if it is a synchronous call) should be called from within ProgressBarThread#run() so that you call monitor.worked(1) only when one file processing is complete.
Q3. What kind of operation are you running, perhaps it already supports showing progress bar, and you just need to invoke the right API. Is it an IUndoableOperation?
Q4. As I said this approach is problematic because you can never accurately report the progress and close the dialog only when the operation is completed. But if this is the only choice you have, then you can just save the monitor reference somewhere so that it is accessible to the other thread. Once monitor.done() is called, your ProgressBarThread#run() should return, the dialog will close.
Q5. You can remove the cancel button by passing the correct parameter to ProgressMonitorDialog#run(..):
new ProgressMonitorDialog(getShell()).run(true, false, new ProgressBarThread());
For the rest of the questions I can better answer if I know what kind of operation (what API) you are using.

Process start & end on button click

i have created an application.In that i have created a button.After clicking on the button a process get's started.Now when i press the close('X') button of the application,the application closes.I want all this to happen on a click of a button i.e When i click the button for the first time it should start the process & as soon as click the same button again the process should get closed.
Here it is. Comments are inside code.
using System.Diagnostics;
/// <summary>
/// Process started by our app
/// </summary>
Process process;
private void button1_Click(object sender, EventArgs e)
{
// Haven't been started yet or user closed it
if (process == null || process.HasExited)
{
// Do open
try
{
process = Process.Start("notepad.exe");
}
catch (Exception ex)
{
// Inform user about error
}
}
// It is started
else
{
// many a thing can go wrong here.
// Even something as simple as user closing the app himself
try
{
// Send app instruction to close itself
if (!process.CloseMainWindow())
{
// Unable to comply - has to be put to death
// Merciful people might give it a few retries
// before execution
process.Kill();
}
}
catch (Exception ex)
{
// Inform user about error
}
finally
{
// So the cycle of life can start again
process = null;
}
}
}
You can use flags that stores a true value if the application is already running i.e. if the button is pressed for the first time. Then use a simple if condition to call the respective function.

When do asyncExec events begin?

I'm attempting to create a bare bones app for use in developing a plugin. I don't need a workbench.
Below the title1 dialog will show, but the title2 never does.
What needs to be done in order for the 2nd one to be shown?
public class BareBonesApp extends AbstractApplication
{
public Object start(IApplicationContext context) throws Exception
{
Display display = PlatformUI.createDisplay();
MessageDialog.openWarning(null, "title1", "message1");
display.asyncExec(new Runnable()
{
public void run()
{
MessageDialog.openWarning(null, "title2", "message2");
}
});
return null;
}
}
Display has different queues for runnables that should run sync, async or in a specifc time (Display.timerExec). When Display.readAndDispatch has dispatched all events, first the runnables in the sync-queue are executed, then the async-queue is emptied and after that the due timerExec runnables are executed.
The only difference between Display.syncExec and Display.asyncExec is that the syncExec method waits for the runnable to be executed by the Display thread. Display.asyncExec simply queues the runnable and goes on.
So if "title2" never appears, I asume your application does not run the Display loop:
Display display = new Display(); // this thread should be the only one that creates a display instance
while (someCondition) {
if (!display.readAndDispatch())
display.sleep();
}