KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jgoodies > looks > common > ExtBasicArrowButtonHandler


1 /*
2  * Copyright (c) 2001-2005 JGoodies Karsten Lentzsch. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * o Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * o Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * o Neither the name of JGoodies Karsten Lentzsch nor the names of
15  * its contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package com.jgoodies.looks.common;
32
33 import java.awt.AWTEvent JavaDoc;
34 import java.awt.Component JavaDoc;
35 import java.awt.Container JavaDoc;
36 import java.awt.FocusTraversalPolicy JavaDoc;
37 import java.awt.KeyboardFocusManager JavaDoc;
38 import java.awt.event.ActionEvent JavaDoc;
39 import java.awt.event.MouseEvent JavaDoc;
40 import java.awt.event.MouseListener JavaDoc;
41 import java.text.AttributedCharacterIterator JavaDoc;
42 import java.text.CharacterIterator JavaDoc;
43 import java.text.DateFormat JavaDoc;
44 import java.text.Format JavaDoc;
45 import java.text.ParseException JavaDoc;
46 import java.util.Calendar JavaDoc;
47 import java.util.Map JavaDoc;
48
49 import javax.swing.*;
50 import javax.swing.text.InternationalFormatter JavaDoc;
51
52 /**
53  * A handler for spinner arrow button mouse and action events. When
54  * a left mouse pressed event occurs we look up the (enabled) spinner
55  * that's the source of the event and start the autorepeat timer. The
56  * timer fires action events until any button is released at which
57  * point the timer is stopped and the reference to the spinner cleared.
58  * The timer doesn't start until after a 300ms delay, so often the
59  * source of the initial (and final) action event is just the button
60  * logic for mouse released - which means that we're relying on the fact
61  * that our mouse listener runs after the buttons mouse listener.<p>
62  *
63  * Note that one instance of this handler is shared by all slider previous
64  * arrow buttons and likewise for all of the next buttons,
65  * so it doesn't have any state that persists beyond the limits
66  * of a single button pressed/released gesture.<p>
67  *
68  * Copied from javax.swing.BasicSpinnerUI
69  *
70  * @version $Revision: 1.2 $
71  *
72  * @see javax.swing.plaf.basic.BasicSpinnerUI
73  */

