[Schmitzm-commits] r2421 - in trunk/schmitzm-core/src/main/java/de/schmitzm/swing: . event

scm-commit at wald.intevation.org scm-commit at wald.intevation.org
Thu Jun 23 17:50:57 CEST 2016


Author: mojays
Date: 2016-06-23 17:50:57 +0200 (Thu, 23 Jun 2016)
New Revision: 2421

Modified:
   trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java
   trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/PopupMenuListener.java
Log:
PopupMenuListener: handle popup sources different than Component (esp. TrayIcon)
SwingUtil: handle application in system tray; simple transform from JPopupMenu to PopupMenu

Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java	2016-02-15 16:40:50 UTC (rev 2420)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/SwingUtil.java	2016-06-23 15:50:57 UTC (rev 2421)
@@ -35,6 +35,7 @@
 import java.awt.Container;
 import java.awt.Cursor;
 import java.awt.Desktop;
+import java.awt.Dialog;
 import java.awt.Dimension;
 import java.awt.EventQueue;
 import java.awt.Font;
@@ -44,9 +45,13 @@
 import java.awt.GraphicsEnvironment;
 import java.awt.GridBagConstraints;
 import java.awt.Image;
+import java.awt.MenuItem;
 import java.awt.Point;
+import java.awt.PopupMenu;
 import java.awt.Rectangle;
+import java.awt.SystemTray;
 import java.awt.Toolkit;
+import java.awt.TrayIcon;
 import java.awt.Window;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -58,6 +63,8 @@
 import java.awt.event.MouseWheelListener;
 import java.awt.font.TextAttribute;
 import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -105,9 +112,11 @@
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
 import javax.swing.JProgressBar;
 import javax.swing.JRadioButtonMenuItem;
 import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
 import javax.swing.JSpinner;
 import javax.swing.JSplitPane;
 import javax.swing.JTabbedPane;
@@ -119,6 +128,7 @@
 import javax.swing.JToolBar;
 import javax.swing.JTree;
 import javax.swing.JViewport;
+import javax.swing.KeyStroke;
 import javax.swing.RootPaneContainer;
 import javax.swing.SpinnerNumberModel;
 import javax.swing.SwingUtilities;
@@ -151,6 +161,7 @@
 import de.schmitzm.lang.ApplicationProps;
 import de.schmitzm.lang.LangUtil;
 import de.schmitzm.lang.ResourceProvider;
+import de.schmitzm.swing.event.PopupMenuListener;
 import de.schmitzm.swing.event.SmoothProgressBarUpdater;
 import de.schmitzm.swing.input.BooleanInputOption;
 import de.schmitzm.swing.input.InputOption;
@@ -305,6 +316,8 @@
 	public static final Cursor SELECTION_REMOVE_CURSOR = createCursorFromResourcePath(
 			"resource/cursor/selection_remove.png", 10, 10, null);
 
+    /** Default java application icon (coffee cup) */
+    public static final ImageIcon ICON_JAVA_DEFAULT = SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/java_coffee_cup.png", null);
 	/** Icon of default checkbox with state enabled and checked */
     public static final ImageIcon ICON_CHECKBOX_CHECKED = SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/checkbox/checked.png", null);
     /** Icon of default checkbox with state enabled and unchecked */
@@ -3211,5 +3224,167 @@
         downloadWorker.terminate();
       return (File)downloadWorker.getWorkResult();
     }
+    
 
