DesktopApplicationContext.java :  » Ajax » apache-pivot-1.4 » org » apache » pivot » wtk » Java Open Source

Java Open Source » Ajax » apache pivot 1.4 
apache pivot 1.4 » org » apache » pivot » wtk » DesktopApplicationContext.java
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.pivot.wtk;

import java.awt.AWTEvent;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.collections.immutable.ImmutableMap;
import org.apache.pivot.wtk.media.Image;
import org.apache.pivot.wtk.media.Picture;

/**
 * Application context used to execute applications in a native frame
 * window.
 */
public final class DesktopApplicationContext extends ApplicationContext {
    private static class HostFrame extends java.awt.Frame {
        private static final long serialVersionUID = 5340356674429280196L;

        private HostFrame() {
            enableEvents(AWTEvent.WINDOW_EVENT_MASK
                | AWTEvent.WINDOW_STATE_EVENT_MASK);

            // Disable focus traversal keys
            setFocusTraversalKeysEnabled(false);

            // Clear the background
            setBackground(null);
        }

        @Override
        public void update(Graphics graphics) {
            paint(graphics);
        }

        @Override
        public void processWindowEvent(WindowEvent event) {
            super.processWindowEvent(event);

            if (this == windowedHostFrame) {
                switch(event.getID()) {
                    case WindowEvent.WINDOW_OPENED: {
                        addDisplay(applicationContext.getDisplay());
                        createTimer();

                        // Load the application
                        Application application = null;
                        try {
                            Class<?> applicationClass = Class.forName(applicationClassName);
                            application = (Application)applicationClass.newInstance();
                            applicationContext.setApplication(application);
                        } catch(Exception exception) {
                            Alert.alert(MessageType.ERROR, exception.getMessage(),
                                applicationContext.getDisplay());
                            exception.printStackTrace();
                        }

                        // Set focus to the display host
                        DisplayHost displayHost = applicationContext.getDisplayHost();
                        displayHost.requestFocus();

                        // Start the application
                        if (application != null) {
                            try {
                                application.startup(applicationContext.getDisplay(),
                                    new ImmutableMap<String, String>(properties));
                            } catch(Exception exception) {
                                displayException(exception);
                            }

                            // Add the application to the application list
                            addApplication(application);

                            // Hook into OS X application menu
                            String osName = System.getProperty("os.name");
                            if (osName.toLowerCase().startsWith("mac os x")) {
                                try {
                                    // Get the EAWT classes and methods
                                    Class<?> eawtApplicationClass = Class.forName("com.apple.eawt.Application");
                                    Class<?> eawtApplicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
                                    Class<?> eawtApplicationEventClass = Class.forName("com.apple.eawt.ApplicationEvent");

                                    Method setEnabledAboutMenuMethod = eawtApplicationClass.getMethod("setEnabledAboutMenu",
                                        new Class<?>[] {Boolean.TYPE});

                                    Method addApplicationListenerMethod = eawtApplicationClass.getMethod("addApplicationListener",
                                        new Class<?>[] {eawtApplicationListenerClass});

                                    final Method setHandledMethod = eawtApplicationEventClass.getMethod("setHandled",
                                        new Class<?>[] {Boolean.TYPE});

                                    // Create the proxy handler
                                    InvocationHandler handler = new InvocationHandler() {
                                    @Override
                                        public Object invoke(Object proxy, Method method, Object[] args)
                                            throws Throwable {
                                            boolean handled = true;

                                            String methodName = method.getName();
                                            if (methodName.equals("handleAbout"))  {
                                                handleAbout();
                                            } else if (methodName.equals("handleQuit")) {
                                                handled = !exit();
                                            }

                                            // Invoke setHandled()
                                            setHandledMethod.invoke(args[0], new Object[] {handled});

                                            return null;
                                        }
                                    };

                                    Object eawtApplication = eawtApplicationClass.newInstance();

                                    setEnabledAboutMenuMethod.invoke(eawtApplication,
                                        application instanceof Application.AboutHandler);

                                    Object eawtApplicationListener =
                                        Proxy.newProxyInstance(DesktopApplicationContext.class.getClassLoader(),
                                            new Class<?>[]{eawtApplicationListenerClass}, handler);

                                    // Invoke the addApplicationListener() method with the proxy listener
                                    addApplicationListenerMethod.invoke(eawtApplication, new Object[] {eawtApplicationListener});
                                } catch(Throwable throwable) {
                                    throwable.printStackTrace(System.err);
                                }
                            }
                        }

                        break;
                    }

                    case WindowEvent.WINDOW_CLOSING: {
                        exit();
                        break;
                    }

                    case WindowEvent.WINDOW_CLOSED: {
                        removeDisplay(applicationContext.getDisplay());
                        destroyTimer();
                        System.exit(0);
                        break;
                    }

                    case WindowEvent.WINDOW_DEACTIVATED: {
                        java.awt.Window oppositeWindow = event.getOppositeWindow();

                        if (oppositeWindow instanceof java.awt.Dialog) {
                            java.awt.Dialog dialog = (java.awt.Dialog)oppositeWindow;

                            switch (dialog.getModalityType()) {
                            case APPLICATION_MODAL:
                            case DOCUMENT_MODAL:
                            case TOOLKIT_MODAL:
                                applicationContext.getDisplay().setEnabled(false);

                                dialog.addWindowListener(new WindowAdapter() {
                                    @Override
                                    public void windowClosed(WindowEvent event) {
                                        applicationContext.getDisplay().setEnabled(true);
                                        event.getWindow().removeWindowListener(this);
                                    }
                                });

                                break;
                            }
                        }

                        break;
                    }
                }
            }
        }

