KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > form > BindingBorder


1 /*
2  * $Id: BindingBorder.java,v 1.4 2005/02/03 13:41:33 kleopatra Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8 package org.jdesktop.swing.form;
9
10 import org.jdesktop.swing.data.MetaData;
11 import org.jdesktop.swing.data.NumberMetaData;
12 import org.jdesktop.swing.data.StringMetaData;
13
14 import org.jdesktop.swing.JXGlassBox;
15
16 import org.jdesktop.swing.binding.Binding;
17
18 import java.awt.AlphaComposite JavaDoc;
19 import java.awt.Color JavaDoc;
20 import java.awt.Component JavaDoc;
21 import java.awt.Composite JavaDoc;
22 import java.awt.Container JavaDoc;
23 import java.awt.Font JavaDoc;
24 import java.awt.Graphics JavaDoc;
25 import java.awt.Graphics2D JavaDoc;
26 import java.awt.GridBagConstraints JavaDoc;
27 import java.awt.GridBagLayout JavaDoc;
28 import java.awt.Insets JavaDoc;
29 import java.awt.Point JavaDoc;
30 import java.awt.Rectangle JavaDoc;
31 import java.awt.event.ActionEvent JavaDoc;
32 import java.awt.event.ActionListener JavaDoc;
33 import java.awt.event.FocusEvent JavaDoc;
34 import java.awt.event.FocusListener JavaDoc;
35 import java.awt.event.MouseEvent JavaDoc;
36
37 import java.beans.PropertyChangeEvent JavaDoc;
38 import java.beans.PropertyChangeListener JavaDoc;
39
40 import java.net.URL JavaDoc;
41
42 import javax.swing.Box JavaDoc;
43 import javax.swing.BoxLayout JavaDoc;
44 import javax.swing.Icon JavaDoc;
45 import javax.swing.ImageIcon JavaDoc;
46 import javax.swing.JComponent JavaDoc;
47 import javax.swing.JLabel JavaDoc;
48 import javax.swing.JRootPane JavaDoc;
49 import javax.swing.SwingConstants JavaDoc;
50 import javax.swing.SwingUtilities JavaDoc;
51 import javax.swing.Timer JavaDoc;
52 import javax.swing.border.Border JavaDoc;
53 import javax.swing.border.CompoundBorder JavaDoc;
54 import javax.swing.border.EmptyBorder JavaDoc;
55 import javax.swing.border.LineBorder JavaDoc;
56 import javax.swing.event.MouseInputAdapter JavaDoc;
57
58 /**
59  * @author Amy Fowler
60  * @version 1.0
61  */

