package eu.ggnet.saft.core.swing; import java.awt.Dialog; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.lang.ref.WeakReference; import java.util.concurrent.Callable; import javax.swing.*; import javafx.stage.Modality; import eu.ggnet.saft.api.ui.Frame; import eu.ggnet.saft.api.ui.IdSupplier; import eu.ggnet.saft.core.*; import eu.ggnet.saft.core.all.OnceCaller; import eu.ggnet.saft.core.all.UiUtil; import static eu.ggnet.saft.core.Client.lookup; public abstract class AbstractSwingOpen<T, R> implements Callable<Window> { protected static class T2<R> { private final JComponent panel; private final R source; public T2(JComponent panel, R source) { this.panel = panel; this.source = source; } } private final OnceCaller<T> before; // Never Null, because in the fallback case private final Window parent; private final Modality modality; private final String id; private final Class<R> creatorClass; public AbstractSwingOpen(Callable<T> before, Window parent, Modality modality, String id, Class<R> creatorClass) { this.before = new OnceCaller<>(before); this.parent = parent; this.modality = modality; this.id = id; this.creatorClass = creatorClass; } @Override public Window call() throws Exception { if ( before.ifPresentIsNull() ) return null; // Chainbreaker final T parameter = before.get(); // Call outside all ui threads assumed. Parameter null dosn't mean chainbreaker. // The Parameter might be a Id supplier, us it. final String localId = ((id == null && parameter instanceof IdSupplier) ? ((IdSupplier)parameter).id() : this.id); String key = creatorClass.getName() + (localId == null ? "" : ":" + localId); // Look into existing Instances and push up to the front if exist. if ( SwingCore.ACTIVE_WINDOWS.containsKey(key) ) { Window window = SwingCore.ACTIVE_WINDOWS.get(key).get(); if ( window == null || !window.isVisible() ) /* cleanup saftynet */ SwingCore.ACTIVE_WINDOWS.remove(key); else { if ( window instanceof JFrame ) ((JFrame)window).setExtendedState(JFrame.NORMAL); window.toFront(); return window; } } // Here it's clear, that our instance does not exist, so we create one. T2<R> t2 = build(parameter, creatorClass); Window window = SwingSaft.dispatch(() -> { Window w = null; if ( creatorClass.getAnnotation(Frame.class) != null ) { // TODO: Reuse Parent and Modality ? JFrame frame = new JFrame(); frame.setTitle(UiUtil.title(creatorClass, localId)); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(t2.panel); w = frame; } else { JDialog dialog = new JDialog(parent); dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); dialog.setModalityType(UiUtil.toSwing(modality).orElse(Dialog.ModalityType.MODELESS)); // This is an "application", default no modaltiy at all // Parse the Title somehow usefull. dialog.setTitle(UiUtil.title(creatorClass, localId)); dialog.getContentPane().add(t2.panel); w = dialog; } w.setIconImages(SwingSaft.loadIcons(creatorClass)); w.pack(); w.setLocationRelativeTo(parent); lookup(UserPreferences.class).loadLocation(creatorClass, localId, w); w.setVisible(true); return w; }); SwingSaft.enableCloser(window, t2.source); SwingCore.ACTIVE_WINDOWS.put(key, new WeakReference<>(window)); // Removes on close. window.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { // Clean us up. SwingCore.ACTIVE_WINDOWS.remove(key); // Store location. lookup(UserPreferences.class).storeLocation(creatorClass, localId, window); } }); return window; } protected abstract T2<R> build(T parameter, Class<R> clazz) throws Exception; public void exec() { Ui.exec(this); } }