001 /*
002 * Copyright (c) 1995-2010, The University of Sheffield. See the file
003 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004 *
005 * This file is part of GATE (see http://gate.ac.uk/), and is free
006 * software, licenced under the GNU Library General Public License,
007 * Version 2, June 1991 (in the distribution as file licence.html,
008 * and also available at http://gate.ac.uk/gate/licence.html).
009 *
010 * JMenuButton.java
011 *
012 * Valentin Tablan, 21 Aug 2008
013 *
014 * $Id: JMenuButton.java 12305 2010-02-25 13:54:10Z ian_roberts $
015 */
016
017 package gate.swing;
018
019 import java.awt.*;
020 import java.awt.event.ActionEvent;
021 import java.awt.event.ActionListener;
022
023 import javax.swing.*;
024 import javax.swing.event.PopupMenuEvent;
025 import javax.swing.event.PopupMenuListener;
026
027 /**
028 * A toggle button that shows a pop-up menu.
029 */
030 public class JMenuButton extends JToggleButton {
031 public JMenuButton(JMenu menu) {
032 this(menu.getPopupMenu());
033 this.menu = menu;
034 }
035
036 public JMenuButton(JPopupMenu popup) {
037 this.popup = popup;
038 popup.setInvoker(this);
039 initListeners();
040 }
041
042 protected void initListeners() {
043
044 addActionListener(new ActionListener() {
045
046 public void actionPerformed(ActionEvent e) {
047 if(menu != null) menu.setSelected(isSelected());
048 if(isSelected()) {
049 // show the popup
050 Point p = getPopupMenuOrigin();
051 popup.show(JMenuButton.this, p.x, p.y);
052 }
053 else {
054 // hide the popup
055 popup.setVisible(false);
056 }
057 }
058 });
059
060 popup.addPopupMenuListener(new PopupMenuListener(){
061
062 public void popupMenuCanceled(PopupMenuEvent e) {
063 setSelected(false);
064 if(menu != null) menu.setSelected(false);
065 }
066
067 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
068 setSelected(false);
069 if(menu != null) menu.setSelected(false);
070 }
071
072 public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
073 }
074 });
075 }
076
077 /**
078 * Method largely borrowed from Swing's JMenu.
079 *
080 * Computes the origin for the <code>JMenu</code>'s popup menu. This
081 * method uses Look and Feel properties named
082 * <code>Menu.menuPopupOffsetX</code>,
083 * <code>Menu.menuPopupOffsetY</code>,
084 * <code>Menu.submenuPopupOffsetX</code>, and
085 * <code>Menu.submenuPopupOffsetY</code> to adjust the exact location
086 * of popup.
087 *
088 * @return a <code>Point</code> in the coordinate space of the menu
089 * which should be used as the origin of the
090 * <code>JMenu</code>'s popup menu
091 */
092 protected Point getPopupMenuOrigin() {
093 int x = 0;
094 int y = 0;
095 // Figure out the sizes needed to caclulate the menu position
096 Dimension s = getSize();
097 Dimension pmSize = popup.getSize();
098 // For the first time the menu is popped up,
099 // the size has not yet been initiated
100 if(pmSize.width == 0) {
101 pmSize = popup.getPreferredSize();
102 }
103 Point position = getLocationOnScreen();
104 Toolkit toolkit = Toolkit.getDefaultToolkit();
105 GraphicsConfiguration gc = getGraphicsConfiguration();
106 Rectangle screenBounds = new Rectangle(toolkit.getScreenSize());
107 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
108 GraphicsDevice[] gd = ge.getScreenDevices();
109 for(int i = 0; i < gd.length; i++) {
110 if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
111 GraphicsConfiguration dgc = gd[i].getDefaultConfiguration();
112 if(dgc.getBounds().contains(position)) {
113 gc = dgc;
114 break;
115 }
116 }
117 }
118
119 if(gc != null) {
120 screenBounds = gc.getBounds();
121 // take screen insets (e.g. taskbar) into account
122 Insets screenInsets = toolkit.getScreenInsets(gc);
123
124 screenBounds.width -= Math.abs(screenInsets.left + screenInsets.right);
125 screenBounds.height -= Math.abs(screenInsets.top + screenInsets.bottom);
126 position.x -= Math.abs(screenInsets.left);
127 position.y -= Math.abs(screenInsets.top);
128 }
129
130 // We are a toplevel menu (pull-down)
131 int xOffset = UIManager.getInt("Menu.menuPopupOffsetX");
132 int yOffset = UIManager.getInt("Menu.menuPopupOffsetY");
133
134 if(getComponentOrientation().isLeftToRight()) {
135 // First determine the x:
136 x = xOffset; // Extend to the right
137 if(position.x + x + pmSize.width >= screenBounds.width + screenBounds.x &&
138 // popup doesn't fit - place it wherever there's more
139 // room
140 screenBounds.width - s.width < 2 * (position.x - screenBounds.x)) {
141
142 x = s.width - xOffset - pmSize.width;
143 }
144 }
145 else {
146 // First determine the x:
147 x = s.width - xOffset - pmSize.width; // Extend to the left
148 if(position.x + x < screenBounds.x &&
149 // popup doesn't fit - place it wherever there's more room
150 screenBounds.width - s.width > 2 * (position.x - screenBounds.x)) {
151
152 x = xOffset;
153 }
154 }
155 // Then the y:
156 y = s.height + yOffset; // Prefer dropping down
157 if(position.y + y + pmSize.height >= screenBounds.height &&
158 // popup doesn't fit - place it wherever there's more room
159 screenBounds.height - s.height < 2 * (position.y - screenBounds.y)) {
160
161 y = 0 - yOffset - pmSize.height; // Otherwise drop 'up'
162 }
163 return new Point(x, y);
164 }
165
166 protected JPopupMenu popup;
167 protected JMenu menu;
168 }
|