package com.rle.monitor; /* * RLE Surface Crack Detector Graphing Software * * Copyright (C) 2002 RLE Technologies * For more information visit http://www.rletech.com/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /** * @author Andy Goth * @author Eric Peterson * @author Matt Lane * @version 0.1 */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; import javax.swing.plaf.metal.*; /** UI for my spinner. Patterned after Sun's 1.4 BasicSpinnerUI. */ public class MySpinnerUI extends ComponentUI { private static Icon upIcon = new ImageIcon("images/up.png"); private static Icon downIcon = new ImageIcon("images/down.png"); private final FocusHandler focusHandler = new FocusHandler(); private final ChangeHandler changeHandler = new ChangeHandler(); private static final ArrowHandler nextHandler = new ArrowHandler(true); private static final ArrowHandler prevHandler = new ArrowHandler(false); private MySpinner spinner; private SpinnerLayout layout; public MySpinnerUI() {this(null);} public MySpinnerUI(MySpinner c) {} public static ComponentUI createUI(JComponent c) { return new MySpinnerUI((MySpinner)c); } /** Adds a component to this container if it's not null. */ private void maybeAdd(Component c, String name) { if (c != null) spinner.add(c, name); } public void installUI(JComponent c) { spinner = (MySpinner)c; layout = new SpinnerLayout(); spinner.setLayout(layout); maybeAdd(createLabel(), "Label"); maybeAdd(createValue(), "Value"); maybeAdd(createNext(), "Next"); maybeAdd(createPrev(), "Prev"); spinner.addMouseListener(focusHandler); spinner.addFocusListener(focusHandler); spinner.addChangeListener(changeHandler); } public void uninstallUI(JComponent c) { layout = null; spinner.setLayout(null); c.removeMouseListener(focusHandler); c.removeFocusListener(focusHandler); spinner.removeChangeListener(changeHandler); spinner = null; } /** Returns the label component of the spinner. */ protected Component createLabel() { return new MyLabel() { { parent = spinner; setHorizontalAlignment(SwingConstants.LEFT); raised = false; } public String getText() { return parent == null ? null : parent.getText(); } }; } /** Returns the value component of the spinner. */ protected Component createValue() { return new MyLabel() { { parent = spinner; setHorizontalAlignment(SwingConstants.RIGHT); raised = true; } public String getText() { return parent == null ? null : String. valueOf(parent.getValue()); } }; } /** Returns the down button component of the spinner. */ protected Component createPrev() { JButton b = new ArrowButton(SwingConstants.SOUTH); b.addActionListener(prevHandler); b.addMouseListener(prevHandler); return b; } /** Returns the up button component of the spinner. */ protected Component createNext() { JButton b = new ArrowButton(SwingConstants.NORTH); b.addActionListener(nextHandler); b.addMouseListener(nextHandler); return b; } public void paint(Graphics g, JComponent c) { if (g == null) return; int x = layout.getComponent("Label").getWidth(); int w = c.getWidth() - x; int h = c.getHeight(); MyUtils.drawSunkenBorder(g, x, 0, w, h); } public Dimension getPreferredSize(JComponent c) { FontMetrics fm = c.getFontMetrics(UIManager.getFont( "Spinner.font")); int width = 21 + fm.stringWidth(((MySpinner)c).getText()) + fm.stringWidth("888"); int height = 8 + fm.getHeight(); if ((height & 1) == 1) height++; return new Dimension(width, height); } /** Handler for the up and down arrow buttons. */ protected static class ArrowHandler extends MouseAdapter implements ActionListener { private final javax.swing.Timer autoRepeat; private final boolean advance; private MySpinner spinner = null; /** Constructor. Handles incrementing or decrementing. */ public ArrowHandler(boolean advance) { this.advance = advance; autoRepeat = new javax.swing.Timer(60, this); autoRepeat.setInitialDelay(500); } /** Increments or decrements the spinner's value. */ public void actionPerformed(ActionEvent e) { if (spinner == null) return; int val = spinner.getValue() + (advance ? 1 : -1); if (val < spinner.getMinimum()) val = spinner.getMinimum(); else if (val > spinner.getMaximum()) val = spinner.getMaximum(); spinner.setValue(val); } /** Returns the spinner containing the precipitating object. */ private MySpinner eventToSpinner(AWTEvent e) { Object src = e.getSource(); while ((src instanceof Component) && !(src instanceof MySpinner)) src = ((Component)src).getParent(); return (src instanceof MySpinner) ? (MySpinner)src : null; } /** Handles clicking and holding the up and down buttons. */ public void mousePressed(MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e)) return; if (!e.getComponent().isEnabled()) return; spinner = eventToSpinner(e); spinner.requestFocus(); autoRepeat.setDelay(60); autoRepeat.start(); } /** Stops the incrementing or decrementing. */ public void mouseReleased(MouseEvent e) { autoRepeat.stop(); spinner = null; } } /** Layout manager that places the various components of a spinner. */ public static class SpinnerLayout implements LayoutManager { private static final Dimension zeroSize = new Dimension(0, 0); private Component next = null; private Component prev = null; private Component label = null; private Component value = null; /** Adds a named component. */ public void addLayoutComponent(String name, Component c) { if ("Next".equals(name)) next = c; else if ("Prev".equals(name)) prev = c; else if ("Label".equals(name)) label = c; else if ("Value".equals(name)) value = c; } /** Returns a named component. */ private Component getComponent(String name) { if ("Next".equals(name)) return next; if ("Prev".equals(name)) return prev; if ("Label".equals(name)) return label; if ("Value".equals(name)) return value; return null; } /** Removes a component. */ public void removeLayoutComponent(Component c) { if (c == next) next = null; else if (c == prev) prev = null; else if (c == label) label = null; else if (c == value) value = null; } /** Returns the preferred size of a component. */ private Dimension preferredSize(Component c) { return c == null ? zeroSize : c.getPreferredSize(); } /** Returns the preferred size of the entire spinner. */ public Dimension preferredLayoutSize(Container parent) { Dimension nextD = preferredSize(next); Dimension prevD = preferredSize(prev); Dimension labelD = preferredSize(label); Dimension valueD = preferredSize(value); if ((labelD.height & 1) == 0) labelD.height--; if ((valueD.height & 1) == 0) valueD.height--; Dimension size = new Dimension(valueD); size.width += nextD.width > prevD.width ? nextD.width : prevD.width; Insets insets = parent.getInsets(); size.width += insets.left + insets.right; size.height += insets.top + insets.bottom; return size; } /** Returns the minimum size of the spinner. */ public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } /** Sets the bounds of a component. */ private void setBounds(Component c, int x, int y, int w, int h) { if (c == null) return; c.setBounds(x, y, w, h); } /** Places the components of the spinner. */ public void layoutContainer(Container parent) { Insets insets = parent.getInsets(); int availW = parent.getWidth() - insets.left - insets.right - 2; int availH = parent.getHeight() - insets.top - insets.bottom - 2; Dimension nextD = preferredSize(next); Dimension prevD = preferredSize(prev); Dimension labelD = preferredSize(label); int nextH = availH / 2; int prevH = availH - nextH; int buttonW = nextD.width > prevD.width ? nextD.width : prevD.width; int labelW = labelD.width; int valueW = availW - buttonW - labelW; int labelX = insets.left + 1; int valueX = labelX + labelW; int buttonX = valueX + valueW; int widgetY = insets.top + 1; int prevY = widgetY + nextH; setBounds(label, labelX, widgetY, labelW, availH); setBounds(value, valueX, widgetY, valueW, availH); setBounds(next, buttonX, widgetY, buttonW, nextH); setBounds(prev, buttonX, prevY, buttonW, prevH); } } /** Not much different than an ordinary label... */ protected class MyLabel extends JLabel { MySpinner parent; boolean focused = false; boolean raised; public void setFocused(boolean focused) { this.focused = focused; repaint(); } public Dimension getPreferredSize() { FontMetrics fm = getFontMetrics(getFont()); int width = fm.stringWidth(getText()) + 4; int height = fm.getHeight() + 4; return new Dimension(width, height); } protected Color getFocusColor() { return UIManager.getColor("Spinner.focus"); } public void paint(Graphics g) { boolean right = getHorizontalAlignment() == RIGHT; int offset = raised ? (right ? -3 : 3) : (right ? -1 : 1); g.translate(offset, 0); super.paint(g); if (focused) { FontMetrics fm = getFontMetrics(getFont()); int w = fm.stringWidth(getText()) + 1; int h = fm.getHeight() + 1; int x = -1; int y = (getHeight() - h) / 2; g.setColor(getFocusColor()); g.drawRect(x, y, w, h); } g.translate(-offset, 0); if (raised) MyUtils.drawRaisedBorder(g, 0, 0, getWidth(), getHeight()); } } /** Handler for value changes. */ protected class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent e) { MyLabel l = (MyLabel)layout.getComponent("Value"); if (l == null) return; l.setText(String.valueOf(spinner.getValue())); } } /** Handler for focus events and clicking. */ protected class FocusHandler extends MouseAdapter implements FocusListener { public void mouseClicked(MouseEvent e) { spinner.requestFocus(); } public void focusGained(FocusEvent e) { MyLabel l = (MyLabel)layout.getComponent("Label"); if (l == null) return; l.setFocused(true); } public void focusLost(FocusEvent e) { MyLabel l = (MyLabel)layout.getComponent("Label"); if (l == null) return; l.setFocused(false); } } /** Customized arrow button. */ protected class ArrowButton extends BasicArrowButton { public ArrowButton(int dir) { super(dir); } public void paint(Graphics g) { int w = getSize().width; int h = getSize().height; boolean pressed = getModel().isPressed(); boolean enabled = isEnabled(); if (pressed) { MyUtils.drawPressedBorder(g, 0, 0, w, h); g.setColor(UIManager.getColor("controlShadow")); g.fillRect(1, 1, w - 2, h - 2); } else { MyUtils.drawRaisedBorder(g, 0, 0, w, h); g.setColor(getBackground()); g.fillRect(1, 1, w - 2, h - 2); } if (h < 5 || w < 7) return; (direction == NORTH ? upIcon : downIcon).paintIcon(this, g, (w - 5) / 2, (h - 3) / 2); } public Dimension getPreferredSize() { return new Dimension(9, 9); } } }