001: /*
002: * Copyright (C) 2005 Jeff Tassin
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package com.jeta.swingbuilder.gui.focus;
020:
021: import java.awt.BorderLayout;
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Dimension;
025: import java.awt.Font;
026: import java.awt.FontMetrics;
027: import java.awt.Graphics;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.ActionListener;
030: import java.awt.event.MouseAdapter;
031: import java.awt.event.MouseEvent;
032: import java.util.Iterator;
033: import java.util.LinkedList;
034:
035: import javax.swing.JComponent;
036: import javax.swing.JPanel;
037: import javax.swing.JSpinner;
038: import javax.swing.SpinnerNumberModel;
039: import javax.swing.UIManager;
040: import javax.swing.event.ChangeEvent;
041: import javax.swing.event.ChangeListener;
042:
043: /**
044: * This component renders the focus order icons over the Form.
045: *
046: * @author Jeff Tassin
047: */
048: public class FocusBox extends JPanel {
049: /**
050: * Displays the current focus index when this focusbox does not have 'focus'
051: */
052: private FocusGlyph m_focus_glyph;
053:
054: /**
055: * A spinner box used to edit the current focus value. Only visible when
056: * this focusbox has 'focus' (i.e. the user clicked on this focusbox with
057: * the mouse
058: */
059: private JSpinner m_spinner;
060:
061: /**
062: * Flag that indicates if the spinner is active
063: */
064: private boolean m_spinner_active = false;
065:
066: /**
067: * The current focus index
068: */
069: private int m_index;
070:
071: /**
072: * The max allowed focus index
073: */
074: private int m_max_index;
075:
076: /**
077: * The form component associated with this box
078: */
079: private Component m_component;
080:
081: /**
082: * A list of ActionListeners that want events for this FocusBox
083: */
084: private LinkedList m_listeners;
085:
086: private Color m_background = Color.blue.darker().darker();
087: private Color m_foreground = Color.white;
088:
089: /**
090: * Action commands
091: */
092: public static final String FOCUS_INDEX_CHANGED = "focus.index.changed";
093: public static final String FOCUS_BOX_ACTIVATED = "focus.box.activated";
094:
095: /** ctor */
096: public FocusBox(int index, int maxIndex, Component comp) {
097: m_index = index;
098: m_max_index = maxIndex;
099: m_component = comp;
100:
101: m_focus_glyph = new FocusGlyph(index, m_foreground,
102: m_background);
103: setLayout(new BorderLayout());
104: add(m_focus_glyph, BorderLayout.CENTER);
105:
106: m_focus_glyph.addMouseListener(new MouseAdapter() {
107: public void mousePressed(MouseEvent evt) {
108: remove(m_focus_glyph);
109: JSpinner spinner = getSpinner();
110: remove(spinner);
111: Dimension d = spinner.getPreferredSize();
112: // d.width = d.width*3/2;
113: setSize(d);
114: add(spinner);
115: revalidate();
116: m_spinner_active = true;
117: notifyListeners(new ActionEvent(FocusBox.this ,
118: ActionEvent.ACTION_PERFORMED,
119: FOCUS_BOX_ACTIVATED));
120: }
121: });
122: }
123:
124: /**
125: * Adds an action listener to this focusbox. A call can get an action event
126: * when the focus index changes or the user has clicked on this focus box.
127: */
128: public void addActionListener(ActionListener listener) {
129: if (m_listeners == null)
130: m_listeners = new LinkedList();
131:
132: m_listeners.add(listener);
133: }
134:
135: /**
136: * Hides the spinner. There is no activate spinner because it is handled
137: * internally in this class.
138: */
139: void deactivateSpinner() {
140: m_spinner_active = false;
141: if (m_spinner != null) {
142: remove(m_spinner);
143: remove(m_focus_glyph);
144: add(m_focus_glyph);
145: revalidate();
146: setSize(getPreferredSize());
147: }
148: }
149:
150: /**
151: * @return the form component associated with this focus box.
152: */
153: public Component getComponent() {
154: return m_component;
155: }
156:
157: public int getFocusIndex() {
158: return m_index;
159: }
160:
161: /**
162: * @return the preferred size for this component
163: */
164: public Dimension getPreferredSize() {
165: if (m_spinner_active)
166: return m_spinner.getPreferredSize();
167: else
168: return m_focus_glyph.getPreferredSize();
169: }
170:
171: int getSpinnerValue() {
172: SpinnerNumberModel smodel = (SpinnerNumberModel) m_spinner
173: .getModel();
174: Integer ival = (Integer) smodel.getValue();
175: return ival.intValue();
176: }
177:
178: public void setFocusIndex(int index) {
179: m_index = index;
180: if (m_spinner != null) {
181: SpinnerNumberModel smodel = (SpinnerNumberModel) m_spinner
182: .getModel();
183: Integer ival = (Integer) smodel.getValue();
184: if (ival.intValue() != index) {
185: smodel.setValue(new Integer(index));
186: }
187: }
188: m_focus_glyph.setIndex(index);
189: setSize(getPreferredSize());
190: repaint();
191: }
192:
193: /**
194: * @return the spinner component that is visible when the focus box has
195: * 'focus'.
196: */
197: JSpinner getSpinner() {
198: if (m_spinner == null) {
199: m_spinner = new JSpinner(new SpinnerNumberModel(m_index, 1,
200: m_max_index, 1));
201: m_spinner.setBorder(javax.swing.BorderFactory
202: .createLineBorder(m_background));
203: JSpinner.NumberEditor seditor = (JSpinner.NumberEditor) m_spinner
204: .getEditor();
205: seditor.getTextField().setBackground(m_background);
206: seditor.getTextField().setForeground(m_foreground);
207:
208: m_spinner.addChangeListener(new ChangeListener() {
209: public void stateChanged(ChangeEvent e) {
210: notifyListeners(new ActionEvent(FocusBox.this ,
211: ActionEvent.ACTION_PERFORMED,
212: FOCUS_INDEX_CHANGED));
213: }
214: });
215: }
216: return m_spinner;
217: }
218:
219: /**
220: * Notifies all registered listeners that an action has occurred.
221: */
222: private void notifyListeners(ActionEvent evt) {
223: if (m_listeners == null)
224: return;
225:
226: Iterator iter = m_listeners.iterator();
227: while (iter.hasNext()) {
228: ActionListener listener = (ActionListener) iter.next();
229: listener.actionPerformed(evt);
230: }
231: }
232:
233: /**
234: * Removes a previously registered action listener from this focusbox.
235: */
236: public void removeActionListener(ActionListener listener) {
237: if (m_listeners == null)
238: return;
239:
240: m_listeners.remove(listener);
241: }
242:
243: /**
244: * Renders the current focus index.
245: */
246: public static class FocusGlyph extends JComponent {
247: private Font m_font;
248: private int m_index;
249: private String m_index_str;
250:
251: private Dimension m_pref_size = new Dimension();
252: private Color m_foreground;
253: private Color m_background;
254:
255: private static int MARGIN = 4;
256:
257: /**
258: * ctor
259: */
260: public FocusGlyph(int index, Color foreground, Color background) {
261: m_index = index;
262: m_index_str = String.valueOf(m_index);
263: m_font = UIManager.getFont("Table.font");
264: m_foreground = foreground;
265: m_background = background;
266: }
267:
268: /**
269: * @return the focus index
270: */
271: public int getIndex() {
272: return m_index;
273: }
274:
275: public void setIndex(int index) {
276: m_index = index;
277: m_index_str = String.valueOf(index);
278: }
279:
280: /**
281: * @return the preferred size
282: */
283: public Dimension getPreferredSize() {
284: FontMetrics fm = getFontMetrics(m_font);
285: int line_height = fm.getHeight();
286: m_pref_size.setSize(fm.stringWidth(m_index_str) + MARGIN
287: * 2, line_height);
288: return m_pref_size;
289: }
290:
291: /**
292: * Paint routine that renders the focus glyphs
293: */
294: public void paintComponent(Graphics g) {
295: Color old_c = g.getColor();
296:
297: FontMetrics fm = g.getFontMetrics(m_font);
298: int line_height = fm.getHeight();
299: int y = line_height - fm.getDescent();
300:
301: g.setColor(m_background);
302: g.fillRect(0, 0, getWidth(), getHeight());
303: g.setColor(m_foreground);
304: g.drawString(m_index_str, MARGIN, y);
305: g.setColor(old_c);
306: }
307: }
308: }
|