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 }