74 public final class ExtBasicArrowButtonHandler extends AbstractAction implements MouseListener JavaDoc {
75
76     private final javax.swing.Timer JavaDoc autoRepeatTimer;
77     private final boolean isNext;
78     
79     private JSpinner spinner = null;
80
81
82     public ExtBasicArrowButtonHandler(String JavaDoc name, boolean isNext) {
83         super(name);
84         this.isNext = isNext;
85         autoRepeatTimer = new javax.swing.Timer JavaDoc(60, this);
86         autoRepeatTimer.setInitialDelay(300);
87     }
88
89
90     private JSpinner eventToSpinner(AWTEvent JavaDoc e) {
91         Object JavaDoc src = e.getSource();
92         while ((src instanceof Component JavaDoc) && !(src instanceof JSpinner)) {
93             src = ((Component JavaDoc) src).getParent();
94         }
95         return (src instanceof JSpinner) ? (JSpinner) src : null;
96     }
97
98
99     public void actionPerformed(ActionEvent JavaDoc e) {
100         JSpinner aSpinner = this.spinner;
101
102         if (!(e.getSource() instanceof javax.swing.Timer JavaDoc)) {
103             // Most likely resulting from being in ActionMap.
104
aSpinner = eventToSpinner(e);
105         }
106         if (aSpinner != null) {
107             try {
108                 int calendarField = getCalendarField(aSpinner);
109                 aSpinner.commitEdit();
110                 if (calendarField != -1) {
111                     ((SpinnerDateModel) aSpinner.getModel()).setCalendarField(calendarField);
112                 }
113                 Object JavaDoc value = (isNext) ? aSpinner.getNextValue() : aSpinner.getPreviousValue();
114                 if (value != null) {
115                     aSpinner.setValue(value);
116                     select(aSpinner);
117                 }
118             } catch (IllegalArgumentException JavaDoc iae) {
119                 UIManager.getLookAndFeel().provideErrorFeedback(aSpinner);
120             } catch (ParseException JavaDoc pe) {
121                 UIManager.getLookAndFeel().provideErrorFeedback(aSpinner);
122             }
123         }
124     }
125
126
127     /**
128      * If the spinner's editor is a DateEditor, this selects the field
129      * associated with the value that is being incremented.
130      */

131     private void select(JSpinner aSpinner) {
132         JComponent editor = aSpinner.getEditor();
133
134         if (editor instanceof JSpinner.DateEditor) {
135             JSpinner.DateEditor dateEditor = (JSpinner.DateEditor) editor;
136             JFormattedTextField ftf = dateEditor.getTextField();
137             Format JavaDoc format = dateEditor.getFormat();
138             Object JavaDoc value;
139
140             if (format != null && (value = aSpinner.getValue()) != null) {
141                 SpinnerDateModel model = dateEditor.getModel();
142                 DateFormat.Field JavaDoc field = DateFormat.Field.ofCalendarField(model.getCalendarField());
143
144                 if (field != null) {
145                     try {
146                         AttributedCharacterIterator JavaDoc iterator =
147                             format.formatToCharacterIterator(value);
148                         if (!select(ftf, iterator, field) && field == DateFormat.Field.HOUR0) {
149                             select(ftf, iterator, DateFormat.Field.HOUR1);
150                         }
151                     } catch (IllegalArgumentException JavaDoc iae) {
152                         // Should not happen
153
}
154                 }
155             }
156         }
157     }
158
159
160     /**
161      * Selects the passed in field, returning true if it is found, false otherwise.
162      */

163     private boolean select(
164         JFormattedTextField ftf,
165         AttributedCharacterIterator JavaDoc iterator,
166         DateFormat.Field JavaDoc field) {
167         int max = ftf.getDocument().getLength();
168
169         iterator.first();
170         do {
171             Map JavaDoc attrs = iterator.getAttributes();
172
173             if (attrs != null && attrs.containsKey(field)) {
174                 int start = iterator.getRunStart(field);
175                 int end = iterator.getRunLimit(field);
176
177                 if (start != -1 && end != -1 && start <= max && end <= max) {
178                     ftf.select(start, end);
179                 }
180                 return true;
181             }
182         } while (iterator.next() != CharacterIterator.DONE);
183         return false;
184     }
185
186
187     /**
188      * Returns the calendarField under the start of the selection, or
189      * -1 if there is no valid calendar field under the selection (or
190      * the spinner isn't editing dates.
191      */

192     private int getCalendarField(JSpinner aSpinner) {
193         JComponent editor = aSpinner.getEditor();
194
195         if (editor instanceof JSpinner.DateEditor) {
196             JSpinner.DateEditor dateEditor = (JSpinner.DateEditor) editor;
197             JFormattedTextField ftf = dateEditor.getTextField();
198             int start = ftf.getSelectionStart();
199             JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter();
200
201             if (formatter instanceof InternationalFormatter JavaDoc) {
202                 Format.Field JavaDoc[] fields = ((InternationalFormatter JavaDoc) formatter).getFields(start);
203
204                 for (int counter = 0; counter < fields.length; counter++) {
205                     if (fields[counter] instanceof DateFormat.Field JavaDoc) {
206                         int calendarField;
207
208                         if (fields[counter] == DateFormat.Field.HOUR1) {
209                             calendarField = Calendar.HOUR;
210                         } else {
211                             calendarField = ((DateFormat.Field JavaDoc) fields[counter]).getCalendarField();
212                         }
213                         if (calendarField != -1) {
214                             return calendarField;
215                         }
216                     }
217                 }
218             }
219         }
220         return -1;
221     }
222
223     public void mousePressed(MouseEvent JavaDoc e) {
224         if (SwingUtilities.isLeftMouseButton(e) && e.getComponent().isEnabled()) {
225             spinner = eventToSpinner(e);
226             autoRepeatTimer.start();
227             focusSpinnerIfNecessary();
228         }
229     }
230
231     public void mouseReleased(MouseEvent JavaDoc e) {
232         autoRepeatTimer.stop();
233         spinner = null;
234     }
235
236     public void mouseClicked(MouseEvent JavaDoc e) {
237         // Do nothing
238
}
239     
240     public void mouseEntered(MouseEvent JavaDoc e) {
241         // Do nothing
242
}
243     
244     public void mouseExited (MouseEvent JavaDoc e) {
245         // Do nothing
246
}
247
248
249     /**
250      * Requests focus on a child of the spinner if the spinner doesn't
251      * have focus.
252      */

253     private void focusSpinnerIfNecessary() {
254         Component JavaDoc fo = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
255         if (spinner.isRequestFocusEnabled()
256             && (fo == null || !SwingUtilities.isDescendingFrom(fo, spinner))) {
257             Container JavaDoc root = spinner;
258
259             if (!root.isFocusCycleRoot()) {
260                 root = root.getFocusCycleRootAncestor();
261             }
262             if (root != null) {
263                 FocusTraversalPolicy JavaDoc ftp = root.getFocusTraversalPolicy();
264                 Component JavaDoc child = ftp.getComponentAfter(root, spinner);
265
266                 if (child != null && SwingUtilities.isDescendingFrom(child, spinner)) {
267                     child.requestFocus();
268                 }
269             }
270         }
271     }
272
273 }
Popular Tags