001: /*
002: * ButtonSelectionPane.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing;
023:
024: import java.awt.Color;
025: import java.awt.Cursor;
026: import java.awt.Graphics;
027: import java.awt.GridBagConstraints;
028: import java.awt.GridBagLayout;
029: import java.awt.Shape;
030:
031: import java.awt.event.ActionEvent;
032: import java.awt.event.ActionListener;
033: import java.awt.event.MouseEvent;
034: import java.awt.event.MouseListener;
035:
036: import java.util.Vector;
037:
038: import javax.swing.Icon;
039: import javax.swing.JButton;
040: import javax.swing.JComponent;
041: import javax.swing.JPanel;
042: import javax.swing.SingleSelectionModel;
043: import javax.swing.SwingUtilities;
044: import javax.swing.SwingConstants;
045: import javax.swing.UIManager;
046:
047: import javax.swing.event.ChangeListener;
048:
049: import javax.swing.plaf.metal.MetalLookAndFeel;
050:
051: import org.underworldlabs.swing.table.ArrowIcon;
052:
053: /* ----------------------------------------------------------
054: * CVS NOTE: Changes to the CVS repository prior to the
055: * release of version 3.0.0beta1 has meant a
056: * resetting of CVS revision numbers.
057: * ----------------------------------------------------------
058: */
059:
060: /**
061: *
062: * @author Takis Diakoumis
063: * @version $Revision: 1.4 $
064: * @date $Date: 2006/05/14 06:56:07 $
065: */
066: public class ButtonSelectionPane extends JPanel implements
067: ActionListener {
068:
069: /** The default button background */
070: private static Color defaultColour;
071: /** The button background on mouse hover */
072: private static Color hoverColour;
073: /** The icon for a selection */
074: private static ArrowIcon selectedIcon;
075: /** The default icon */
076: private static ArrowIcon defaultIcon;
077:
078: /** Default selection model */
079: private SingleSelectionModel model;
080: /** The components displayed */
081: private Vector componentPanels;
082: /** The selection buttons */
083: private Vector componentButtons;
084: /** Whether the look and feel is an instance of Java look and feel */
085: private boolean isJavaLookAndFeel;
086: /** The background colour */
087: private static Color background;
088: /** The foreground colour */
089: private static Color foreground;
090:
091: public ButtonSelectionPane(Vector componentPanels,
092: Vector buttonLabels) {
093: this ();
094: this .componentPanels = componentPanels;
095:
096: int numButtons = buttonLabels.size();
097: componentButtons = new Vector(numButtons);
098:
099: for (int i = 0; i < numButtons; i++) {
100: SelectionPaneButton button = new SelectionPaneButton(
101: buttonLabels.elementAt(i).toString());
102: componentButtons.add(button);
103: button.addActionListener(this );
104: }
105:
106: }
107:
108: public ButtonSelectionPane() {
109: super (new GridBagLayout());
110:
111: // initialise the model
112: model = new ButtonSelectionPaneModel();
113: model.setSelectedIndex(0);
114:
115: // initialise the component cache
116: componentButtons = new Vector();
117: componentPanels = new Vector();
118:
119: hoverColour = UIManager.getColor("activeCaption");
120: defaultColour = getBackground();
121:
122: defaultIcon = new ArrowIcon(Color.BLACK, ArrowIcon.RIGHT);
123: selectedIcon = new ArrowIcon(Color.BLACK, ArrowIcon.DOWN);
124:
125: isJavaLookAndFeel = UIManager.getLookAndFeel() instanceof MetalLookAndFeel;
126:
127: background = UIManager.getDefaults().getColor(
128: "InternalFrame.borderDarkShadow");
129: foreground = Color.WHITE;
130: }
131:
132: public void actionPerformed(ActionEvent e) {
133: requestFocus();
134: final SelectionPaneButton button = (SelectionPaneButton) e
135: .getSource();
136:
137: if (button.isSelected()) {
138: return;
139: }
140:
141: SwingUtilities.invokeLater(new Runnable() {
142: public void run() {
143: button.setSelected(true);
144: model.setSelectedIndex(getComponentIndex(button));
145: layoutComponents();
146: }
147: });
148:
149: }
150:
151: public int getComponentIndex(JComponent component) {
152: int index = 0;
153: Vector cache = null;
154:
155: if (component instanceof SelectionPaneButton)
156: cache = componentButtons;
157: else
158: cache = componentPanels;
159:
160: int size = cache.size();
161:
162: for (int i = 0; i < size; i++) {
163:
164: if (cache.elementAt(i) == component) {
165: index = i;
166: break;
167: }
168:
169: }
170:
171: return index;
172:
173: }
174:
175: public void layoutComponents() {
176: removeAll();
177: invalidate();
178:
179: GridBagConstraints gbc = new GridBagConstraints();
180: gbc.gridy = 0;
181: gbc.fill = GridBagConstraints.HORIZONTAL;
182: gbc.anchor = GridBagConstraints.NORTHWEST;
183: gbc.weightx = 1.0;
184:
185: int total = componentPanels.size();
186: int selectedIndex = model.getSelectedIndex();
187:
188: for (int i = 0; i < total; i++) {
189: SelectionPaneButton button = (SelectionPaneButton) componentButtons
190: .elementAt(i);
191: this .add(button, gbc);
192: button.setSelected(false);
193: gbc.gridy++;
194:
195: if (i == selectedIndex) {
196: button.setSelected(true);
197: JComponent selectedPanel = (JComponent) componentPanels
198: .elementAt(i);
199: gbc.weighty = 1.0;
200: gbc.fill = GridBagConstraints.BOTH;
201: this .add(selectedPanel, gbc);
202: gbc.fill = GridBagConstraints.HORIZONTAL;
203: gbc.gridy++;
204: gbc.weighty = 0;
205: }
206:
207: }
208:
209: validate();
210: repaint();
211:
212: }
213:
214: public void setSelectedIndex(int index) {
215: model.setSelectedIndex(index);
216: }
217:
218: public int getSelectedIndex() {
219: return model.getSelectedIndex();
220: }
221:
222: public void addSelectionPanel(String label, JComponent panel) {
223: addSelectionPanel(label, panel, null);
224: }
225:
226: public void addSelectionPanel(String label, JComponent panel,
227: String toolTip) {
228: SelectionPaneButton button = new SelectionPaneButton(label,
229: toolTip);
230: button.addActionListener(this );
231: componentButtons.add(button);
232: componentPanels.add(panel);
233: }
234:
235: class SelectionPaneButton extends JButton implements MouseListener {
236:
237: private boolean selected;
238:
239: public SelectionPaneButton(String label, String toolTip) {
240: super (label);
241: setToolTipText(toolTip);
242: jbInit();
243: }
244:
245: public SelectionPaneButton(String label) {
246: super (label);
247: jbInit();
248: }
249:
250: /** <p>Initialises the state of the button. */
251: private void jbInit() {
252: addMouseListener(this );
253: selected = false;
254: setHorizontalAlignment(SwingConstants.LEFT);
255: }
256:
257: public Icon getIcon() {
258:
259: if (selected)
260: return selectedIcon;
261: else
262: return defaultIcon;
263:
264: }
265:
266: public boolean isSelected() {
267: return selected;
268: }
269:
270: public void setSelected(boolean selected) {
271: this .selected = selected;
272: super .setSelected(selected);
273: }
274:
275: public void paintComponent(Graphics g) {
276:
277: super .paintComponent(g);
278:
279: if (isJavaLookAndFeel) {
280:
281: int height = getHeight();
282: Shape clip = g.getClip();
283:
284: g.setColor(foreground);
285: g.setClip(2, 2, 8, height - 6);
286:
287: for (int x = 3; x <= height; x += 4) {
288:
289: for (int y = 3; y <= height; y += 4) {
290: g.drawLine(x, y, x, y);
291: g.drawLine(x + 2, y + 2, x + 2, y + 2);
292: }
293:
294: }
295:
296: g.setColor(background);
297:
298: for (int x = 3; x <= height; x += 4) {
299:
300: for (int y = 3; y <= height; y += 4) {
301: g.drawLine(x + 1, y + 1, x + 1, y + 1);
302: g.drawLine(x + 3, y + 3, x + 3, y + 3);
303: }
304:
305: }
306:
307: g.setClip(clip);
308:
309: }
310:
311: }
312:
313: /**
314: * Paints the button's borders as the mouse pointer enters.
315: *
316: * @param e the MouseEvent that created this event
317: */
318: public void mouseEntered(MouseEvent e) {
319:
320: if (!selected) {
321: setCursor(Cursor
322: .getPredefinedCursor(Cursor.HAND_CURSOR));
323: setBackground(hoverColour);
324: }
325:
326: }
327:
328: /** Override the <code>isFocusable()</code>
329: * method of <code>Component</code> (JDK1.4) to
330: * return false so the button never maintains
331: * the focus.
332: *
333: * @return false
334: */
335: public boolean isFocusable() {
336: return false;
337: }
338:
339: /**
340: * Sets the button's borders unpainted as the mouse
341: * pointer exits.
342: *
343: * @param e the MouseEvent that created this event
344: */
345: public void mouseExited(MouseEvent e) {
346: setCursor(Cursor.getDefaultCursor());
347: setBackground(defaultColour);
348: }
349:
350: public void mouseClicked(MouseEvent e) {
351: selected = true;
352: }
353:
354: public void mouseReleased(MouseEvent e) {
355: }
356:
357: public void mousePressed(MouseEvent e) {
358: }
359:
360: } // class SelectionPaneButton
361:
362: class ButtonSelectionPaneModel implements SingleSelectionModel {
363:
364: private int selectedIndex;
365:
366: public void clearSelection() {
367: selectedIndex = -1;
368: }
369:
370: public int getSelectedIndex() {
371: return selectedIndex;
372: }
373:
374: public void setSelectedIndex(int index) {
375: selectedIndex = index;
376: }
377:
378: public boolean isSelected() {
379: return selectedIndex != -1;
380: }
381:
382: public void removeChangeListener(ChangeListener listener) {
383: }
384:
385: public void addChangeListener(ChangeListener listener) {
386: }
387:
388: } // class ButtonSelectionPaneModel
389:
390: }
|