package au.com.vaadinutils.ui;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import au.com.vaadinutils.dao.EntityManagerRunnable;
import au.com.vaadinutils.listener.CancelListener;
import au.com.vaadinutils.listener.ClickEventLogged;
import au.com.vaadinutils.listener.CompleteListener;
import au.com.vaadinutils.listener.ProgressListener;
/**
* Displays a dialog designed to be shown when a long running task is in
* progress.
*
* You can use WorkingDialog in one of two ways.
*
* 1) Call WorkingDialog Add it to the UI via
* UI.getCurrent().addWindow(workingDialog); Then set a runnable by calling
* setWorker(new Runnable() {} ); The working dialog will then display its self
* and run the Runnable in a background thread. When the Runnable completes the
* WorkingDialog will be removed from the UI.
*
* 2) Call WorkingDialog Add it to the UI via
* UI.getCurrent().addWindow(workingDialog); Pass it to your own thread as a
* 'ProgressListener'. When your thread calls either the complete or exception
* methods the Working Dialog will be closed. Calls to itemError are ignored.
*
*/
public class WorkingDialog extends Window implements ProgressListener<String>
{
private static final long serialVersionUID = 1L;
private Label messageLabel;
private VerticalLayout content;
private Button cancel;
private CancelListener cancelListener;
private CompleteListener completeListener;
private VerticalLayout layout;
final UI ui;
/**
* Displays a dialog designed to be shown when a long running task is in
* progress.
*
* @param caption
* @param message
*/
public WorkingDialog(String caption, String message)
{
this(caption, message, null);
}
/**
* Display the Working Dialog with a Cancel Button. If the user clicks the
* Cancel button the listener will be sent a cancel button. The setWorker
* method does not support being cancelled.
*
* @param caption
* @param message
* @param listener
* @param refresher
*/
public WorkingDialog(String caption, String message, CancelListener listener)
{
super(caption);
ui = UI.getCurrent();
this.setModal(true);
this.setClosable(false);
this.setResizable(false);
content = new VerticalLayout();
this.setWidth("500px");
this.setHeight("150px");
content.setSizeFull();
content.setMargin(true);
content.setSpacing(true);
this.cancelListener = listener;
layout = new VerticalLayout();
layout.setSpacing(true);
layout.setSizeFull();
HorizontalLayout progressArea = new HorizontalLayout();
progressArea.setSizeFull();
ProgressBar progress = new ProgressBar();
progressArea.addComponent(progress);
progress.setIndeterminate(true);
messageLabel = new Label(message);
messageLabel.setContentMode(ContentMode.HTML);
messageLabel.setSizeFull();
progressArea.addComponent(messageLabel);
progressArea.setExpandRatio(messageLabel, 1);
layout.addComponent(progressArea);
content.addComponent(layout);
if (listener != null)
{
cancel = new Button("Cancel");
cancel.addClickListener(new ClickEventLogged.ClickListener()
{
private static final long serialVersionUID = 1L;
@Override
public void clicked(ClickEvent event)
{
WorkingDialog.this.cancelListener.cancel();
WorkingDialog.this.close();
}
});
content.addComponent(cancel);
content.setComponentAlignment(cancel, Alignment.BOTTOM_RIGHT);
}
this.setContent(content);
this.center();
}
@Override
public void close()
{
ui.accessSynchronously(new Runnable()
{
@Override
public void run()
{
WorkingDialog.super.close();
}
});
}
/**
* Pass a Runnable that WorkingDialog will run in a background thread. On
* completion of the thread the complete listener will be notified and the
* WorkingDialog will remove itself rom the UI.
*
* @param runnable
* the runnable to be run in a background thread.
* @param listener
* a complete listener to be notified when the thread has
* finished.
*/
public void setWorker(EntityManagerRunnable runnable, CompleteListener listener)
{
this.completeListener = listener;
Thread worker = new Thread(new Worker(this, runnable), "WorkingDialog");
worker.start();
}
/**
* convenience method, wraps the runnable in a EntityManagerRunnable and
* passes it to setWorker
*
* @param runnable
* @param listener
*/
public void setEntityWorker(Runnable runnable, CompleteListener listener)
{
setWorker(new EntityManagerRunnable(runnable),listener);
}
class Worker implements Runnable
{
private EntityManagerRunnable runnable;
private WorkingDialog parent;
Worker(WorkingDialog parent, EntityManagerRunnable runnable)
{
this.parent = parent;
this.runnable = runnable;
}
@Override
public void run()
{
try
{
this.runnable.run();
}
finally
{
ui.access(new Runnable()
{
@Override
public void run()
{
parent.complete(0);
}
});
}
}
}
public void addUserComponent(final Component component)
{
ui.accessSynchronously(new Runnable()
{
@Override
public void run()
{
layout.addComponent(component);
}
});
}
@Override
public void progress(int count, int max, final String message)
{
ui.accessSynchronously(new Runnable()
{
@Override
public void run()
{
messageLabel.setValue(message);
}
});
}
@Override
public void complete(int sent)
{
ui.accessSynchronously(new Runnable()
{
@Override
public void run()
{
if (completeListener != null)
completeListener.complete();
WorkingDialog.this.close();
}
});
}
@Override
public void itemError(Exception e, String status)
{
// Ignored.
}
@Override
public void exception(Exception e)
{
ui.accessSynchronously(new Runnable()
{
@Override
public void run()
{
if (completeListener != null)
completeListener.complete();
WorkingDialog.this.close();
}
});
}
public void removeUserComponent(Component component)
{
layout.removeComponent(component);
}
}