+    /**
+     * Configures the current application for use as tray icon. Frame title is used as tray icon tooltip.
+     * @param icon icon used in tray (if {@code null} the frame icon is used if available)
+     * @param menu popup menu for tray icon (can be {@code null})
+     * @param defaultAction action performed on click on tray icon (if {@code null} show frame action is used)
+     * @return {@code null} if tray is not supported or could not be installed
+     */
+    public static TrayIcon configureApplicationInTray(final Frame frame, Image icon, final JPopupMenu menu, ActionListener defaultAction) {
+      // Default Action: show/hide frame
+      if ( defaultAction == null ) {
+        defaultAction = new ActionListener() {
+          public void actionPerformed(ActionEvent e) {
+            // execute default action of the application
+            boolean visible = true; // !frame.isVisible();
+            frame.setVisible( visible );
+            frame.toFront();
+          }
+        };
+      }
+      // Default Icon: frame icon
+      if ( icon == null )
+        icon = frame.getIconImage();
+      // Title = Dialog title
+      String tooltipTitle = frame.getTitle(); 
+      return configureApplicationInTray(icon, tooltipTitle, menu, defaultAction);
+      
+    }
+
+    /**
+     * Configures the current application for use as tray icon. Dialog title is used as tray icon tooltip.
+     * @param icon icon used in tray (if {@code null} the dialog icon is used if available)
+     * @param menu popup menu for tray icon (can be {@code null})
+     * @param defaultAction action performed on click on tray icon (if {@code null} show dialog action is used)
+     * @return {@code null} if tray is not supported or could not be installed
+     */
+    public static TrayIcon configureApplicationInTray(final Dialog dialog, Image icon, final JPopupMenu menu, ActionListener defaultAction) {
+      // Default Action: show/hide frame
+      if ( defaultAction == null ) {
+        defaultAction = new ActionListener() {
+          public void actionPerformed(ActionEvent e) {
+            boolean visible = true; // !dialog.isVisible();
+            dialog.setVisible( visible );
+            dialog.toFront();
+          }
+        };
+      }
+      // Default Icon: frame icon
+      if ( icon == null && !dialog.getIconImages().isEmpty() )
+        icon = dialog.getIconImages().get(0);
+      // Title = Dialog title
+      String tooltipTitle = dialog.getTitle(); 
+      return configureApplicationInTray(icon, tooltipTitle, menu, defaultAction);
+    }
+
+    /**
+     * Configures the current application for use as tray icon. Either {@code menu} or
+     * {@code defaultAction} should be set to handle some action on tray icon.
+     * @param icon icon used in tray (if {@code null} the icon {@link #ICON_JAVA_DEFAULT} is used)
+     * @param tooltipTitle tool tip text to show when mouse moves over tray icon
+     * @param menu popup menu for tray icon (can be {@code null})
+     * @param defaultAction action performed on click on tray icon (can be {@code null})
+     * @return {@code null} if tray is not supported or could not be installed
+     */
+    public static TrayIcon configureApplicationInTray(Image icon, String tooltipTitle, final JPopupMenu menu, final ActionListener defaultAction) {
+      if (!SystemTray.isSupported())
+        return( null );
+      
+      if ( icon == null )
+        icon = SwingUtil.ICON_JAVA_DEFAULT.getImage();
+      // get the SystemTray instance
+      SystemTray tray = SystemTray.getSystemTray();
+      
+      // construct a TrayIcon
+      TrayIcon trayIcon = new TrayIcon(icon, tooltipTitle);
+      trayIcon.setImageAutoSize(true);
+      if ( menu != null ) {
+//      trayIcon.addMouseListener( new PopupMenuListener(menu) ); // does not handle ESC key well!
+        trayIcon.setPopupMenu( transformJMenu(menu) ); // transform JPopupMenu to PopupMenu
+      }
+      // set the TrayIcon properties
+      if ( defaultAction != null )
+        if ( defaultAction instanceof Action )
+          // If listerner is instance of Action pipe event
+          // to provide action's command ID in event
+          trayIcon.addActionListener( new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+              e = new ActionEvent(e.getSource(), e.getID(), (String)((Action)defaultAction).getValue(Action.ACTION_COMMAND_KEY));
+              defaultAction.actionPerformed(e);
+            }
+          });
+        else
+          trayIcon.addActionListener( defaultAction );
+
+      // add the tray image
+      try {
+          tray.add(trayIcon);
+      } catch (Exception e) {
+          System.err.println(e);
+          return( null );
+      }
+      
+      return( trayIcon );
+    }
+    
+    /**
+     * Transforms a {@link JPopupMenu} to a {@link PopupMenu} in a simple way,
+     * by copying all items and separators. The {@link Action} of each new {@link MenuItem} is
+     * piped to the corresponding {@link JMenuItem} action.<br> 
+     * <b>Note:</b> As the only property change the enabled/disabled property is piped
+     * from {@link JMenuItem} to corresponding {@link MenuItem}. All other belated property
+     * changes on {@link JMenu} are ignored! 
+     */
+    public static PopupMenu transformJMenu(JPopupMenu jMenu) {
+      PopupMenu menu = new PopupMenu( jMenu.getLabel() );
+      
+      for (Component c : jMenu.getComponents()) {
+        if ( c instanceof JMenuItem ) {
+          // Create MenuItem from JMenuItem
+          final JMenuItem jMenuItem = (JMenuItem)c;
+          final MenuItem menuItem = new MenuItem();
+          menuItem.setActionCommand((String)jMenuItem.getAction().getValue(Action.ACTION_COMMAND_KEY));
+          menuItem.setEnabled(jMenuItem.isEnabled());
+          menuItem.setFont(jMenuItem.getFont());
+          menuItem.setLabel(jMenuItem.getText());
+          menuItem.setName((String)jMenuItem.getAction().getValue(Action.SHORT_DESCRIPTION));
+          // listener to pipe action from MenuItem to corresponding JMenuItem
+          menuItem.addActionListener( new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+              jMenuItem.getAction().actionPerformed( new ActionEvent(
+                                                                     jMenuItem,
+                                                                     e.getID(),
+                                                                     e.getActionCommand()
+                                                                     )
+              );
+            }
+          });
+          // Listener to pipe proerty changes from JMenuItem to
+          // corresponding MenuItem
+          jMenuItem.addPropertyChangeListener(new PropertyChangeListener() {
+            @Override
+            public void propertyChange(PropertyChangeEvent evt) {
+//              System.out.println( "JMenuItem."+evt.getPropertyName()+ ":   "+evt.getOldValue()+" --> "+evt.getNewValue());
+              if ( "enabled".equalsIgnoreCase(evt.getPropertyName()) )
+                menuItem.setEnabled( !menuItem.isEnabled() );
+            }
+          });
+          // Add item to menue
+          menu.add(menuItem);
+        }
+        if ( c instanceof JSeparator )
+          menu.addSeparator();
+      }
+      
+      return( menu );
+    }
 }
+
+
+
+

Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/PopupMenuListener.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/PopupMenuListener.java	2016-02-15 16:40:50 UTC (rev 2420)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/event/PopupMenuListener.java	2016-06-23 15:50:57 UTC (rev 2421)
@@ -29,7 +29,7 @@
  ******************************************************************************/
 package de.schmitzm.swing.event;
 
-import java.awt.Component;
+import java.awt.TrayIcon;
 import java.awt.event.MouseEvent;
 
 import javax.swing.JPopupMenu;
@@ -61,7 +61,16 @@
    */
   protected void checkPopupSignal(MouseEvent e) {
     if ( e.isPopupTrigger() ) {
-      menu.show( (Component)e.getSource(), e.getX(), e.getY() );
+      if ( e.getSource() instanceof TrayIcon ) {
+        // show(.) method does not work properly on tray icon (e.g.
+        // highlighting of menu items on mouseover works only with
+        // following command sequence)
+        menu.setLocation(e.getX(), e.getY());
+        menu.setInvoker(menu);
+        menu.setVisible(true);
+      } else {
+        menu.show( e.getComponent(), e.getX(), e.getY() );
+      }
       e.consume();
     }
   }



More information about the Schmitzm-commits mailing list