All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.openfin.desktop.Window Maven / Gradle / Ivy

There is a newer version: 11.0.2
Show newest version
package com.openfin.desktop;

import com.openfin.desktop.animation.AnimationOptions;
import com.openfin.desktop.animation.AnimationTransitions;
import com.openfin.desktop.win32.WinMessageHelper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.Exception;
import java.util.ArrayList;
import java.util.List;

/**
 *
 *  An object representing a window that can be controlled by the AppDesktop API.
 *
 */
public class Window {
    private static Logger logger = LoggerFactory.getLogger(Window.class.getName());

    private DesktopConnection connection;
    private JSONObject noParamPayload, resizeToPayload, resizeByPayload,
        moveToPayload, moveByPayload;
    private String uuid, name;
    private long parentHwndId = -1, hwndId;  // for embedding

    /**
     * Window constructor
     *
     * @param applicationUuid UUID of the parent Application
     * @param name Name of the Window
     * @param connection Connection object to the AppDeskto
     */
    private Window(String applicationUuid, String name, DesktopConnection connection) {
        this.connection = connection;
        initialize(applicationUuid, name);
    }

    /**
     * Window constructor
     * @param application Parent Application
     */
    protected Window(Application application) {
        this.connection = application.getConnection();
        initialize(application.getUuid(), application.getUuid());
    }

    /**
     * Initialize internal data
     * @param uuid UUID of the application
     * @param name name of the application
     */
    private void initialize(String uuid, String name) {
        this.uuid = uuid;
        this.name = name;
        noParamPayload = new JSONObject();
        resizeToPayload = new JSONObject();
        resizeByPayload = new JSONObject();
        moveToPayload = new JSONObject();
        moveByPayload = new JSONObject();

        try {
            noParamPayload.put("uuid", uuid);
            resizeToPayload.put("uuid", uuid);
            resizeByPayload.put("uuid", uuid);
            moveToPayload.put("uuid", uuid);
            moveByPayload.put("uuid", uuid);

            noParamPayload.put("name", name);
            resizeToPayload.put("name", name);
            resizeByPayload.put("name", name);
            moveToPayload.put("name", name);
            moveByPayload.put("name", name);
        } catch (JSONException e) {
            logger.error("Error initializing", e);
        }
    }

    /**
     * Gets UUID
     * @return UUID
     */
    public String getUuid() {
        return uuid;
    }

    /**
     * Gets name
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * Returns the wrapped application that this window belongs to
     * @return Parent application
     */
    public Application getParentApplication() {
        return Application.wrap(getUuid(), connection);
    }

    /**
     * Get parent window
     * @return Parent window
     */
    public Window getParentWindow() {
        return getParentApplication().getWindow();
    }

    /**
     * Gets a base64 encoded PN snapshot of the window
     * @param callback AckListener for the request
     * @see AckListener
     */
    public void getSnapshot(AckListener callback)    {
        connection.sendAction("get-window-snapshot", new JSONObject(), callback, this);
    }


    /**
     * Shows the window if it is hidden
     *
     * @throws DesktopException if the window fails to show
     * @see DesktopException
     */
    public void show() throws DesktopException {
        connection.sendAction("show-window", noParamPayload);
    }

    /**
     * Shows the window if it is hidden
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void show(AckListener listener) {
        connection.sendAction("show-window", noParamPayload, listener, this);
    }

    /**
     * Hides the window if it is shown
     *
     * @throws DesktopException if the window fails to hide
     * @see DesktopException
     */
    public void hide() throws DesktopException {
        connection.sendAction("hide-window", noParamPayload);
    }

    /**
     * Hides the window if it is shown
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void hide(AckListener listener) {
        connection.sendAction("hide-window", noParamPayload, listener, this);
    }

    /**
     * Closes the window
     *
     * @throws DesktopException if the window fails to close
     * @see DesktopException
     */
    public void close() throws DesktopException {
        this.close(false, null);
    }

