components/visual-panels/core/src/java/vpanels/panel/com/oracle/solaris/vp/panel/swing/control/SystemTrayControl.java
changeset 827 0944d8c0158b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/visual-panels/core/src/java/vpanels/panel/com/oracle/solaris/vp/panel/swing/control/SystemTrayControl.java	Thu May 24 04:16:47 2012 -0400
@@ -0,0 +1,414 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package com.oracle.solaris.vp.panel.swing.control;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.net.URL;
+import java.util.Map;
+import java.util.logging.Level;
+import javax.help.HelpSet;
+import com.oracle.solaris.vp.panel.common.*;
+import com.oracle.solaris.vp.panel.common.action.ActionAbortedException;
+import com.oracle.solaris.vp.panel.common.control.*;
+import com.oracle.solaris.vp.panel.common.model.PanelDescriptor;
+import com.oracle.solaris.vp.panel.swing.view.AuthPanel;
+import com.oracle.solaris.vp.util.misc.finder.Finder;
+
+public class SystemTrayControl<P extends PanelDescriptor>
+    extends SwingControl<P, Component> implements ConnectionListener,
+    ActionListener, MouseListener, MouseMotionListener {
+
+    //
+    // Instance data
+    //
+
+    private TrayIcon trayIcon;
+    private PopupMenu popup;
+
+    //
+    // Constructors
+    //
+
+    public SystemTrayControl(String id, String name, ClientContext context) {
+	super(id, name, context);
+    }
+
+    public SystemTrayControl(String id, String name, P descriptor) {
+	super(id, name, descriptor);
+    }
+
+    //
+    // ConnectionListener methods
+    //
+
+    @Override
+    public void connectionChanged(ConnectionEvent event) {
+	if (popup != null) {
+	    String text = AuthPanel.toString(
+		getClientContext().getConnectionInfo(), true);
+	    popup.setLabel(text);
+	}
+    }
+
+    @Override
+    public void connectionFailed(ConnectionEvent event) {
+        // There's nothing particularly helpful we can do here except wait for
+        // the repaired connection in connectionChanged
+    }
+
+    //
+    // ActionListener methods
+    //
+
+    /**
+     * As a convenience, this class is added as an {@code ActionListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void actionPerformed(ActionEvent e) {
+    }
+
+    //
+    // MouseListener methods
+    //
+
+    /**
+     * As a convenience, this class is added as an {@code MouseListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void mouseClicked(MouseEvent e) {
+    }
+
+    /**
+     * As a convenience, this class is added as an {@code MouseListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void mousePressed(MouseEvent e) {
+    }
+
+    /**
+     * As a convenience, this class is added as an {@code MouseListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void mouseReleased(MouseEvent e) {
+    }
+
+    /**
+     * As a convenience, this class is added as an {@code MouseListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void mouseEntered(MouseEvent e) {
+    }
+
+    /**
+     * As a convenience, this class is added as an {@code MouseListener} to the
+     * {@link #createTrayIcon created} {@code TrayIcon}.  This method provides a
+     * default empty implementation.
+     */
+    @Override
+    public void mouseExited(MouseEvent e) {
+    }
+
+    //
+    // MouseMotionListener methods
+    //
+
+    /**
+     * As a convenience, this class is added as an {@code MouseMotionListener}
+     * to the {@link #createTrayIcon created} {@code TrayIcon}.  This method
+     * provides a default empty implementation.
+     */
+    @Override
+    public void mouseDragged(MouseEvent e) {
+    }
+
+    /**
+     * As a convenience, this class is added as an {@code MouseMotionListener}
+     * to the {@link #createTrayIcon created} {@code TrayIcon}.  This method
+     * provides a default empty implementation.
+     */
+    @Override
+    public void mouseMoved(MouseEvent e) {
+    }
+
+    //
+    // Control methods
+    //
+
+    /**
+     * Calls the superclass implementation and {@link #getTrayIconCreate
+     * creates} this {@code SystemTrayControl}'s {@code TrayIcon} if necessary.
+     */
+    @Override
+    public void start(Navigator navigator, Map<String, String> parameters)
+	throws NavigationAbortedException, InvalidParameterException,
+	NavigationFailedException {
+
+	super.start(navigator, parameters);
+
+	SystemTray tray;
+
+	try {
+	    tray = SystemTray.getSystemTray();
+	} catch (UnsupportedOperationException e) {
+	    throw new NavigationAbortedException(e);
+	}
+
+	trayIcon = getTrayIconCreate(tray);
+
+	try {
+	    tray.add(trayIcon);
+
+	// Shouldn't happen
+	} catch (AWTException e) {
+	    throw new NavigationAbortedException(e);
+	}
+
+	ClientContext context = getClientContext();
+	context.addConnectionListener(this);
+	connectionChanged(null);
+    }
+
+    @Override
+    public void stop(boolean isCancel) throws NavigationAbortedException {
+	super.stop(isCancel);
+
+	ClientContext context = getClientContext();
+	context.removeConnectionListener(this);
+
+	try {
+	    SystemTray.getSystemTray().remove(trayIcon);
+	} catch (UnsupportedOperationException e) {
+	    getLog().log(Level.WARNING, "system tray no longer accessible!", e);
+	}
+    }
+
+    //
+    // SystemTrayControl methods
+    //
+
+    /**
+     * Configures the just-{@code #createTrayIcon created} {@code TrayIcon} for
+     * this {@code SystemTrayControl}.	This method is called automatically just
+     * after {@link #createTrayIcon}.
+     * <p/>
+     * Most subclasses can do all configuration in {@link #createTrayIcon}.
+     * Only implementors that wish to provide a common configuration for all
+     * {@code TrayIcon}s created by their subclasses need to implement this
+     * method.
+     * <p/>
+     * Subclasses that override this method should call {@code
+     * super.configTrayIcon(trayIcon)} to ensure that any present or future
+     * functionality in any superclass implementation is executed.
+     * <p/>
+     * This default implementation adds a {@link #getPopupMenu popup menu} (if
+     * non-null), then adds this class as an {@code ActionListener}, {@code
+     * MouseListener}, and {@code MouseMotionListener} to the {@code TrayIcon}.
+     *
+     * @param	    trayIcon
+     *		    the newly-created {@code TrayIcon}
+     */
+    protected void configTrayIcon(TrayIcon trayIcon) {
+	PopupMenu popup = getPopupMenu();
+	if (popup != null) {
+	    trayIcon.setPopupMenu(popup);
+	}
+
+	trayIcon.addActionListener(this);
+	trayIcon.addMouseListener(this);
+	trayIcon.addMouseMotionListener(this);
+    }
+
+    /**
+     * Creates the {@code TrayIcon} for this {@code SystemTrayControl}.
+     * <p/>
+     * This default implementation does nothing and returns {@code null}.
+     *
+     * @return	    the newly-created {@code TrayIcon}
+     */
+    protected TrayIcon createTrayIcon(SystemTray tray) {
+	return null;
+    }
+
+    /**
+     * Gets, creating if necessary, a {@code PopupMenu} to display when the
+     * {@link #getTrayIcon system tray icon} is clicked. This popup menu shall
+     * include {@link #createLoginItem login}, {@link #createHelpItem help},
+     * and {@link #createExitItem exit}, menu items.
+     *
+     * @return	    a {@code PopupMenu}, or {@code null} to display no popop
+     */
+    protected PopupMenu getPopupMenu() {
+	if (popup == null) {
+	    popup = new PopupMenu();
+
+	    MenuItem loginItem = createLoginItem();
+	    MenuItem helpItem = createHelpItem();
+	    MenuItem exitItem = createExitItem();
+
+	    if (loginItem != null) {
+		popup.add(loginItem);
+	    }
+	    if (helpItem != null) {
+		popup.add(helpItem);
+	    }
+	    if (exitItem != null) {
+		popup.add(exitItem);
+	    }
+	}
+	return popup;
+    }
+
+    /**
+     * Creates a login {@code MenuItem} object for use with the
+     * {@link #getTrayIcon system tray icon} popup menu.
+     *
+     * @return	    a {@code MenuItem}, or {@code null} to display no item
+     */
+    protected MenuItem createLoginItem() {
+	MenuItem loginItem = new MenuItem(Finder.getString("tray.popup.login"));
+	loginItem.addActionListener(
+	    new ActionListener() {
+		@Override
+		public void actionPerformed(ActionEvent e) {
+		    PanelFrameControl.promptForLogin(getClientContext());
+		}
+	    });
+	return loginItem;
+    }
+
+    /**
+     * Creates a help {@code MenuItem} object for use with the
+     * {@link #getTrayIcon system tray icon} popup menu.
+     *
+     * @return	    a {@code MenuItem}, or {@code null} to display no item
+     */
+    protected MenuItem createHelpItem() {
+	MenuItem helpItem = null;
+	HelpSet helpSet = getPanelDescriptor().getHelpSet();
+	if (helpSet != null) {
+	    final URL url = getHelpURL(helpSet);
+	    if (url != null) {
+		helpItem = new MenuItem(Finder.getString("tray.popup.help"));
+		helpItem.addActionListener(
+		    new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+			    ClientContext context = getClientContext();
+			    context.getHelpBroker().setCurrentURL(url);
+			    context.showHelp();
+			}
+		    });
+	    }
+	}
+        return helpItem;
+    }
+
+    /**
+     * Creates a exit {@code MenuItem} object for use with the
+     * {@link #getTrayIcon system tray icon} popup menu.
+     *
+     * @return	    a {@code MenuItem}, or {@code null} to display no item
+     */
+    protected MenuItem createExitItem() {
+	MenuItem exitItem = new MenuItem(Finder.getString("tray.popup.exit"));
+	exitItem.addActionListener(
+	    new ActionListener() {
+		@Override
+		public void actionPerformed(ActionEvent e) {
+		    getNavigator().asyncExec(
+			new Runnable() {
+			    @Override
+			    public void run() {
+				try {
+				    getClientContext().closeInstance(true);
+				} catch (ActionAbortedException ignore) {
+				}
+			    }
+			});
+		}
+	    });
+	return exitItem;
+    }
+
+    /**
+     * Gets the {@code TrayIcon} for this {@code SystemTrayControl}.
+     *
+     * @return	    a {@code TrayIcon}, or {@code null} if this {@code
+     *		    SystemTrayControl} has no {@code TrayIcon}.
+     *
+     * @see	    #setTrayIcon
+     */
+    public TrayIcon getTrayIcon() {
+	return trayIcon;
+    }
+
+    /**
+     * Gets the {@code TrayIcon} for this {@code SystemTrayControl}, {@link
+     * #createTrayIcon creating} it and {@code #setTrayIcon setting} it first if
+     * necessary.
+     * <p/>
+     * This method is not thread-safe; external locking may be necessary to
+     * ensure that {@link #createTrayIcon} is not called by multiple threads.
+     *
+     * @return	    a {@code TrayIcon}, or {@code null} if this {@code
+     *		    SystemTrayControl} has no {@code TrayIcon}.
+     */
+    public TrayIcon getTrayIconCreate(SystemTray tray) {
+	TrayIcon trayIcon = getTrayIcon();
+	if (trayIcon == null) {
+	    trayIcon = createTrayIcon(tray);
+	    if (trayIcon != null) {
+		setTrayIcon(trayIcon);
+		configTrayIcon(trayIcon);
+	    }
+	}
+	return trayIcon;
+    }
+
+    /**
+     * Gets the {@code TrayIcon} for this {@code SystemTrayControl}.
+     *
+     * @param	    trayIcon
+     *		    a {@code TrayIcon}, or {@code null} if this {@code
+     *		    SystemTrayControl} has no {@code TrayIcon}.
+     *
+     * @see	    #getTrayIcon
+     */
+    protected void setTrayIcon(TrayIcon trayIcon) {
+	this.trayIcon = trayIcon;
+    }
+}