001 /*
002 * Created on Sep 16, 2007
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 *
014 * Copyright @2007-2010 the original author or authors.
015 */
016 package org.fest.swing.format;
017
018 import static org.fest.swing.edt.GuiActionRunner.execute;
019 import static org.fest.util.Strings.*;
020
021 import java.awt.*;
022 import java.util.concurrent.ConcurrentHashMap;
023 import java.util.concurrent.ConcurrentMap;
024 import java.util.logging.Logger;
025
026 import javax.swing.*;
027 import javax.swing.text.JTextComponent;
028
029 import org.fest.swing.annotation.RunsInCurrentThread;
030 import org.fest.swing.annotation.RunsInEDT;
031 import org.fest.swing.edt.GuiQuery;
032 import org.fest.util.VisibleForTesting;
033
034 /**
035 * Understands utility methods related to formatting.
036 *
037 * @author Alex Ruiz
038 * @author Yvonne Wang
039 */
040 public class Formatting {
041
042
043 private static final String MAXIMUM = "maximum";
044
045 private static final String MINIMUM = "minimum";
046
047 private static final String NULL_COMPONENT_MESSAGE = "Null Component";
048
049 private static final String ENABLED = "enabled";
050 private static final String NAME = "name";
051 private static final String SHOWING = "showing";
052 private static final String TEXT = "text";
053 private static final String TITLE = "title";
054 private static final String VALUE = "value";
055 private static final String VISIBLE = "visible";
056
057 private static final ConcurrentMap<Class<?>, ComponentFormatter> FORMATTERS = new ConcurrentHashMap<Class<?>, ComponentFormatter>();
058
059 private static Logger logger = Logger.getLogger(Formatting.class.getName());
060
061 static {
062 register(instrospect(AbstractButton.class, NAME, TEXT, "selected", ENABLED, VISIBLE, SHOWING));
063 register(instrospect(Dialog.class, NAME, TITLE, ENABLED, "modal", VISIBLE, SHOWING));
064 register(instrospect(Frame.class, NAME, TITLE, ENABLED, VISIBLE, SHOWING));
065 register(new JComboBoxFormatter());
066 register(instrospect(JButton.class, NAME, TEXT, ENABLED, VISIBLE, SHOWING));
067 register(new JFileChooserFormatter());
068 register(instrospect(JLabel.class, NAME, TEXT, ENABLED, VISIBLE, SHOWING));
069 register(empty(JLayeredPane.class));
070 register(new JListFormatter());
071 register(empty(JMenuBar.class));
072 register(new JOptionPaneFormatter());
073 register(nameOnly(JPanel.class));
074 register(instrospect(JPopupMenu.class, NAME, "label", ENABLED, VISIBLE, SHOWING));
075 register(instrospect(JProgressBar.class, NAME, VALUE, MINIMUM, MAXIMUM, "string", "stringPainted", ENABLED, VISIBLE, SHOWING));
076 register(empty(JRootPane.class));
077 register(instrospect(JScrollBar.class, NAME, VALUE, "blockIncrement", MINIMUM, MAXIMUM, ENABLED, VISIBLE, SHOWING));
078 register(instrospect(JScrollPane.class, NAME, ENABLED, VISIBLE, SHOWING));
079 register(instrospect(JSlider.class, NAME, VALUE, MINIMUM, MAXIMUM, ENABLED, VISIBLE, SHOWING));
080 register(instrospect(JSpinner.class, NAME, VALUE, ENABLED, VISIBLE, SHOWING));
081 register(new JTabbedPaneFormatter());
082 register(new JTableFormatter());
083 register(nameOnly(JToolBar.class));
084 register(instrospect(JPasswordField.class, NAME, ENABLED, VISIBLE, SHOWING));
085 register(instrospect(JTextComponent.class, NAME, TEXT, ENABLED, VISIBLE, SHOWING));
086 register(new JTreeFormatter());
087 }
088
089 private static ComponentFormatter instrospect(Class<? extends Component> targetType, String...propertyNames) {
090 return new IntrospectionComponentFormatter(targetType, propertyNames);
091 }
092
093 private static ComponentFormatter empty(Class<? extends Component> targetType) {
094 return new IntrospectionComponentFormatter(targetType);
095 }
096
097 private static ComponentFormatter nameOnly(Class<? extends Component> targetType) {
098 return new IntrospectionComponentFormatter(targetType, NAME);
099 }
100
101 /**
102 * Registers the given formatter, replacing any other one previously registered for the same supported component type.
103 * @param formatter the formatter to register.
104 */
105 public static void register(ComponentFormatter formatter) {
106 Class<?> key = formatter.targetType();
107 ComponentFormatter previous = FORMATTERS.put(key, formatter);
108 if (previous != null)
109 logger.info(
110 concat("Replaced formatter ", previous, " with ", formatter, " for the type ", key.getName()));
111 }
112
113 @VisibleForTesting
114 static ComponentFormatter formatter(Class<?> type) {
115 return FORMATTERS.get(type);
116 }
117
118 /**
119 * Returns a <code>String</code> representation of the given <code>{@link Component}</code>. This method is invoked in
120 * the event dispatch thread.
121 * @param c the given <code>Component</code>.
122 * @return a <code>String</code> representation of the given <code>Component</code>.
123 */
124 @RunsInEDT
125 public static String inEdtFormat(final Component c) {
126 return execute(new GuiQuery<String>() {
127 protected String executeInEDT() {
128 return format(c);
129 }
130 });
131 }
132
133 /**
134 * Returns a <code>String</code> representation of the given <code>{@link Component}</code>.
135 * <p>
136 * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
137 * responsible for calling this method from the EDT.
138 * </p>
139 * @param c the given <code>Component</code>.
140 * @return a <code>String</code> representation of the given <code>Component</code>.
141 */
142 @RunsInCurrentThread
143 public static String format(Component c) {
144 if (c == null) return NULL_COMPONENT_MESSAGE;
145 ComponentFormatter formatter = formatterFor(c.getClass());
146 if (formatter != null) return formatter.format(c);
147 String name = c.getName();
148 if (isEmpty(name)) return c.toString();
149 return concat(c.getClass().getName(), "[name=", quote(name), "]");
150 }
151
152 private static ComponentFormatter formatterFor(Class<?> type) {
153 ComponentFormatter formatter = FORMATTERS.get(type);
154 if (formatter != null) return formatter;
155 Class<?> superType = type.getSuperclass();
156 if (superType != null) return formatterFor(superType);
157 return null;
158 }
159
160 private Formatting() {}
161 }