    /**
     * Closes the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void close(AckListener listener) {
        this.close(false, listener);
    }

    /**
     * Closes the window
     *
     * @param force Close will be prevented from closing when force is false and ‘close-requested’ has been subscribed to for the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void close(Boolean force, AckListener listener) {
        JSONObject closePayload = new JSONObject();
        try {
            closePayload.put("uuid", uuid);
            closePayload.put("name", name);
            closePayload.put("force", force);
            connection.sendAction("close-window", closePayload, listener, this);
        } catch (Exception e) {
            logger.error("Error closing window", e);
            DesktopUtils.errorAckOnException(listener, closePayload, e);
        }
    }

    /**
     * Minimizes the window
     *
     * @throws DesktopException if the window fails to minimize
     * @see DesktopException
     */
    public void minimize() throws DesktopException {
        connection.sendAction("minimize-window", noParamPayload);
    }

    /**
     * Minimizes the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void minimize(AckListener listener) {
        connection.sendAction("minimize-window", noParamPayload, listener, this);
    }

    /**
     * Maximizes the window
     *
     * @throws DesktopException if the window fails to maximize
     * @see DesktopException
     */
    public void maximize() throws DesktopException {
        connection.sendAction("maximize-window", noParamPayload);
    }

    /**
     * Maximizes the window
     *
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void maximize(AckListener listener) {
        connection.sendAction("maximize-window", noParamPayload, listener, this);
    }

    /**
     * Restores the window
     *
     * @throws DesktopException if the window fails to restore
     * @see DesktopException
     */
    public void restore() throws DesktopException {
        connection.sendAction("restore-window", noParamPayload);
    }

    /**
     * Restores the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void restore(AckListener listener) {
        connection.sendAction("restore-window", noParamPayload, listener, this);
    }

    /**
     * Gives focus to the window
     *
     * @throws DesktopException if the windw fails to gain focus
     * @see DesktopException
     */
    public void focus() throws DesktopException {
        connection.sendAction("focus-window", noParamPayload);
    }

    /**
     * Gives focus to the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void focus(AckListener listener) {
        connection.sendAction("focus-window", noParamPayload, listener, this);
    }

    /**
     * Removes focus to the window
     *
     * @throws DesktopException if the window fails to lose focus
     * @see DesktopException
     */
    public void blur() throws DesktopException {
        connection.sendAction("blur-window", noParamPayload);
    }

    /**
     * Removes focus to the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void blur(AckListener listener) {
        connection.sendAction("blur-window", noParamPayload, listener, this);
    }

    /**
     * Draws attention to the window by flashing the taskbar and window caption.
     * This effect continues until the window receives focus.
     * @param callback AckListener for the request
     * @see AckListener
     */
    public void flash(AckListener callback) {
        connection.sendAction("flash-window", new JSONObject(), callback, this);
    }

    /**
     * Stops flashing of taskbar and window caption
     * @param callback AckListener for the request
     * @see AckListener
     */
    public void stopFlashing(AckListener callback) {
        connection.sendAction("stop-flash-window", new JSONObject(), callback, this);
    }