62
63 public class BindingBorder
64     implements Border JavaDoc {
65     private static final int PAD = 0;
66     private static Icon JavaDoc defaultValidIcon;
67     private static Icon JavaDoc defaultInvalidIcon;
68     private static Icon JavaDoc defaultRequiredIcon;
69
70     private Binding binding;
71     private Icon JavaDoc validIcon;
72     private Icon JavaDoc invalidIcon;
73     private Icon JavaDoc requiredIcon;
74     private int iconPosition;
75
76     private FocusListener JavaDoc focusListener;
77
78     private Rectangle JavaDoc validIconBounds = new Rectangle JavaDoc();
79     private Timer JavaDoc messageTriggerTimer;
80     private int messageTriggerX;
81     private int messageTriggerY;
82     private JXGlassBox messageBox;
83
84     static {
85         URL JavaDoc url = BindingBorder.class.getResource("resources/blue-tipicon.png");
86         defaultValidIcon = new ImageIcon JavaDoc(url);
87
88         url = BindingBorder.class.getResource("resources/red-tipicon.png");
89         defaultInvalidIcon = new ImageIcon JavaDoc(url);
90
91         url = BindingBorder.class.getResource("resources/asterisk.8x8.png");
92         defaultRequiredIcon = new ImageIcon JavaDoc(url);
93     }
94
95     public BindingBorder(Binding binding) {
96         this(binding, SwingConstants.EAST);
97     }
98
99     public BindingBorder(Binding binding, int iconPosition) {
100         this(binding, defaultValidIcon, defaultInvalidIcon, iconPosition);
101     }
102
103     public BindingBorder(Binding binding,
104                          Icon JavaDoc validIcon, Icon JavaDoc invalidIcon, int iconPosition) {
105         this(binding, validIcon, invalidIcon, null, iconPosition);
106     }
107
108     public BindingBorder(Binding binding,
109                          Icon JavaDoc validIcon, Icon JavaDoc invalidIcon,
110                          Icon JavaDoc requiredIcon,
111                          int iconPosition) {
112         this.binding = binding;
113         this.validIcon = validIcon;
114         this.invalidIcon = invalidIcon;
115         this.iconPosition = iconPosition;
116         Component JavaDoc component = binding.getComponent();
117         MetaData metaData = binding.getDataModel().getMetaData(binding.getFieldName());
118         if (metaData.isRequired()) {
119             this.requiredIcon = requiredIcon;
120         }
121         binding.addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
122             public void propertyChange(PropertyChangeEvent JavaDoc e) {
123                 Binding binding = (Binding) e.getSource();
124                 if (e.getPropertyName().equals("validState")) {
125                     binding.getComponent().repaint();
126                 }
127             }
128         });
129
130         addFocusListener(component);
131
132         messageTriggerTimer = new Timer JavaDoc(1000, new MessageTrigger());
133         MouseInputAdapter JavaDoc mouseAdapter = new MouseInputAdapter JavaDoc() {
134             public void mousePressed(MouseEvent JavaDoc e) {
135                 int x = e.getX();
136                 int y = e.getY();
137                 if (!isMessageBoxShowing() && validIconBounds.contains(x, y)) {
138                     if (messageTriggerTimer.isRunning()) {
139                         messageTriggerTimer.stop();
140                     }
141                     showMessageBox(x, y);
142                 }
143             }
144             public void mouseMoved(MouseEvent JavaDoc e) {
145                 if (!isMessageBoxShowing()) {
146                     int x = e.getX();
147                     int y = e.getY();
148                     if (!messageTriggerTimer.isRunning()) {
149                         if (validIconBounds.contains(x, y)) {
150                             messageTriggerX = x;
151                             messageTriggerY = y;
152                             messageTriggerTimer.start();
153                         }
154                     }
155                     else {
156                         if (!validIconBounds.contains(x, y)) {
157                             messageTriggerTimer.stop();
158                         }
159                     }
160                 }
161             }
162             public void mouseExited(MouseEvent JavaDoc e) {
163                 if (messageTriggerTimer.isRunning()) {
164                     messageTriggerTimer.stop();
165                 }
166             }
167         };
168         component.addMouseMotionListener(mouseAdapter);
169         component.addMouseListener(mouseAdapter);
170     }
171
172     public Insets JavaDoc getBorderInsets(Component JavaDoc c) {
173         if (requiredIcon != null) {
174             return new Insets JavaDoc(0, 0, 0,
175                               validIcon.getIconWidth() +
176                               requiredIcon.getIconWidth() +
177                               (3 * PAD));
178         }
179         return new Insets JavaDoc(0, 0, 0, validIcon.getIconWidth() + (2 * PAD));
180
181     }
182
183     public boolean isBorderOpaque() {
184         return false;
185     }
186
187     public void paintBorder(Component JavaDoc c, Graphics JavaDoc g, int x, int y,
188                             int width, int height) {
189         Graphics2D JavaDoc g2d = (Graphics2D JavaDoc) g;
190         Composite JavaDoc oldComp = null;
191         boolean paintValid = binding.getValidState() != Binding.INVALID;
192
193         if (!hasFocus(c)) {
194             // fade back icons if component or descendent does not have focus
195
oldComp = g2d.getComposite();
196             Composite JavaDoc alphaComp = AlphaComposite.getInstance(AlphaComposite.
197                 SRC_OVER, 0.35f);
198             g2d.setComposite(alphaComp);
199         }
200         Icon JavaDoc validIcon = (paintValid ? this.validIcon :
201                           this.invalidIcon);
202
203         int requiredIconSpace = (requiredIcon != null ?
204                                  requiredIcon.getIconWidth() + PAD : 0);
205
206         if (!isMessageBoxShowing()) {
207             validIconBounds.x = x + width - PAD - requiredIconSpace -
208                 validIcon.getIconWidth();
209             if (iconPosition == SwingConstants.NORTH_EAST) {
210                 validIconBounds.y = y + PAD;
211
212             } else if (iconPosition == SwingUtilities.EAST){ // EAST
213
validIconBounds.y = y +
214                      ((height - validIcon.getIconHeight())/2);
215             } else if (iconPosition == SwingUtilities.WEST) {
216               validIconBounds.y = y +
217               ((height - validIcon.getIconHeight())/2);
218               validIconBounds.x = x + width - PAD - requiredIconSpace -
219               validIcon.getIconWidth();
220               
221             }
222             validIconBounds.width = validIcon.getIconWidth();
223             validIconBounds.height = validIcon.getIconHeight();
224             validIcon.paintIcon(c, g, validIconBounds.x, validIconBounds.y);
225         }
226
227         if (requiredIcon != null) {
228             int requiredX = x + width - PAD - requiredIcon.getIconWidth();
229             int requiredY = y + (height - requiredIcon.getIconHeight()) / 2;
230             requiredIcon.paintIcon(c, g, requiredX, requiredY);
231         }
232
233         if (!paintValid) {
234             Color JavaDoc save = g.getColor();
235             Color JavaDoc invalidColor = new Color JavaDoc(255, 0, 0, 225);
236             g.setColor(invalidColor);
237             g.drawRect(0, 0, c.getWidth(), c.getHeight());
238             g.drawRect(1, 1, c.getWidth() - 2, c.getHeight() - 2);
239             g.setColor(save);
240         }
241
242         if (oldComp != null) {
243             g2d.setComposite(oldComp);
244         }
245     }
246
247     private void addFocusListener(Component JavaDoc component) {
248         if (focusListener == null) {
249             focusListener = new FocusListener JavaDoc() {
250                 public void focusGained(FocusEvent JavaDoc e) {
251                     binding.getComponent().repaint();
252                 }
253                 public void focusLost(FocusEvent JavaDoc e) {
254                     binding.getComponent().repaint();
255                 }
256             };
257         }
258         component.addFocusListener(focusListener);
259         // Some components may be compound components where the focus
260
// is taken on internal components
261
if (component instanceof Container JavaDoc) {
262             Component JavaDoc children[] = ((Container JavaDoc)component).getComponents();
263             for(int i = 0; i < children.length; i++) {
264                 addFocusListener(children[i]);
265             }
266         }
267     }
268
269     private boolean hasFocus(Component JavaDoc component) {
270         if (component.isFocusOwner()) {
271             return true;
272         }
273         if (component instanceof Container JavaDoc) {
274             Component JavaDoc children[] = ( (Container JavaDoc) component).getComponents();
275             for (int i = 0; i < children.length; i++) {
276                 if (hasFocus(children[i])) {
277                     return true;
278                 }
279             }
280         }
281         return false;
282     }
283
284     private boolean isMessageBoxShowing() {
285         return (messageBox != null && messageBox.getParent() != null);
286     }
287
288     /** @todo: aim this will have localization problems - need to figure that out */
289     private void showMessageBox(int x, int y) {
290         JComponent JavaDoc component = binding.getComponent();
291         boolean valid = binding.getValidState() != Binding.INVALID;
292         Color JavaDoc borderColor = valid ? Color.blue : Color.red;
293         Icon JavaDoc messageIcon = (valid ? validIcon : invalidIcon);
294         MetaData metaData = binding.getDataModel().getMetaData(binding.
295             getFieldName());
296
297         messageBox = new JXGlassBox();
298         messageBox.setAlpha(0.95f);
299         messageBox.setBorder(new LineBorder JavaDoc(borderColor, 1));
300         GridBagLayout JavaDoc gridBag = new GridBagLayout JavaDoc();
301         GridBagConstraints JavaDoc c = new GridBagConstraints JavaDoc();
302         messageBox.setLayout(gridBag);
303
304         JLabel JavaDoc label = new JLabel JavaDoc(metaData.getLabel() + ":");
305         Font JavaDoc boldFont = label.getFont().deriveFont(Font.BOLD);
306         label.setFont(boldFont);
307         c.anchor = GridBagConstraints.NORTHWEST;
308         c.insets = new Insets JavaDoc(2,4,0,2);
309         gridBag.setConstraints(label, c);
310         messageBox.add(label);
311
312         Box textContent = new Box(BoxLayout.X_AXIS);
313         c.gridx = 1;
314         c.anchor = GridBagConstraints.NORTH;
315         c.insets = new Insets JavaDoc(2, 2, 2, 2);
316         gridBag.setConstraints(textContent, c);
317         messageBox.add(textContent);
318
319         JLabel JavaDoc iconLabel = new JLabel JavaDoc(messageIcon);
320         c.gridx = 2;
321         c.anchor = GridBagConstraints.NORTHEAST;
322         c.insets = new Insets JavaDoc(1,0,0,1);
323         gridBag.setConstraints(iconLabel, c);
324         messageBox.add(iconLabel);
325
326
327         textContent.add(Box.createHorizontalStrut(4));
328         Box content = new Box(BoxLayout.Y_AXIS);
329         textContent.add(content);
330
331         if (!valid) {
332             String JavaDoc errors[] = binding.getValidationErrors();
333             if (errors.length > 0) {
334                 for (int i = 0; i < errors.length; i++) {
335                     content.add(new JLabel JavaDoc(errors[i]));
336                 }
337             }
338             else {
339                 content.add(new JLabel JavaDoc("contains invalid value"));
340             }
341         }
342         else {
343             content.add(new JLabel JavaDoc("value must be of type " +
344                                    metaData.getElementClass().getName()));
345             content.add(new JLabel JavaDoc("value is " +
346                                    (metaData.isRequired() ? "required" :
347                                     "optional")));
348             if (metaData instanceof NumberMetaData) {
349                 NumberMetaData numberMetaData = (NumberMetaData) metaData;
350                 Number JavaDoc minimum = numberMetaData.getMinimum();
351                 if (minimum != null) {
352                     content.add(new JLabel JavaDoc("minimum value is " +
353                                            minimum.toString()));
354                 }
355                 Number JavaDoc maximum = numberMetaData.getMaximum();
356                 if (maximum != null) {
357                     content.add(new JLabel JavaDoc("maximum value is " +
358                                            maximum.toString()));
359                 }
360             }
361
362         }
363         /*
364              Container glasspane = (Container)component.getRootPane().getGlassPane();
365              Point p = SwingUtilities.convertPoint(component, x, y, glasspane);
366                  messageBox.showOnGlassPane(glasspane, p.x, p.y);
367          */

368         Container JavaDoc glassPane = (Container JavaDoc) component.getRootPane().
369             getGlassPane();
370         // Only allow one message box to be visible at a time so
371
// pop down any visible message boxes
372
Component JavaDoc glassPaneChildren[] = glassPane.getComponents();
373         for(int i = 0; i < glassPaneChildren.length; i++) {
374             glassPaneChildren[i].setVisible(false);
375             glassPane.remove(glassPaneChildren[i]);
376         }
377         messageBox.showOnGlassPane(glassPane, component, x, y,
378                                    SwingConstants.TOP);
379
380     }
381
382     private class MessageTrigger implements ActionListener JavaDoc {
383         public void actionPerformed(ActionEvent JavaDoc e) {
384             messageTriggerTimer.stop();
385             showMessageBox(messageTriggerX, messageTriggerY);
386         }
387     }
388 }
389
Popular Tags