package org.openpnp.util;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import javax.swing.SwingUtilities;
import org.openpnp.gui.MainFrame;
import org.openpnp.gui.support.MessageBoxes;
import org.openpnp.model.Configuration;
import com.google.common.util.concurrent.FutureCallback;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
public class UiUtils {
/**
* Functional interface for a Runnable that can throw an Exception but returns no value. Splits
* the difference between Runnable and Callable.
*/
public interface Thrunnable {
public void thrun() throws Exception;
}
/**
* Shortcut for submitMachineTask(Callable) which uses a Thrunnable instead. This allows for
* simple tasks that may throw an Exception but return nothing.
*
* @param thrunnable
* @return
*/
public static Future<Void> submitUiMachineTask(final Thrunnable thrunnable) {
return submitUiMachineTask(() -> {
thrunnable.thrun();
return null;
});
}
/**
* Wrapper for submitMachineTask(Callable, Consumer, Consumer) which ignores the return value in
* onSuccess and shows a MessageBox when an Exception is thrown. Handy for simple tasks that
* don't care about the return value but want to notify the user in case of failure. Ideal for
* running Machine tasks from ActionListeners.
*
* @param callable
* @return
*/
public static <T> Future<T> submitUiMachineTask(final Callable<T> callable) {
return submitUiMachineTask(callable, (result) -> {
} , (t) -> {
MessageBoxes.errorBox(MainFrame.get(), "Error", t);
});
}
/**
* Functional version of Machine.submit which guarantees that the the onSuccess and onFailure
* handlers will be run on the Swing event thread.
*
* @param callable
* @param onSuccess
* @param onFailure
* @return
*/
public static <T> Future<T> submitUiMachineTask(final Callable<T> callable,
final Consumer<T> onSuccess, final Consumer<Throwable> onFailure) {
return Configuration.get().getMachine().submit(callable, new FutureCallback<T>() {
@Override
public void onSuccess(T result) {
try {
SwingUtilities.invokeLater(() -> onSuccess.accept(result));
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Throwable t) {
try {
SwingUtilities.invokeLater(() -> onFailure.accept(t));
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Functional wrapper for actions that may throw an Exception. Presents an error box to the user
* with the Exception contents if one is thrown. Basically saves like 5 lines of boilerplate in
* actions.
*
* @param thrunnable
*/
public static void messageBoxOnException(Thrunnable thrunnable) {
try {
thrunnable.thrun();
}
catch (Exception e) {
MessageBoxes.errorBox(MainFrame.get(), "Error", e);
}
}
// From http://stackoverflow.com/questions/26854301/control-javafx-tooltip-delay
public static void bindTooltip(final Node node, final Tooltip tooltip){
node.setOnMouseMoved(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event) {
// +15 moves the tooltip 15 pixels below the mouse cursor;
// if you don't change the y coordinate of the tooltip, you
// will see constant screen flicker
tooltip.show(node, event.getScreenX(), event.getScreenY() + 15);
}
});
node.setOnMouseExited(new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent event){
tooltip.hide();
}
});
}
}