package com.openfin.desktop.demo; import com.openfin.desktop.DockingManager; import com.openfin.desktop.*; import info.clearthought.layout.TableLayout; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.lang.System; import java.util.Arrays; /** * Example of snap&dock Java window with OpenFin html5 window * * Move windows close to each other so they snap, and release mouse to dock 2 windows. * * This example use snap and dock library at https://github.com/openfin/java-snap-and-dock. * * Steps to implement snap&dock in this example * * 1. Launch OpenFin Runtime, as in startOpenFinRuntime * 2. Create an instance of DockingManager * 2. Launch a HTML5 app and register with DockingManager as in launchHTMLApps * 3. Register Java window as in DockingManager registerJavaWindow * * All windows can receive notification when it is docked by subscribing to 'window-docked' topic. It can also request to be undocked * by sending a message to Docking Manager. Please refer to document of Snap&Dock library for more into * * Created by wche on 2/28/15. * */ public class OpenFinDockingDemo extends JPanel implements ActionListener, WindowListener { private final static Logger logger = LoggerFactory.getLogger(OpenFinDockingDemo.class.getName()); private static JFrame jFrame; protected JButton launch; protected JButton close; protected JButton undockButton; // For a Java window to be dockable, it must be registered with Runtime as a child window of a HTML5 app. We are going to create // a hidden HTML5 app, with javaParentAppUuid as UUID, as the parent app of all Java windows protected String javaParentAppUuid = "Java Parent App"; protected String appUuid = "JavaDocking"; // UUID for desktopConnection protected String javaWindowName = "Java Dock Window"; protected String openfin_app_url = "https://cdn.openfin.co/examples/junit/SimpleDockingExample.html"; // source is in release/SimpleDockingExample.html protected DesktopConnection desktopConnection; protected DockingManager dockingManager; protected JTextField dockStatus; // show Ready to dock message protected JTextArea status; public OpenFinDockingDemo() { try { this.desktopConnection = new DesktopConnection(appUuid); } catch (DesktopException desktopError) { desktopError.printStackTrace(); } setLayout(new BorderLayout()); add(layoutCenterPanel(), BorderLayout.CENTER); add(layoutLeftPanel(), BorderLayout.WEST); setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); setMainButtonsEnabled(false); setAppButtonsEnabled(false); } private JPanel layoutLeftPanel() { JPanel panel = new JPanel(); double size[][] = {{410}, {120, 30, TableLayout.FILL}}; panel.setLayout(new TableLayout(size)); panel.add(layoutActionButtonPanel(), "0,0,0,0"); panel.add(layoutDockStatus(), "0,1,0,1"); panel.add(layoutStatusPanel(), "0, 2, 0, 2"); return panel; } private JTextField layoutDockStatus() { this.dockStatus = new JTextField(); this.dockStatus.setForeground(Color.RED); return this.dockStatus; } private JPanel layoutActionButtonPanel() { JPanel buttonPanel = new JPanel(); JPanel topPanel = new JPanel(); double size[][] = {{10, 190, 20, 190, 10}, {25, 10, 25, 10}}; topPanel.setLayout(new TableLayout(size)); topPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(2), "Desktop")); launch = new JButton("Launch OpenFin"); launch.setActionCommand("start"); close = new JButton("Shutdown OpenFin"); close.setActionCommand("close"); topPanel.add(launch, "1,0,1,0"); topPanel.add(close, "3,0,3,0"); undockButton = new JButton("Undock"); undockButton.setActionCommand("undock-window"); undockButton.setEnabled(false); topPanel.add(undockButton, "1,2,1,2"); close.addActionListener(this); launch.addActionListener(this); undockButton.addActionListener(this); buttonPanel.add(topPanel, "0,0"); return buttonPanel; } private JPanel layoutCenterPanel() { JPanel panel = new JPanel(); double size[][] = {{TableLayout.FILL}, {150, 150, TableLayout.FILL}}; panel.setLayout(new TableLayout(size)); return panel; } protected JPanel layoutStatusPanel() { //Simple status console status = new JTextArea(); status.setEditable(false); status.setAutoscrolls(true); status.setLineWrap(true); JScrollPane statusPane = new JScrollPane(status); statusPane.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); statusPane.getViewport().setOpaque(false); statusPane.setOpaque(false); statusPane.setBorder(BorderFactory.createEmptyBorder(5,15,15,15)); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(2), "Status")); panel.add(statusPane, BorderLayout.CENTER); return panel; } @Override public void windowOpened(WindowEvent e) { } @Override public void windowClosing(WindowEvent e) { closeDesktop(); } @Override public void windowClosed(WindowEvent e) { } @Override public void windowIconified(WindowEvent e) { } @Override public void windowDeiconified(WindowEvent e) { } @Override public void windowActivated(WindowEvent e) { } @Override public void windowDeactivated(WindowEvent e) { } private void updateMessagePanel(final String msg) { if (SwingUtilities.isEventDispatchThread()) { String t = ""; if (status.getText().length() > 0) { t = status.getText(); } StringBuilder b = new StringBuilder(); b.append(msg).append("\n").append(t); status.setText(b.toString()); status.setCaretPosition(0); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateMessagePanel(msg); } }); } } private void closeDesktop() { if (desktopConnection != null && desktopConnection.isConnected()) { try { Application javaParentApp = Application.wrap(javaParentAppUuid, desktopConnection); javaParentApp.close(); dockingManager.dispose(); Thread.sleep(2000); desktopConnection.exit(); desktopConnection = null; } catch (Exception e) { e.printStackTrace(); } } try { Thread.sleep(2000); System.exit(0); } catch (InterruptedException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } private void undockFromOtherWindows() { try { // send message to Docking Manager to undock me JSONObject msg = new JSONObject(); msg.put("applicationUuid", javaParentAppUuid); msg.put("windowName", javaWindowName); desktopConnection.getInterApplicationBus().publish("undock-window", msg); } catch (Exception e) { e.printStackTrace(); } undockButton.setEnabled(false); } /** * * Start OpenFin Runtime * */ private void startOpenFinRuntime() { try { DesktopStateListener listener = new DesktopStateListener() { @Override public void onReady() { onRuntimeReady(); } @Override public void onClose(String error) { updateMessagePanel(String.format("Connection closed %s", error)); } @Override public void onError(String reason) { updateMessagePanel("Connection failed: " + reason); } @Override public void onMessage(String message) { } @Override public void onOutgoingMessage(String message) { } }; RuntimeConfiguration configuration = new RuntimeConfiguration(); configuration.setDevToolsPort(9090); configuration.setAdditionalRuntimeArguments(" --v=1 "); // enable additional logging from Runtime String desktopVersion = java.lang.System.getProperty("com.openfin.demo.version"); if (desktopVersion == null) { desktopVersion = "stable"; } configuration.setRuntimeVersion(desktopVersion); desktopConnection.connect(configuration, listener, 60); } catch (Exception e) { e.printStackTrace(); } } private void onRuntimeReady() { try { updateMessagePanel("Connection authorized."); setMainButtonsEnabled(true); this.dockingManager = new DockingManager(this.desktopConnection, this.javaParentAppUuid); this.desktopConnection.getInterApplicationBus().subscribe("*", "window-docked", (uuid, topic, data) -> { JSONObject event = (JSONObject) data; String appUuid = event.getString("applicationUuid"); String windowName = event.getString("windowName"); updateMessagePanel(String.format("Window docked %s %s", appUuid, windowName)); if (javaParentAppUuid.equals(appUuid) && javaWindowName.equals(windowName)) { updateUndockButton(true); } }); this.desktopConnection.getInterApplicationBus().subscribe("*", "window-undocked", (uuid, topic, data) -> { JSONObject event = (JSONObject) data; String appUuid = event.getString("applicationUuid"); String windowName = event.getString("windowName"); updateMessagePanel(String.format("Window undocked %s %s", appUuid, windowName)); if (javaParentAppUuid.equals(appUuid) && javaWindowName.equals(windowName)) { updateUndockButton(false); } }); registerJavaWindow(); launchHTMLApps(); launchAnotherJavaApp(); } catch (Exception e) { logger.error("Error creating DockingManager", e); } } public void actionPerformed(java.awt.event.ActionEvent e) { if ("start".equals(e.getActionCommand())) { startOpenFinRuntime(); } else if ("close".equals(e.getActionCommand())) { closeDesktop(); } else if ("undock-window".equals(e.getActionCommand())) { undockFromOtherWindows(); } } private void setMainButtonsEnabled(boolean enabled) { launch.setEnabled(!enabled); close.setEnabled(enabled); } private void setAppButtonsEnabled(boolean enabled) { } /** * Register Java window with OpenFin Runtime * */ private void registerJavaWindow() { try { // Java window needs to be assigned a HTML5 app as parent app in order for Runtime to control it. // now we are creating a HTML5 app aith autoShow = false so it is hidden. ApplicationOptions options = new ApplicationOptions(javaParentAppUuid, javaParentAppUuid, openfin_app_url); options.setApplicationIcon("http://openfin.github.io/snap-and-dock/openfin.ico"); WindowOptions mainWindowOptions = new WindowOptions(); mainWindowOptions.setAutoShow(false); mainWindowOptions.setDefaultHeight(50); mainWindowOptions.setDefaultLeft(50); mainWindowOptions.setDefaultTop(50); mainWindowOptions.setDefaultWidth(50); mainWindowOptions.setShowTaskbarIcon(false); mainWindowOptions.setSaveWindowState(false); // set to false so all windows start at same initial positions for each run options.setMainWindowOptions(mainWindowOptions); launchHTMLApp(options, new AckListener() { @Override public void onSuccess(Ack ack) { Application app = (Application) ack.getSource(); logger.debug("Registering java window"); dockingManager.registerJavaWindow(javaWindowName, jFrame, new AckListener() { @Override public void onSuccess(Ack ack) { if (ack.isSuccessful()) { undockButton.setEnabled(false); } } @Override public void onError(Ack ack) { logger.error("Error registering Java window " + ack.getReason()); } }); } @Override public void onError(Ack ack) { logger.error("Error launching " + javaParentAppUuid); } }); } catch (Exception e) { e.printStackTrace(); } } /** * * Launching HTML5 apps and register docking manager * */ private void launchHTMLApps() { // launch 5 instances of same example app int width = 300, height=200; int gap = 50; // gap between windows at initial positions for (int i = 0; i < 2; i++) { try { String uuid = String.format("docking-html-%d", i); ApplicationOptions options = new ApplicationOptions(uuid, uuid, openfin_app_url); options.setApplicationIcon("http://openfin.github.io/snap-and-dock/openfin.ico"); WindowOptions mainWindowOptions = new WindowOptions(); mainWindowOptions.setAutoShow(true); mainWindowOptions.setDefaultHeight(height); mainWindowOptions.setDefaultLeft(10 + i * (width + gap)); mainWindowOptions.setDefaultTop(50); mainWindowOptions.setDefaultWidth(width); mainWindowOptions.setShowTaskbarIcon(true); mainWindowOptions.setSaveWindowState(false); // set to false so all windows start at same initial positions for each run options.setMainWindowOptions(mainWindowOptions); launchHTMLApp(options, new AckListener() { @Override public void onSuccess(Ack ack) { logger.debug(String.format("Successful launching %s", options.getUUID())); Application app = (Application) ack.getSource(); dockingManager.registerWindow(app.getWindow()); } @Override public void onError(Ack ack) { logger.error(String.format("Error launching %s %s", options.getUUID(), ack.getReason())); } }); } catch (Exception e) { logger.error("Error launching app", e); } } } private void launchHTMLApp(ApplicationOptions options, AckListener ackListener) throws Exception { logger.debug(String.format("Launching %s", options.getUUID())); DemoUtils.runApplication(options, this.desktopConnection, ackListener); } private void launchAnotherJavaApp() { Thread launchThread = new Thread() { public void run() { logger.debug(String.format("Launching docking.bat %s", DockingDemo2.class.getName())); String[] command = {"docking.bat", DockingDemo2.class.getName()}; ProcessBuilder probuilder = new ProcessBuilder( command ); //You can set up your work directory probuilder.directory(new File(".")); try { // Process process = probuilder.start(); // //Read out dir output // InputStream is = process.getInputStream(); // InputStreamReader isr = new InputStreamReader(is); // BufferedReader br = new BufferedReader(isr); // String line; // while ((line = br.readLine()) != null) { // logger.debug(String.format("Java App output: %s", line)); // } // int exitValue = process.waitFor(); // logger.debug(String.format("Java app exit code %d", exitValue)); Process process = Runtime.getRuntime().exec("cmd"); OutputStream stdin = process.getOutputStream(); InputStream stderr = process.getErrorStream(); InputStream stdout = process.getInputStream(); String line = "start docking.bat " + DockingDemo2.class.getName() + "\n"; stdin.write(line.getBytes()); stdin.flush(); stdin.close(); // clean up if any output in stdout BufferedReader brCleanUp = new BufferedReader(new InputStreamReader(stdout)); while ((line = brCleanUp.readLine()) != null) { logger.debug("[Stdout] " + line); } brCleanUp.close(); // clean up if any output in stderr brCleanUp = new BufferedReader(new InputStreamReader(stderr)); while ((line = brCleanUp.readLine()) != null) { logger.info("[Stderr] " + line); } brCleanUp.close(); } catch (Exception ex) { logger.error("Error launch java app", ex); } } }; launchThread.start(); } private void updateUndockButton(boolean enabled) { this.undockButton.setEnabled(enabled); if (enabled) { this.dockStatus.setText("Docked. Click Unlock button to undock"); } else { this.dockStatus.setText(""); } } private static void createAndShowGUI() { //Create and set up the window. jFrame = new JFrame("Java Docking Demo"); jFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); //Create and set up the content pane. OpenFinDockingDemo newContentPane = new OpenFinDockingDemo(); newContentPane.setOpaque(true); //content panes must be opaque jFrame.setContentPane(newContentPane); jFrame.addWindowListener(newContentPane); //Display the window. jFrame.pack(); jFrame.setSize(470, 300); jFrame.setLocation(100, 400); // jFrame.setLocationRelativeTo(null); jFrame.setResizable(false); jFrame.setVisible(true); } /** * * @param args */ public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } }