001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.components;
042:
043: import java.awt.AWTEvent;
044: import java.awt.Color;
045: import java.awt.Dimension;
046: import java.awt.EventQueue;
047: import java.awt.Graphics;
048: import java.awt.Rectangle;
049: import java.awt.event.ActionEvent;
050: import java.awt.event.ActionListener;
051: import java.awt.event.InputEvent;
052: import java.awt.event.KeyAdapter;
053: import java.awt.event.KeyEvent;
054: import java.awt.event.MouseEvent;
055: import java.awt.event.MouseMotionAdapter;
056: import javax.swing.DefaultButtonModel;
057: import javax.swing.ImageIcon;
058: import javax.swing.JButton;
059: import javax.swing.JPopupMenu;
060: import javax.swing.JRadioButtonMenuItem;
061:
062: /**
063: *
064: * @author Jiri Sedlacek
065: */
066: public class PopupButton extends JButton {
067: //~ Inner Classes ------------------------------------------------------------------------------------------------------------
068:
069: private class PopupButtonListener extends MouseMotionAdapter {
070: //~ Instance fields ------------------------------------------------------------------------------------------------------
071:
072: private boolean overPopupArea;
073:
074: //~ Methods --------------------------------------------------------------------------------------------------------------
075:
076: public boolean isOverPopupArea() {
077: return overPopupArea;
078: }
079:
080: public void mouseDragged(MouseEvent e) {
081: mouseMoved(e);
082: }
083:
084: public void mouseMoved(MouseEvent e) {
085: boolean newOverPopupArea = getPopupBounds().contains(
086: e.getPoint());
087:
088: if (overPopupArea != newOverPopupArea) {
089: overPopupArea = newOverPopupArea;
090: repaint();
091: }
092: }
093: }
094:
095: private class PopupButtonModel extends DefaultButtonModel {
096: //~ Instance fields ------------------------------------------------------------------------------------------------------
097:
098: private boolean popupAreaPressed;
099:
100: //~ Methods --------------------------------------------------------------------------------------------------------------
101:
102: public void setPopupAreaPressed(boolean b) {
103: popupAreaPressed = b;
104: }
105:
106: public boolean isPopupAreaPressed() {
107: return popupAreaPressed;
108: }
109:
110: public void setPressed(boolean b) {
111: if (b == false) {
112: boolean popupAction = isPopupAreaPressed() && isArmed()
113: && listener.isOverPopupArea();
114: setPopupAreaPressed(b);
115: super .setPressed(b);
116:
117: if (popupAction) {
118: showPopupMenu();
119: }
120: } else {
121: if (listener.isOverPopupArea()) {
122: setPopupAreaPressed(b);
123: } else {
124: super .setPressed(b);
125: }
126: }
127: }
128: }
129:
130: //~ Instance fields ----------------------------------------------------------------------------------------------------------
131:
132: private Dimension preferredSize;
133: private Dimension referenceSize;
134: private JPopupMenu popupMenu;
135: private JRadioButtonMenuItem selectedItem;
136: private PopupButtonListener listener;
137: private PopupButtonModel model;
138: private ImageIcon[] icons;
139: private String[] labels;
140:
141: //~ Constructors -------------------------------------------------------------------------------------------------------------
142:
143: public PopupButton(String[] labels, ImageIcon[] icons) {
144: super (labels[0], icons[0]);
145:
146: this .labels = labels;
147: this .icons = icons;
148:
149: if (labels.length > 1) {
150: model = new PopupButtonModel();
151: listener = new PopupButtonListener();
152: addMouseMotionListener(listener);
153: setModel(model);
154: addKeyListener(new KeyAdapter() {
155: public void keyPressed(KeyEvent e) {
156: if (e.isShiftDown()
157: && ((e.getKeyCode() == KeyEvent.VK_UP) || (e
158: .getKeyCode() == KeyEvent.VK_DOWN))) {
159: showPopupMenu();
160: }
161: }
162: });
163: }
164: }
165:
166: //~ Methods ------------------------------------------------------------------------------------------------------------------
167:
168: public Dimension getMinimumSize() {
169: Dimension size = computePreferredSize();
170:
171: if (size != null) {
172: return size;
173: } else {
174: return super .getMinimumSize();
175: }
176: }
177:
178: public Dimension getPreferredSize() {
179: Dimension size = computePreferredSize();
180:
181: if (size != null) {
182: return size;
183: } else {
184: return super .getPreferredSize();
185: }
186: }
187:
188: public void paint(Graphics g) {
189: super .paint(g);
190:
191: if ((labels.length > 1) && model.isRollover()
192: && !(model.isPressed())) {
193: Rectangle popupBounds = getPopupBounds();
194: g.setColor(Color.WHITE);
195: g.fillRect(popupBounds.x + 1, popupBounds.y + 1,
196: popupBounds.width - 2, popupBounds.height - 2);
197: g.setColor(((model.isPressed() && model.isArmed()) || model
198: .isSelected()) ? Color.GRAY : Color.LIGHT_GRAY);
199: g.drawLine(popupBounds.x, popupBounds.y + 1, popupBounds.x,
200: (popupBounds.y + popupBounds.height) - 2);
201: drawPopupArrow(g, popupBounds.x + 4,
202: (popupBounds.y + (popupBounds.height / 2)) - 1);
203: }
204: }
205:
206: public void showPopupMenu() {
207: JPopupMenu popup = getPopupMenu();
208: popup.show(this , 0, getSize().height - 1);
209: }
210:
211: private Rectangle getButtonBounds() {
212: return new Rectangle(0, 0, getSize().width, getSize().height);
213: }
214:
215: private Rectangle getPopupBounds() {
216: Rectangle buttonBounds = getButtonBounds();
217:
218: return new Rectangle(
219: (buttonBounds.x + buttonBounds.width) - 15,
220: buttonBounds.y, 15, buttonBounds.height);
221: }
222:
223: private JPopupMenu getPopupMenu() {
224: if (popupMenu == null) {
225: ActionListener menuItemListener = new ActionListener() {
226: public void actionPerformed(ActionEvent e) {
227: JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) e
228: .getSource();
229:
230: if (selectedItem != menuItem) {
231: selectedItem.setSelected(false);
232: }
233:
234: menuItem.setSelected(true);
235: selectedItem = menuItem;
236: setText(menuItem.getText());
237:
238: if (icons.length > 1) {
239: setIcon(icons[getPopupMenu().getComponentIndex(
240: menuItem)]);
241: }
242:
243: firePopupAction();
244: }
245: };
246:
247: JPopupMenu popup = new JPopupMenu();
248:
249: for (int i = 0; i < labels.length; i++) {
250: JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(
251: labels[i], i == 0);
252:
253: if (i == 0) {
254: selectedItem = menuItem;
255: }
256:
257: menuItem.addActionListener(menuItemListener);
258: popup.add(menuItem);
259: }
260:
261: popupMenu = popup;
262: }
263:
264: return popupMenu;
265: }
266:
267: private Dimension computePreferredSize() {
268: if ((labels.length > 1)
269: && (referenceSize != super .getPreferredSize())) {
270: JButton referenceButton = new JButton(labels[0], icons[0]);
271: referenceButton.setFont(getFont());
272: referenceButton.setBorder(getBorder());
273: referenceButton.setMargin(getMargin());
274: referenceButton.setContentAreaFilled(isContentAreaFilled());
275: referenceButton
276: .setVerticalTextPosition(getVerticalTextPosition());
277: referenceButton
278: .setHorizontalTextPosition(getHorizontalTextPosition());
279:
280: preferredSize = new Dimension(referenceButton
281: .getPreferredSize());
282:
283: if (labels.length > 1) {
284: for (int i = 1; i < labels.length; i++) {
285: referenceButton.setText(labels[i]);
286:
287: if (icons.length > 1) {
288: referenceButton.setIcon(icons[i]);
289: }
290:
291: preferredSize.width = Math.max(preferredSize.width,
292: referenceButton.getPreferredSize().width);
293: preferredSize.height = Math.max(
294: preferredSize.height, referenceButton
295: .getPreferredSize().height);
296: }
297: }
298:
299: referenceSize = super .getPreferredSize();
300: }
301:
302: return preferredSize;
303: }
304:
305: private void drawPopupArrow(Graphics g, int x, int y) {
306: g.setColor(listener.isOverPopupArea() ? Color.DARK_GRAY
307: : Color.GRAY);
308:
309: if (model.isPopupAreaPressed()) {
310: x++;
311: y++;
312: }
313:
314: ;
315: g.drawLine(x + 0, y + 0, x + 6, y + 0);
316: g.drawLine(x + 1, y + 1, x + 5, y + 1);
317: g.drawLine(x + 2, y + 2, x + 4, y + 2);
318: g.drawLine(x + 3, y + 3, x + 3, y + 3);
319: }
320:
321: private void firePopupAction() {
322: int modifiers = 0;
323: AWTEvent currentEvent = EventQueue.getCurrentEvent();
324:
325: if (currentEvent instanceof InputEvent) {
326: modifiers = ((InputEvent) currentEvent).getModifiers();
327: } else if (currentEvent instanceof ActionEvent) {
328: modifiers = ((ActionEvent) currentEvent).getModifiers();
329: }
330:
331: fireActionPerformed(new ActionEvent(this,
332: ActionEvent.ACTION_PERFORMED, getActionCommand(),
333: EventQueue.getMostRecentEventTime(), modifiers));
334: }
335: }
|