        @Override
        protected void processWindowStateEvent(WindowEvent event) {
            super.processWindowStateEvent(event);

            if (this == windowedHostFrame) {
                Application application = applicationContext.getApplication();

                switch(event.getID()) {
                    case WindowEvent.WINDOW_ICONIFIED: {
                        try {
                            application.suspend();
                        } catch(Exception exception) {
                            displayException(exception);
                        }

                        break;
                    }

                    case WindowEvent.WINDOW_DEICONIFIED: {
                        try {
                            application.resume();
                        } catch(Exception exception) {
                            displayException(exception);
                        }

                        break;
                    }
                }
            }
        }
    }

    private static DesktopApplicationContext applicationContext = null;
    private static String applicationClassName = null;
    private static HashMap<String, String> properties = null;

    private static HostFrame windowedHostFrame = null;
    private static HostFrame fullScreenHostFrame = null;

    private static Runnable updateFrameTitleBarCallback = null;

    private static final String DEFAULT_HOST_FRAME_TITLE = "Apache Pivot";

    private static final String X_ARGUMENT = "x";
    private static final String Y_ARGUMENT = "y";
    private static final String WIDTH_ARGUMENT = "width";
    private static final String HEIGHT_ARGUMENT = "height";
    private static final String CENTER_ARGUMENT = "center";
    private static final String RESIZABLE_ARGUMENT = "resizable";

    private static final String FULL_SCREEN_ARGUMENT = "fullScreen";

    /**
     * Terminates the application context.
     */
    public static boolean exit() {
        boolean cancelShutdown = false;

        Application application = applicationContext.getApplication();
        if (application != null) {
            try {
                cancelShutdown = application.shutdown(true);
            } catch(Exception exception) {
                displayException(exception);
            }

            if (!cancelShutdown) {
                // Remove the application from the application list
                removeApplication(application);
            }
        }

        if (!cancelShutdown) {
            if (windowedHostFrame.getExtendedState() == 0) {
                try {
                    Preferences preferences = Preferences.userNodeForPackage(DesktopApplicationContext.class);
                    preferences = preferences.node(applicationClassName);

                    preferences.putInt(X_ARGUMENT, windowedHostFrame.getX());
                    preferences.putInt(Y_ARGUMENT, windowedHostFrame.getY());
                    preferences.putInt(WIDTH_ARGUMENT, windowedHostFrame.getWidth());
                    preferences.putInt(HEIGHT_ARGUMENT, windowedHostFrame.getHeight());

                    preferences.flush();
                } catch (SecurityException exception) {
                    // No-op
                } catch (BackingStoreException exception) {
                    // No-op
                }
            }

            windowedHostFrame.dispose();
            fullScreenHostFrame.dispose();
        }

        return cancelShutdown;
    }

