001package org.jdesktop.swingx.prompt;
002
003import java.awt.Component;
004import java.awt.Insets;
005import java.util.ArrayList;
006import java.util.Collections;
007import java.util.List;
008
009import javax.swing.Box;
010import javax.swing.JComponent;
011import javax.swing.JTextField;
012import javax.swing.plaf.basic.BasicTextUI;
013
014import org.jdesktop.swingx.plaf.TextUIWrapper;
015
016public class BuddySupport {
017        public enum Position {
018                LEFT, RIGHT
019        };
020
021        public static final String OUTER_MARGIN = "outerMargin";
022
023        public static void addLeft(Component c, JTextField textField) {
024                add(c, Position.LEFT, textField);
025        }
026
027        public static void addRight(Component c, JTextField textField) {
028                add(c, Position.RIGHT, textField);
029        }
030
031        public static void add(Component c, Position pos, JTextField textField) {
032                TextUIWrapper.getDefaultWrapper().install(textField, true);
033
034                List<Component> leftBuddies = buddies(Position.LEFT, textField);
035                List<Component> rightBuddies = buddies(Position.RIGHT, textField);
036
037                // ensure buddies are added
038                setLeft(textField, leftBuddies);
039                setRight(textField, rightBuddies);
040
041                // check if component is already here
042                if (isBuddy(c, textField)) {
043                        throw new IllegalStateException("Component already added.");
044                }
045
046                if (Position.LEFT == pos) {
047                        leftBuddies.add(c);
048                } else {
049                        rightBuddies.add(0, c);
050                }
051
052                addToComponentHierarchy(c, pos, textField);
053        }
054        
055        public static void addGap(int width, Position pos, JTextField textField) {
056                add(createGap(width), pos, textField);
057        }
058
059        public static void setRight(JTextField textField, List<Component> rightBuddies) {
060                set(rightBuddies, Position.RIGHT, textField);
061        }
062
063        public static void setLeft(JTextField textField, List<Component> leftBuddies) {
064                set(leftBuddies, Position.LEFT, textField);
065        }
066
067        public static void set(List<Component> buddies, Position pos, JTextField textField) {
068                textField.putClientProperty(pos, buddies);
069        }
070
071        private static void addToComponentHierarchy(Component c, Position pos, JTextField textField) {
072                textField.add(c, pos.toString());
073        }
074
075        public static List<Component> getLeft(JTextField textField) {
076                return getBuddies(Position.LEFT, textField);
077        }
078
079        public static List<Component> getRight(JTextField textField) {
080                return getBuddies(Position.RIGHT, textField);
081        }
082
083        public static List<Component> getBuddies(Position pos, JTextField textField) {
084                return Collections.unmodifiableList(buddies(pos, textField));
085        }
086
087        @SuppressWarnings("unchecked")
088        private static List<Component> buddies(Position pos, JTextField textField) {
089                List<Component> buddies = (List<Component>) textField.getClientProperty(pos);
090
091                if (buddies != null) {
092                        return buddies;
093                }
094                return new ArrayList<Component>();
095        }
096
097        public static boolean isBuddy(Component c, JTextField textField) {
098                return buddies(Position.LEFT, textField).contains(c) || buddies(Position.RIGHT, textField).contains(c);
099        }
100
101        /**
102         * Because {@link BasicTextUI} removes all components when uninstalled and
103         * therefore all buddies are removed when the LnF changes.
104         * 
105         * @param c
106         * @param textField
107         */
108        public static void remove(JComponent c, JTextField textField) {
109                buddies(Position.LEFT, textField).remove(c);
110                buddies(Position.RIGHT, textField).remove(c);
111
112                textField.remove(c);
113        }
114
115        public static void removeAll(JTextField textField) {
116                List<Component> left = buddies(Position.LEFT, textField);
117                for (Component c : left) {
118                        textField.remove(c);
119                }
120                left.clear();
121                List<Component> right = buddies(Position.RIGHT, textField);
122                for (Component c : right) {
123                        textField.remove(c);
124                }
125                right.clear();
126                
127        }
128
129        public static void setOuterMargin(JTextField buddyField, Insets margin) {
130                buddyField.putClientProperty(OUTER_MARGIN, margin);
131        }
132
133        public static Insets getOuterMargin(JTextField buddyField) {
134                return (Insets) buddyField.getClientProperty(OUTER_MARGIN);
135        }
136
137        public static void ensureBuddiesAreInComponentHierarchy(JTextField textField) {
138                for (Component c : BuddySupport.getLeft(textField)) {
139                        addToComponentHierarchy(c, Position.LEFT, textField);
140                }
141                for (Component c : BuddySupport.getRight(textField)) {
142                        addToComponentHierarchy(c, Position.RIGHT, textField);
143                }
144        }
145
146        /**
147         * Create a gap to insert between to buddies.
148         * 
149         * @param width
150         * @return
151         */
152        public static Component createGap(int width) {
153                return Box.createHorizontalStrut(width);
154        }
155}