    /**
     * Shows the window if it is hidden at the specified location
     *
     * @param left The left position of the window
     * @param top The right position of the window
     * @param toggle If true, the window will alternate between showing and hiding in subsequent calls
     * @throws DesktopException if the window fails to show
     * @see DesktopException
     */
    public void showAt(int left, int top, boolean toggle) throws DesktopException {
        try {
            connection.sendAction("show-at-window", moveToPayload
                    .put("left", left)
                    .put("top", top)
                    .put("toggle", toggle));
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
    }

    /**
     * Shows the window if it is hidden at the specified location
     *
     * @param left The left position of the window
     * @param top The right position of the window
     * @param toggle If true, the window will alternate between showing and hiding in subsequent calls
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to show
     * @see DesktopException
     */
    public void showAt(int left, int top, boolean toggle, AckListener listener) throws DesktopException {
        try {
            connection.sendAction("show-at-window", moveToPayload
                    .put("left", left)
                    .put("top", top)
                    .put("toggle", toggle), listener, this);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
    }

    /**
     * Moves the window to a specified location
     *
     * @param left The left position of the window
     * @param top The right position of the window
     * @throws DesktopException if the window fails to move
     * @see DesktopException
     */
    public void moveTo(int left, int top) throws DesktopException {
        try {
            moveToPayload.put("left", left);
            moveToPayload.put("top", top);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("move-window", moveToPayload);
    }

    /**
     * Moves the window to a specified location
     *
     * @param left The left position of the window
     * @param top The right position of the window
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to move
     * @see DesktopException
     */
    public void moveTo(int left, int top, AckListener listener) throws DesktopException {
        try {
            moveToPayload.put("left", left);
            moveToPayload.put("top", top);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("move-window", moveToPayload, listener, this);
    }

    /**
     * Moves the window by a specified amount
     *
     * @param deltaLeft The change in the left position of the window
     * @param deltaTop The change in the top position of the window
     * @throws DesktopException if the window fails to move
     * @see DesktopException
     */
    public void moveBy(int deltaLeft, int deltaTop) throws DesktopException {
        moveBy(deltaLeft, deltaTop, null);
    }

    /**
     * Moves the window by a specified amount
     *
     * @param deltaLeft The change in the left position of the window
     * @param deltaTop The change in the top position of the window
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to move
     * @see DesktopException
     */
    public void moveBy(int deltaLeft, int deltaTop, AckListener listener) throws DesktopException {
        try {
            moveByPayload.put("deltaLeft", deltaLeft);
            moveByPayload.put("deltaTop", deltaTop);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("move-window-by", moveByPayload, listener, this);
    }

    /**
     * Resizes the window to the specified dimensions
     *
     * @param width Width of the window
     * @param height Height of the window
     * @param anchor Specifies a corner to remain fixed during the resize.
     *               Can take the values:
     *                      "top-left"
     *                      "top-right"
     *                      "bottom-left"
     *                      "bottom-right"
     *               If undefined, the default is "top-left".
     * @throws DesktopException if the windw fails to resize
     * @see DesktopException
     */
    public void resizeTo(int width, int height, String anchor) throws DesktopException {
        try {
            resizeToPayload.put("height", height);
            resizeToPayload.put("width", width);
            resizeToPayload.put("anchor", anchor);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("resize-window", resizeToPayload);
    }

    /**
     * Resizes the window to the specified dimensions
     *
     * @param width Width of the window
     * @param height Height of the window
     * @param anchor Specifies a corner to remain fixed during the resize.
     *               Can take the values:
     *                      "top-left"
     *                      "top-right"
     *                      "bottom-left"
     *                      "bottom-right"
     *               If undefined, the default is "top-left".
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to resize
     * @see DesktopException
     */
    public void resizeTo(int width, int height, String anchor, AckListener listener) throws DesktopException {
        try {
            resizeToPayload.put("height", height);
            resizeToPayload.put("width", width);
            resizeToPayload.put("anchor", anchor);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("resize-window", resizeToPayload, listener, this);
    }

    /**
     * Resizes the window to the specified dimensions
     * @param width Width of the window
     * @param height Height of the window
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to resize
     * @see DesktopException
     */
    public void resizeTo(int width, int height, AckListener listener) throws DesktopException {
        resizeTo(width, height, "top-left", listener);
    }

    /**
     * Resizes the window by the specified amount
     *
     * @param deltaWidth Width delta of the window
     * @param deltaHeight Height delta of the window
     * @param anchor Specifies a corner to remain fixed during the resize.  Please check resizeTo method for more information
     * @throws DesktopException if the window fails to resize
     * @see DesktopException
     */
    public void resizeBy(int deltaWidth, int deltaHeight, String anchor) throws DesktopException {
        try {
            resizeByPayload.put("deltaWidth", deltaWidth);
            resizeByPayload.put("deltaHeight", deltaHeight);
            resizeByPayload.put("anchor", anchor);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("resize-window-by", resizeByPayload);
    }

    /**
     * Resizes the window by the specified amount
     *
     * @param deltaWidth Width delta of the window
     * @param deltaHeight Height delta of the window
     * @param anchor Specifies a corner to remain fixed during the resize.  Please check resizeTo method for more information
     * @param listener AckListener for the request
     * @see AckListener
     * @throws DesktopException if the window fails to resize
     * @see DesktopException
     */
    public void resizeBy(int deltaWidth, int deltaHeight, String anchor, AckListener listener) throws DesktopException {
        try {
            resizeByPayload.put("deltaWidth", deltaWidth);
            resizeByPayload.put("deltaHeight", deltaHeight);
            resizeByPayload.put("anchor", anchor);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("resize-window-by", resizeByPayload, listener, this);
    }

    /**
     * Gets the current state ("minimized", "maximized", or "restored") of the window
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void getState(AckListener listener) {
        connection.sendAction("get-window-state", noParamPayload, listener, this);
    }

    /**
     * Brings the window to the front of the window stack
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void bringToFront(AckListener listener) {
        connection.sendAction("bring-window-to-front", noParamPayload, listener, this);
    }

    /**
     * Determines if the window is currently showing
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void isShowing(AckListener listener) {
        connection.sendAction("is-window-showing", noParamPayload, listener, this);
    }

    /**
     * Gets the current bounds (top, left, width, height) of the window
     *
     * @param callback A function that is called if the method succeeds
     * @param listener A function that is called if the method fails
     * @see AsyncCallback
     * @see AckListener
     */
    public void getBounds(final AsyncCallback callback, final AckListener listener) {
        AckListener mainCallback = null;
        if(callback != null) {
            mainCallback = new AckListener() {
                @Override
                public void onSuccess(Ack ack) {
                    try {
                        JSONObject jsonObject = ack.getJsonObject();
                        JSONObject data = JsonUtils.getJsonValue(jsonObject, "data", null);
                        WindowBounds bounds = new WindowBounds(JsonUtils.getIntegerValue(data, "top", null), JsonUtils.getIntegerValue(data, "left", null),
                                JsonUtils.getIntegerValue(data, "width", null), JsonUtils.getIntegerValue(data, "height", null));
                        callback.onSuccess(bounds);
                    } catch (Exception ex) {
                        logger.error("Error calling onSuccess", ex);
                    }
                }
                @Override
                public void onError(Ack ack) {
                    DesktopUtils.errorAck(listener, ack);
                }
            } ;
        }
        connection.sendAction("get-window-bounds", noParamPayload, mainCallback, this);
    }

    /**
     * Sets the current bounds (top, left, width, height) of the window
     *
     * @param left The left position of the window.
     * @param top The top position of the window.
     * @param width The width position of the window.
     * @param height The height position of the window.
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void setBounds(int left, int top, int width, int height, AckListener listener) {
        JSONObject setBoundsPayload = new JSONObject();
        try {
            setBoundsPayload.put("uuid", uuid);
            setBoundsPayload.put("name", name);
            setBoundsPayload.put("top", top);
            setBoundsPayload.put("left", left);
            setBoundsPayload.put("width", width);
            setBoundsPayload.put("height", height);
            connection.sendAction("set-window-bounds", setBoundsPayload, listener, this);
        } catch (Exception e) {
            logger.error("Error setting bounds", e);
            DesktopUtils.errorAckOnException(listener, setBoundsPayload, e);
        }
    }



    /**
     * Brings the window to the front of the window stack
     *
     * @throws DesktopException if the window fails to be brought to front
     * @see DesktopException
     */
    public void bringToFront() throws DesktopException {
        connection.sendAction("bring-window-to-front", noParamPayload);
    }

    /**
     * Changes a window's options that were defined upon creation
     * @param options The window options to change
     * @see WindowOptions
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void updateOptions(WindowOptions options, AckListener listener) {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", uuid);
            payload.put("options", options.getJson());
        } catch (JSONException e) {
            DesktopUtils.errorAckOnException(listener, payload, e);
        }
        connection.sendAction("update-window-options", payload, listener, this);
    }

    /**
     * Returns the current options as stored in the desktop
     * @param callback A function that is called if the method succeeds
     * @param listener A function that is called if the method fails
     * @see AsyncCallback
     * @see AckListener
     */
    public void getOptions(final AsyncCallback callback, AckListener listener)    {
        AckListener mainCallback = null;
        if(callback != null) {
            mainCallback = new AckListener() {
                @Override
                public void onSuccess(Ack ack) {
                    try {
                        JSONObject jsonObject = ack.getJsonObject();
                        WindowOptions options = new WindowOptions(JsonUtils.getJsonValue(jsonObject, "data", null));
                        callback.onSuccess(options);
                    } catch (Exception ex) {
                        logger.error("Error calling onSuccess", ex);
                    }
                }
                @Override
                public void onError(Ack ack) {
                }
            } ;
        }
        connection.sendAction("get-window-options", noParamPayload, mainCallback, this);
    }


    /**
     * Set's the window as the foreground window
     * The window is activated(focused) and brought to front
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void setAsForeground(AckListener listener) {
        connection.sendAction("set-foreground-window", noParamPayload, listener, this);
    }

    /**
     * Allows a user from changing a window's size/position when using the window's frame
     *
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void enableFrame(AckListener listener) {
        connection.sendAction("enable-window-frame", noParamPayload, listener, this);
    }

    /**
     * Prevents a user from changing a window's size/position when using the window's frame
     *
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void disableFrame(AckListener listener) {
        connection.sendAction("disable-window-frame", noParamPayload, listener, this);
    }

    /**
     * Changes a window's options that were defined upon creation
     *
     * @param options The window options to change
     * @throws DesktopException if this method fails to update window options
     */
    public void updateOptions(JSONObject options) throws DesktopException {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
            payload.put("options", options);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("update-window-options", payload);
    }

    /**
     * Gets HWND of the current window
     *
     * @param listener A function that is called if the method fails
     * @see AsyncCallback
     * @see AckListener
     */
    public void getNativeId(final AckListener listener) {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
        } catch (JSONException e) {
            logger.error("Error setting nativeId", e);
        }
        connection.sendAction("get-window-native-id", payload, listener, this);
    }


    /**
     * Attaches a Window object to an application Window that already exists
     * @param applicationUuid UUID of the parent Application
     * @param windowName name of the Window
     * @param connection Connection object to the AppDesktop
     * @return Window instance
     */
    public static Window wrap(String applicationUuid, String windowName, DesktopConnection connection) {
        return new Window(applicationUuid, windowName, connection);
    }

    /**
     * Joins the same window group as the specified window
     * When windows are joined, if the user moves one of the windows,
     * all other windows in the same group move too. This function is
     * to be used when docking to other windows. If the window is
     * already within a group, it will leave that group to join the
     * new one. Windows must be owned by the same application in order
     * to be joined.
     *
     * @param window The window whose group is to be joined
     * @throws DesktopException if this window fails to join a group
     */
    public void joinGroup(Window window) throws DesktopException  {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
            payload.put("groupingUuid", window.uuid);
            payload.put("groupingWindowName", window.name);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("join-window-group", payload);
    }

    /**
     * Joins the same window group as the specified window
     *
     * @param window The window whose group is to be joined
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void joinGroup(Window window, AckListener listener)
    {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
            payload.put("groupingUuid", window.uuid);
            payload.put("groupingWindowName", window.name);
        } catch (JSONException e) {
            logger.error("Error joining group", e);
        }
        connection.sendAction("join-window-group", payload, listener, this);
    }

    /**
     * Merges the instance's window group with the same window group as the specified window.
     *    When windows are joined, if the user moves one of the windows,
     *    all other windows in the same group move too. This function is
     *    to be used when docking to other windows. If the window is
     *    already within a group, The two groups are joined to create a
     *    new one. Windows must be owned by the same application in order
     *    to be joined.
     * @param window The window whose group is to be merged
     * @throws DesktopException if this window fails to merge into a group
     * @see DesktopException
     *
     */
    public void mergeGroups(Window window) throws DesktopException {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
            payload.put("groupingUuid", window.uuid);
            payload.put("groupingWindowName", window.name);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("merge-window-groups", payload);
    }

    /**
     * Merges the instance's window group with the same window group as the specified window.
     *    When windows are joined, if the user moves one of the windows,
     *    all other windows in the same group move too. This function is
     *    to be used when docking to other windows. If the window is
     *    already within a group, The two groups are joined to create a
     *    new one. Windows must be owned by the same application in order
     *    to be joined.
     * @param window The window whose group is to be merged
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void mergeGroups(Window window, AckListener listener)
    {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
            payload.put("groupingUuid", window.uuid);
            payload.put("groupingWindowName", window.name);
        } catch (JSONException e) {
            DesktopUtils.errorAckOnException(listener, payload, e);
        }
        connection.sendAction("merge-window-groups", payload, listener, this);
    }

    /**
     * Leaves the current window group so that the window
     * can be move independently of those in the group.
     *
     * @throws DesktopException if this window fails to leave a group
     *
     */
    public void leaveGroup() throws DesktopException {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
        } catch (JSONException e) {
            throw new DesktopException(e);
        }
        connection.sendAction("leave-window-group", payload);
    }

    /**
     * Leaves the current window group so that the window
     * can be move independently of those in the group.
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void leaveGroup(AckListener listener)
    {
        JSONObject payload = new JSONObject();
        try {
            payload.put("uuid", uuid);
            payload.put("name", name);
        } catch (JSONException e) {
            logger.error("Error leaving group", e);
        }
        connection.sendAction("leave-window-group", payload, listener, this);
    }

    /**
     * Performs the specified window transitions
     * @param transitions Describes the animations to preform
     * @see AnimationTransitions
     * @param options Options for the animation
     * @see AnimationOptions
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void animate(AnimationTransitions transitions, AnimationOptions options, AckListener listener) {
        JSONObject animationPayload = new JSONObject();
        try {
            animationPayload.put("uuid", this.uuid);
            animationPayload.put("name", this.name);
            if (transitions != null) {
                animationPayload.put("transitions", transitions.toJsonObject());
            }
            if (options != null) {
                animationPayload.put("options", options.getOptions());
            }
            this.connection.sendAction("animate-window", animationPayload, listener, this);
        } catch (Exception e) {
            logger.error("Error animating", e);
        }
    }

    /**
     * Passes a list of wrapped windows in the same group
     * An empty list is returned if the window is not in a group.
     * The calling window is included in the resulting List.
     * @param groupHandler A class that receives a list of wrapped windows in the same group.
     * @see AsyncCallback
     * @param listener AckListener for the request
     * @see AckListener
     */
    public void getGroup(final AsyncCallback> groupHandler, final AckListener listener) {
        if (groupHandler != null) {
            JSONObject payload = new JSONObject();
            payload.put("uuid", this.uuid);
            payload.put("name", this.name);
            payload.put("crossApp", true); // cross app group supported
            connection.sendAction("get-window-group", payload, new AckListener() {
                @Override
                public void onSuccess(Ack ack) {
                    List list = new ArrayList();
                    try {
                        JSONObject value = ack.getJsonObject();
                        if (value != null) {
                            JSONArray array = value.getJSONArray("data");
                            for (int i = 0; i < array.length(); i++) {
                                JSONObject item = array.getJSONObject(i);
                                list.add(Window.wrap(item.getString("uuid"), item.getString("windowName"), connection));
                            }
                        }
                        groupHandler.onSuccess(list);
                    } catch (Exception e) {
                        logger.error("Error processing group", e);
                    }
                }

                @Override
                public void onError(Ack ack) {
                    DesktopUtils.errorAck(listener, ack);
                }
            }, this);
        }


    }

    /**
     * Helper method for adding event listener
     * @param subscriptionObject A JSON object containing subscription information such as the topic and type
     * @param listener Listener for the event
     * @see EventListener
     * @param callback AckListener for the request
     * @see AckListener
     */
    private void addEventListener(JSONObject subscriptionObject, EventListener listener, AckListener callback) {
        this.connection.addEventCallback(subscriptionObject, listener, callback, this);
    }

    /**
     *
     * Registers an event listener on the specified event
     *
     * 
     *     Supported window event types are:
     *
     *         app-connected       same as connected. @Deprecated
     *         app-loaded          same as connected. @Deprecated
     *         blurred
     *         bounds-changed
     *         bounds-changing
     *         closed
     *         close-requested
     *         disabled-frame-bounds-changed
     *         disabled-frame-bounds-changing
     *         focused
     *         frame-disabled
     *         frame-enabled
     *         group-changed
     *         hidden
     *         maximized
     *         minimized
     *         connected        (this window is connected to Runtime with javascript API)
     *         restored
     *         shown
     * 
* * @param type Event type * @param listener Listener for the event * @see EventListener * @param callback AckListener for the request * @see AckListener */ public void addEventListener(String type, EventListener listener, AckListener callback) { JSONObject eventListenerPayload = new JSONObject(); try { eventListenerPayload.put("uuid", getUuid()); eventListenerPayload.put("name", getName()); eventListenerPayload.put("topic", "window"); eventListenerPayload.put("type", type); addEventListener(eventListenerPayload, listener, callback); } catch (Exception e) { logger.error("Error adding eventListener", e); } } /** * Removes a previously registered event listener from the specified event * @param type Event type * @param listener Listener for the event * @see EventListener * @param callback AckListener for the request * @see AckListener */ public void removeEventListener(String type, EventListener listener, AckListener callback) { try { JSONObject eventListenerPayload = new JSONObject(); eventListenerPayload.put("uuid", getUuid()); eventListenerPayload.put("name", getName()); eventListenerPayload.put("topic", "window"); eventListenerPayload.put("type", type); this.connection.removeEventCallback(eventListenerPayload, listener, callback, this); } catch (Exception e) { logger.error("Error removing event listener", e); } } /** * Embeds a window in a target window * * @param parentHwndId This will be the parent window handle * @param width width of parent window * @param height height of parent window * @param callback AckListener for the request * @see AckListener */ public void embedInto(final long parentHwndId, final int width, final int height, final AckListener callback) { embedInto(parentHwndId, 0, 0, width, height, callback); } /** * Embeds a window in a target window * * @param parentHwndId This will be the parent window handle * @param left The new position of the left side of the window. * @param top The new position of the top of the window. * @param width width of parent window * @param height height of parent window * @param callback AckListener for the request * @see AckListener */ public void embedInto(final long parentHwndId, final int left, final int top, final int width, final int height, final AckListener callback) { this.parentHwndId = parentHwndId; this.getNativeId(new AckListener() { public void onSuccess(Ack ack) { String data = ack.getJsonObject().getString("data"); hwndId = Long.decode(data); WinMessageHelper.embedInto(Window.this.parentHwndId, hwndId, left, top, width, height, new AckListener() { public void onSuccess(Ack ack) { try { JSONObject targetObject = new JSONObject(); targetObject.put("uuid", uuid); targetObject.put("name", name); targetObject.put("parentHwnd", Long.toHexString(parentHwndId)); connection.sendAction("window-embedded", targetObject); Window.this.show(); Window.this.focus(); if (callback != null) { callback.onSuccess(ack); } } catch (Exception ex) { logger.error("Error registering embedded window", ex); } } public void onError(Ack ack) { if (callback != null) { callback.onError(ack); } } }); } public void onError(Ack ack) { if (callback != null) { callback.onError(ack); } } }); } /** * Executes Javascript on the window, restricted to windows you own or windows owned by applications you have created. * * @param code JavaScript code to be executed on the window * @param callback A function that is called if the method succeeds * @param listener A function that is called if the method fails * @see AsyncCallback * @see AckListener */ public void executeJavaScript(final String code, final AsyncCallback callback, final AckListener listener) { AckListener mainCallback = null; if(callback != null) { mainCallback = new AckListener() { @Override public void onSuccess(Ack ack) { try { JSONObject jsonObject = ack.getJsonObject(); if (jsonObject.has("data")) { Object data = jsonObject.get("data"); if (data == JSONObject.NULL) { callback.onSuccess(null); } else { callback.onSuccess(data); } } else { JSONObject payload = new JSONObject(); JsonUtils.updateValue(payload, "reason", "Missing data in response"); Ack ack2 = new Ack(payload, this); DesktopUtils.errorAck(listener, ack2); } } catch (Exception ex) { logger.error("Error calling onSuccess", ex); } } @Override public void onError(Ack ack) { DesktopUtils.errorAck(listener, ack); } } ; } JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); payload.put("code", code); connection.sendAction("execute-javascript-in-window", payload, mainCallback, this); } catch (Exception e) { logger.error("Error executing javascript", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Shows window's developer tools * * @param listener A function that is called if the method fails * @see AckListener */ public void showDeveloperTools(AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); connection.sendAction("show-developer-tools", payload, listener, this); } catch (Exception e) { logger.error("Error showing devtools", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Navigates the Widnow to the specified address * * @param url The URL that you want to navigate to * @param listener A function that is called if the method fails * @see AckListener */ public void navigate(String url, AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("targetUuid", getUuid()); payload.put("targetName", getName()); payload.put("url", url); connection.sendAction("redirect-window-to-url", payload, listener, this); } catch (Exception e) { logger.error("Error navigating", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Navigates the window forward one page. * @param listener A function that is called if the method fails * @see AckListener */ public void navigateForward(AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); connection.sendAction("navigate-window-forward", payload, listener, this); } catch (Exception e) { logger.error("Error navigating", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Navigates the window back one page. * @param listener A function that is called if the method fails * @see AckListener */ public void navigateBack(AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); connection.sendAction("navigate-window-back", payload, listener, this); } catch (Exception e) { logger.error("Error navigating", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Stops window navigation. * @param listener A function that is called if the method fails * @see AckListener */ public void stopWindowNavigation(AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); connection.sendAction("stop-window-navigation", payload, listener, this); } catch (Exception e) { logger.error("Error navigating", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * authenticate a user. * * @param username user name * @param password passwprd * @param cancel true to cancel the request * @param listener A function that is called if the method fails */ public void authenticate(String username, String password, boolean cancel, AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", getUuid()); payload.put("name", getName()); payload.put("userName", username); payload.put("password", password); payload.put("cancel", cancel); connection.sendAction("window-authenticate", payload, listener, this); } catch (Exception e) { logger.error("Error navigating", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Gets the window information * * @param code JavaScript code to be executed on the window * @param callback A function that is called if the method succeeds * @param listener A function that is called if the method fails * @see AsyncCallback * @see AckListener */ public void getInfo(final String code, final AsyncCallback callback, final AckListener listener) { AckListener mainCallback = null; if(callback != null) { mainCallback = new AckListener() { @Override public void onSuccess(Ack ack) { try { JSONObject jsonObject = ack.getJsonObject(); if (jsonObject.has("data")) { JSONObject data = jsonObject.getJSONObject("data"); callback.onSuccess(data); } else { JSONObject payload = new JSONObject(); JsonUtils.updateValue(payload, "reason", "Missing data in response"); Ack ack2 = new Ack(payload, this); DesktopUtils.errorAck(listener, ack2); } } catch (Exception ex) { logger.error("Error calling onSuccess", ex); } } @Override public void onError(Ack ack) { DesktopUtils.errorAck(listener, ack); } } ; } try { connection.sendAction("get-window-info", null, listener, this); } catch (Exception e) { logger.error("Error executing javascript", e); DesktopUtils.errorAckOnException(listener, this, e); } } /** * Update width and height of parent window for embedded window * * @param width width of parent window * @param height height of parent window */ public void embedComponentSizeChange(final int width, final int height) { embedComponentSizeChange(0, 0, width, height); } /** * Update width and height of parent window for embedded window * * @param left The new position of the left side of the window. * @param top The new position of the top of the window. * @param width width of parent window * @param height height of parent window */ public void embedComponentSizeChange(final int left, final int top, final int width, final int height) { if (parentHwndId > 0) { WinMessageHelper.embededViewSizeChange(this.parentHwndId, this.hwndId, left, top, width, height); } } /** * Gets the current zoom level of the window * * @param callback A function that is called if the method succeeds * @param listener A function that is called if the method fails * @see AsyncCallback * @see AckListener */ public void getZoomLevel(final AsyncCallback callback, final AckListener listener) { AckListener mainCallback = null; if(callback != null) { mainCallback = new AckListener() { @Override public void onSuccess(Ack ack) { try { Double level = Double.parseDouble(ack.getData().toString()); callback.onSuccess(level); } catch (Exception ex) { logger.error("Error calling onSuccess", ex); } } @Override public void onError(Ack ack) { DesktopUtils.errorAck(listener, ack); } } ; } connection.sendAction("get-zoom-level", noParamPayload, mainCallback, this); } /** * Sets the zoom level of the window * * @param level The zoom level. * @param listener AckListener for the request * @see AckListener */ public void setZoomLevel(double level, AckListener listener) { JSONObject payload = new JSONObject(); try { payload.put("uuid", uuid); payload.put("name", name); payload.put("level", level); connection.sendAction("set-zoom-level", payload, listener, this); } catch (Exception e) { logger.error("Error setting zoom level", e); DesktopUtils.errorAckOnException(listener, payload, e); } } /** * Reloads the window current page * * @param ignoreCache * Specifies if the cache should be ignored during page reload * @param listener * AckListener for the request * @see AckListener */ public void reload(boolean ignoreCache, AckListener listener) { JSONObject payload = new JSONObject(); payload.put("uuid", uuid); payload.put("name", name); payload.put("ignoreCache", ignoreCache); connection.sendAction("reload-window", payload, listener, this); } }