    /**
     * Primary aplication entry point.
     *
     * @param args
     */
    public static void main(String[] args) {
        if (applicationContext != null) {
            throw new IllegalStateException();
        }

        // Get the application class name
        if (args.length == 0) {
            System.err.println("Application class name is required.");
            return;
        }

        applicationClassName = args[0];

        // Get the startup properties
        properties = new HashMap<String, String>();

        int x = 0;
        int y = 0;
        int width = 800;
        int height = 600;
        boolean center = false;
        boolean resizable = true;
        boolean fullScreen = false;

        try {
            Preferences preferences = Preferences.userNodeForPackage(DesktopApplicationContext.class);
            preferences = preferences.node(applicationClassName);

            x = preferences.getInt(X_ARGUMENT, x);
            y = preferences.getInt(Y_ARGUMENT, y);
            width = preferences.getInt(WIDTH_ARGUMENT, width);
            height = preferences.getInt(HEIGHT_ARGUMENT, height);
        } catch (SecurityException exception) {
            System.err.println("Unable to retrieve startup preferences: " + exception);
        }

        for (int i = 1, n = args.length; i < n; i++) {
            String arg = args[i];

            if (!arg.startsWith("--")) {
                throw new IllegalArgumentException("Startup property names must begin with \"--\".");
            }

            arg = arg.substring(2);
            String[] property = arg.split("=");

            if (property.length == 2) {
                String key = property[0];
                String value = property[1];

                try {
                    if (key.equals(X_ARGUMENT)) {
                        x = Integer.parseInt(value);
                    } else if (key.equals(Y_ARGUMENT)) {
                        y = Integer.parseInt(value);
                    } else if (key.equals(WIDTH_ARGUMENT)) {
                        width = Integer.parseInt(value);
                    } else if (key.equals(HEIGHT_ARGUMENT)) {
                        height = Integer.parseInt(value);
                    } else if (key.equals(CENTER_ARGUMENT)) {
                        center = Boolean.parseBoolean(value);
                    } else if (key.equals(RESIZABLE_ARGUMENT)) {
                        resizable = Boolean.parseBoolean(value);
                    } else if (key.equals(FULL_SCREEN_ARGUMENT)) {
                        fullScreen = Boolean.parseBoolean(value);
                    } else {
                        properties.put(key, value);
                    }
                } catch (NumberFormatException exception) {
                    System.err.println("Warning: " + exception.getClass().getSimpleName() + ": " +
                        exception.getLocalizedMessage());
                }
            } else {
                System.err.println(arg + " is not a valid startup property.");
            }
        }

        // Set the origin
        try {
            // Load the JNLP classes dynamically because they are only available
            // when run via javaws
            Class<?> serviceManagerClass = Class.forName("javax.jnlp.ServiceManager");
            Method lookupMethod = serviceManagerClass.getMethod("lookup", String.class);
            Object basicService = lookupMethod.invoke(null, "javax.jnlp.BasicService");

            Class<?> basicServiceClass = Class.forName("javax.jnlp.BasicService");
            Method getCodeBaseMethod = basicServiceClass.getMethod("getCodeBase");
            URL codeBase = (URL)getCodeBaseMethod.invoke(basicService);

            if (codeBase != null) {
                origin = new URL(codeBase.getProtocol(), codeBase.getHost(), codeBase.getPort(), "");
            }
        } catch (Exception exception) {
            // No-op
        }

        if (origin == null) {
            // Could not obtain origin from JNLP; use user's home directory
            File userHome = new File(System.getProperty("user.home"));

            try {
                origin = userHome.toURI().toURL();
            } catch(MalformedURLException exception) {
                // No-op
            }
        }

        // Create the application context
        applicationContext = new DesktopApplicationContext();
        DisplayHost displayHost = applicationContext.getDisplayHost();

        // Create the windowed host frame
        windowedHostFrame = new HostFrame();
        windowedHostFrame.add(displayHost);

        windowedHostFrame.setTitle(DEFAULT_HOST_FRAME_TITLE);
        windowedHostFrame.setSize(width, height);
        windowedHostFrame.setResizable(resizable);

        if (center) {
            java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
            windowedHostFrame.setLocation((screenSize.width - width) / 2,
                (screenSize.height - height) / 2);
        } else {
            windowedHostFrame.setLocation(x, y);
        }

        applicationContext.getDisplay().getContainerListeners().add(new ContainerListener.Adapter() {
            @Override
            public void componentInserted(Container container, int index) {
                if (index == container.getLength() - 1) {
                    topWindowChanged((Display)container,
                        (index > 0) ? (Window)container.get(index - 1) : null);
                }
            }

            @Override
            public void componentsRemoved(Container container, int index,
                Sequence<Component> removed) {
                if (index == container.getLength()) {
                    topWindowChanged((Display)container,
                        (Window)removed.get(removed.getLength() - 1));
                }
            }

            @Override
            public void componentMoved(Container container, int from, int to) {
                int n = container.getLength();
                if (from == n) {
                    topWindowChanged((Display)container, (Window)container.get(from));
                } else if (to == n) {
                    topWindowChanged((Display)container, (Window)container.get(n - 1));
                }
            }

            private void topWindowChanged(Display display, Window previousTopWindow) {
                if (updateFrameTitleBarCallback == null) {
                    updateFrameTitleBarCallback = new Runnable() {
                        @Override
                        public void run() {
                            Display display = applicationContext.getDisplay();
                            int n = display.getLength();

                            if (n == 0) {
                                windowedHostFrame.setTitle(DEFAULT_HOST_FRAME_TITLE);
                                windowedHostFrame.setIconImage(null);
                            } else {
                                Window topWindow = (Window)display.get(n - 1);
                                Window rootOwner = topWindow.getRootOwner();
                                updateFrameTitleBar(rootOwner);
                            }

                            updateFrameTitleBarCallback = null;
                        }
                    };

                    queueCallback(updateFrameTitleBarCallback);
                }
            }
        });

        // Add a key listener to the display host to toggle between full-screen
        // and windowed mode
        displayHost.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent keyEvent) {
                if (keyEvent.getKeyCode() == KeyEvent.VK_F
                    && (keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) > 0
                    && (keyEvent.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) > 0) {
                    setFullScreen(!isFullScreen());
                }
            }
        });

        // Create the full-screen host frame
        fullScreenHostFrame = new HostFrame();
        fullScreenHostFrame.setUndecorated(true);

        // Open the windowed host
        windowedHostFrame.setVisible(true);

        // Go to full-screen mode, if requested
        setFullScreen(fullScreen);
    }

    private static void updateFrameTitleBar(Window rootOwner) {
        windowedHostFrame.setTitle(rootOwner.getTitle());

        Image icon = rootOwner.getIcon();
        if (icon instanceof Picture) {
            Picture rootPicture = (Picture)icon;
            windowedHostFrame.setIconImage(rootPicture.getBufferedImage());
        }
    }

    private static void displayException(Exception exception) {
        exception.printStackTrace();

        String message = exception.getClass().getName();

        Label body = null;
        String bodyText = exception.getMessage();
        if (bodyText != null
            && bodyText.length() > 0) {
            body = new Label(bodyText);
            body.getStyles().put("wrapText", true);
        }

        Alert.alert(MessageType.ERROR, message, body, applicationContext.getDisplay());
    }

    /**
     * Invokes the application's about handler. The application must implement
     * the {@link Application.AboutHandler} interface.
     */
    public static void handleAbout() {
        Application application = applicationContext.getApplication();
        Application.AboutHandler aboutHandler = (Application.AboutHandler)application;
        aboutHandler.aboutRequested();
    }

    /**
     * Returns the full-screen mode flag.
     */
    public static boolean isFullScreen() {
        return (!windowedHostFrame.isVisible());
    }

    /**
     * Sets the full-screen mode flag.
     *
     * @param fullScreen
     */
    public static void setFullScreen(boolean fullScreen) {
        if (fullScreen != isFullScreen()) {
            DisplayHost displayHost = applicationContext.getDisplayHost();

            GraphicsDevice graphicsDevice =
                windowedHostFrame.getGraphicsConfiguration().getDevice();

            if (fullScreen) {
                // Go to full screen mode
                windowedHostFrame.remove(displayHost);
                windowedHostFrame.setVisible(false);

                fullScreenHostFrame.add(displayHost);
                fullScreenHostFrame.setVisible(true);

                graphicsDevice.setFullScreenWindow(fullScreenHostFrame);

            } else {
                // Go to windowed mode
                try {
                    graphicsDevice.setFullScreenWindow(null);
                } catch (Exception exception) {
                    // TODO remove this catch. On Win32 platforms, the
                    // preceding call can throw.
                }

                fullScreenHostFrame.remove(displayHost);
                fullScreenHostFrame.setVisible(false);

                windowedHostFrame.add(displayHost);
                windowedHostFrame.setVisible(true);
            }

            displayHost.requestFocus();
        }
    }

    public static void sizeToFit(Window window) {
        if (window == null) {
            throw new IllegalArgumentException();
        }

        if (applicationContext == null) {
            throw new IllegalStateException("Desktop application context is not active.");
        }

        if (isFullScreen()) {
            setFullScreen(false);
        }

        Dimensions size = window.getPreferredSize();
        java.awt.Insets frameInsets = windowedHostFrame.getInsets();
        windowedHostFrame.setSize(size.width + (frameInsets.left + frameInsets.right),
            size.height + (frameInsets.top + frameInsets.bottom));
    }

    /**
     * Utility method to make it easier to define <tt>main()</tt> entry-points
     * into applications. For example:
     *
     * <code>
     * public class MyApp implements Application {
     *   public static void main(String[] args) throws Exception {
     *     DesktopApplicationContext.main(MyApp.class, args);
     *   }
     * }
     * </code>
     *
     * @param applicationClass
     * @param applicationArgs
     */
    public static final void main(Class<? extends Application> applicationClass,
        String[] applicationArgs) {
        String[] args = new String[applicationArgs.length + 1];
        System.arraycopy(applicationArgs, 0, args, 1, applicationArgs.length);
        args[0] = applicationClass.getName();
        main(args);
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.